Compare commits
410 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b8494eb83a | |||
| cb549dfe25 | |||
| 17507bc8c5 | |||
| 12f8e453ea | |||
| 97ef024b8a | |||
| 3dc94223ae | |||
| 50cd18a926 | |||
| 897d51cba0 | |||
| 1f1d91bd1e | |||
| 9d63a30b07 | |||
| 5b22b1c298 | |||
| 0302d9ae5d | |||
| eb6949528a | |||
| 41b77c3ad5 | |||
| 2f78f5eb26 | |||
| cdbd731f10 | |||
| 5cb4949d46 | |||
| 9ec0b30812 | |||
| 7e1cf2f105 | |||
| 04636a569a | |||
| 52f5b980a4 | |||
| 0e4f833715 | |||
| d22914c4dc | |||
| 7d506e6e2a | |||
| c7007de1ea | |||
| 10bf70b22b | |||
| d952f3233a | |||
| af4ac1b7c9 | |||
| eae4276381 | |||
| d8fab74df6 | |||
| b8c184cc60 | |||
| 8bcc931d9b | |||
| 955ef7b871 | |||
| 9ee7ad4fa8 | |||
| 79aa1febbe | |||
| 4ed9d3a297 | |||
| 97dee2e1a0 | |||
| 32c4974c44 | |||
| 5dadd73dfd | |||
| 6ad5badef4 | |||
| 480ad18b2e | |||
| cdb21f418b | |||
| bd4c18c723 | |||
| e7716ae852 | |||
| b19528d47e | |||
| ef88ce9252 | |||
| 488f1c7742 | |||
| 63c698d903 | |||
| 7e1c3b4501 | |||
| e1d7772a78 | |||
| 9db589e0b3 | |||
| 57c8d69785 | |||
| 4a9cc5b757 | |||
| 06aac9393b | |||
| f4c5b1d67f | |||
| 2e0aba6100 | |||
| 8c6549c5dd | |||
| 7b431ebfa8 | |||
| 3152fd6887 | |||
| e03e7f186a | |||
| ec056a548f | |||
| 24aa075a07 | |||
| 8488c4cb0f | |||
| 20c96b940f | |||
| cfb43699d6 | |||
| 79e7b5b938 | |||
| 47156e693c | |||
| b61f6c8833 | |||
| cc3b710af9 | |||
| 4de3f16bb3 | |||
| 7aad7daa5e | |||
| 4107d670cf | |||
| 284e797fb3 | |||
| 8a63df3e82 | |||
| 7b8731ddcc | |||
| 1017c9c642 | |||
| 4e0c59a8f1 | |||
| f6d85a0784 | |||
| 6516811276 | |||
| ca0ed3594f | |||
| a28ad4f81a | |||
| 0ea3183288 | |||
| c6ff7c51f0 | |||
| 0240ab6144 | |||
| 2746ec49a3 | |||
| b3f1c943a7 | |||
| 7654ede904 | |||
| c882487d01 | |||
| 865e4839f3 | |||
| 5a270f6489 | |||
| 6776bb4bab | |||
| cbe9bad66e | |||
| 5761e1c1a4 | |||
| 062a5edf76 | |||
| a009e76568 | |||
| dcc9b856d7 | |||
| 592e52b333 | |||
| bc923be862 | |||
| e880631500 | |||
| d9b0834476 | |||
| 2fda22e168 | |||
| a5091cd124 | |||
| b2ec19ece4 | |||
| 72e64cfab7 | |||
| 7eacb6b57e | |||
| e0e1ca992f | |||
| f1a628dee4 | |||
| 81d49dc4b9 | |||
| 7e581183f4 | |||
| a9f3fa0c72 | |||
| e6c5a97f8c | |||
| efb9b70293 | |||
| 666c233d6c | |||
| 4307756719 | |||
| 622d0d3ff9 | |||
| ad763c2131 | |||
| 87a2ec9468 | |||
| dd590e8779 | |||
| 9555f3a2cd | |||
| 0b79fc33d7 | |||
| b7e14489da | |||
| 84b426042e | |||
| f683b9e770 | |||
| 5fb2c9d822 | |||
| 0f7280c227 | |||
| 4ebca86a66 | |||
| 1a0c6eed27 | |||
| 673e13ec57 | |||
| 7caac334f4 | |||
| 4e0e081b3e | |||
| 51dc8c81ed | |||
| 727eedf7d3 | |||
| e37fddf3ab | |||
| 885679e575 | |||
| 36554c3c34 | |||
| 2197062372 | |||
| 487b894f3d | |||
| a03603b274 | |||
| e6879dba63 | |||
| 68a43e33b9 | |||
| db2ab41636 | |||
| c624327a7a | |||
| 32ff5cbc1e | |||
| 9ba203c7b3 | |||
| 729625ef4f | |||
| fd3923a5f9 | |||
| c2fd07ea18 | |||
| d76a2d84b5 | |||
| 2a98f7482d | |||
| 12637d93ff | |||
| f63aba9058 | |||
| 668325a4ce | |||
| e891c68158 | |||
| b1fb032f43 | |||
| 23ea82952e | |||
| 9a65e44166 | |||
| 020cad897d | |||
| 5dfaff6296 | |||
| 5b03982043 | |||
| 8f6856d6fb | |||
| 976dd7aae2 | |||
| 0d21f4e937 | |||
| 1403449ad5 | |||
| e84af4f601 | |||
| 26b032c15c | |||
| cba3625394 | |||
| e1ddaff04d | |||
| 66ab5de442 | |||
| 0b9c03ca90 | |||
| c9dce0c1da | |||
| e00e77db15 | |||
| 1074449f91 | |||
| 08276e6e42 | |||
| 9a3d824a4a | |||
| 2789ee8f18 | |||
| a7ba643c35 | |||
| 28be53eefb | |||
| 219c45a352 | |||
| 1a3b83752e | |||
| c42f3c6844 | |||
| a5d3ba3900 | |||
| cdf0d44341 | |||
| 92f976a45d | |||
| 2bc858cde3 | |||
| 92e13a5d00 | |||
| 122f5d9f2e | |||
| 982ee0266c | |||
| 5f42a9bd05 | |||
| 1811df9ddb | |||
| 6bdfe7f895 | |||
| c6b286a1db | |||
| b3568a26f5 | |||
| 15ae0f521e | |||
| 2923d4b872 | |||
| d740e8b8a9 | |||
| a274edffba | |||
| eec211e038 | |||
| f5f888a0aa | |||
| 86ec1d6026 | |||
| bc3f5838f1 | |||
| 7e58b3273d | |||
| bed09bf8a4 | |||
| 28e55c6de6 | |||
| abb4537551 | |||
| b48f2f1660 | |||
| ccf8063a52 | |||
| 8694396942 | |||
| fb253e53a4 | |||
| fdd34863ba | |||
| 4ac95ad8cf | |||
| 132d550cb6 | |||
| efc5035144 | |||
| ebeac73f30 | |||
| 5303288b9c | |||
| bcac045c77 | |||
| d643df74b3 | |||
| 4c1c6d86c8 | |||
| 623448a220 | |||
| b403ce1e62 | |||
| 6faf8786ea | |||
| aaa4378b33 | |||
| 6512bfb4d9 | |||
| 1afabfd1b6 | |||
| f05e2880a9 | |||
| 81675008a6 | |||
| 8b4fc5719e | |||
| e4f7452241 | |||
| 9602379368 | |||
| 35ba39c196 | |||
| 6d09da40e0 | |||
| de44f21d64 | |||
| edc91e0e36 | |||
| 518cd21fd6 | |||
| b36ca2c4f1 | |||
| 2db79de722 | |||
| 3a9531b586 | |||
| f96d768341 | |||
| 26fb13fe2d | |||
| 67a9d80299 | |||
| 84249cab4b | |||
| f4305dfaa5 | |||
| 0c45c61c85 | |||
| 7d250b3384 | |||
| bb2029e21c | |||
| 0f0611f390 | |||
| 2904141c14 | |||
| c569a7a858 | |||
| 87db1fd8c1 | |||
| a1d2d09f28 | |||
| b949d7b221 | |||
| de468760d6 | |||
| 30a78df986 | |||
| e8622a190a | |||
| 75f098f002 | |||
| b034a07439 | |||
| 68956456dd | |||
| aa048cabe6 | |||
| 5dc67b995e | |||
| 721e4bda8b | |||
| 2673f83116 | |||
| bc68513a78 | |||
| 91250f199a | |||
| 3ec92a0784 | |||
| 70a9317ab3 | |||
| 71e36065e5 | |||
| 389d1ba3b9 | |||
| 18f5d4084d | |||
| 83744962f1 | |||
| df08a894cc | |||
| 2354828481 | |||
| 74693bda6f | |||
| 613ff5da71 | |||
| a11937699f | |||
| eb59ca77ef | |||
| 12d07fd870 | |||
| 1d18def642 | |||
| 70d4bce42f | |||
| c81454e00b | |||
| ac4ee2bcf2 | |||
| 9184c119d6 | |||
| 216b114346 | |||
| 793dbdef7e | |||
| 432e1e6065 | |||
| c8a02e1354 | |||
| 698345dbe9 | |||
| 5568073c17 | |||
| addb721d66 | |||
| 3bbf959086 | |||
| 0db4aa5f39 | |||
| f41ee7700d | |||
| 1c335d3172 | |||
| 191b3c09e2 | |||
| 725b4de74a | |||
| ce038bf56a | |||
| 8727038443 | |||
| afbed0e438 | |||
| b6a026da83 | |||
| fc74b723fa | |||
| b1fe1f6073 | |||
| 043ca9a63e | |||
| 46b49eea2f | |||
| 7430eb99cf | |||
| 111cccea97 | |||
| 5e9d87b1ad | |||
| c28b320b66 | |||
| a80a1bbe34 | |||
| c1808ae692 | |||
| d8277e851f | |||
| c795490164 | |||
| 3f2fa717c9 | |||
| c0be2330b0 | |||
| e86467d007 | |||
| e5afd54ce0 | |||
| 25d2af3b04 | |||
| 8e24583f2a | |||
| c09846bb36 | |||
| 86034bd955 | |||
| a9797879e8 | |||
| 407d2bba47 | |||
| 8f4b5ab4c7 | |||
| 0fd203371d | |||
| 68f2d8b925 | |||
| 973c30592f | |||
| 3886ec5291 | |||
| 929775c517 | |||
| 427893efef | |||
| cb33871934 | |||
| 4a86b24ff5 | |||
| 8f98de4abc | |||
| e6460208d3 | |||
| 3b7315d1e2 | |||
| 3aafe54887 | |||
| f08f19cd86 | |||
| 2e6a32b298 | |||
| 57df77a995 | |||
| 343c55f981 | |||
| 1660e0796d | |||
| b30f11ed7a | |||
| 2bdee705b7 | |||
| 31f567f1ef | |||
| 216573b65b | |||
| 4102690cf1 | |||
| a82ac9c50d | |||
| bb0257ccc6 | |||
| 142a70365f | |||
| 12ddf80fe9 | |||
| 34fcca052b | |||
| e06e7aa8f3 | |||
| 4d701be053 | |||
| 3bf02c558c | |||
| e7dcc8dc30 | |||
| b7f197d278 | |||
| 3412a0b7bd | |||
| 23951acdec | |||
| b56bb7f226 | |||
| f0fafe97fe | |||
| 9df360cf63 | |||
| 035ee3a402 | |||
| 035a2554ee | |||
| 4c8f8ff1b6 | |||
| 35cddab3bd | |||
| 0a5f6f2ca7 | |||
| 53253d443c | |||
| 07f2f9c39e | |||
| 1d4026ec71 | |||
| 6524fa3f9c | |||
| 6e24b2681b | |||
| 5ba20268dd | |||
| 4e03759c0f | |||
| a6be3e763f | |||
| 29ac119127 | |||
| 67ce93ffc8 | |||
| 08964f8775 | |||
| d8d2d84aa7 | |||
| 7d69fa3ed5 | |||
| dff7a8976a | |||
| 50fbe55be9 | |||
| 648543e536 | |||
| 3d2654923a | |||
| d03798629c | |||
| e470ac4b0f | |||
| 9324e3511f | |||
| 23d0607239 | |||
| ebba222a86 | |||
| fdbecb2a3f | |||
| 785513914c | |||
| c789853b32 | |||
| 97ec416b3e | |||
| 164c8ad05c | |||
| 7b02026476 | |||
| 1fb26b68c6 | |||
| 29fd8b8805 | |||
| 31b9048144 | |||
| 10c0e04926 | |||
| c0ad3ce1a6 | |||
| 82def1349f | |||
| 94a52aa2db | |||
| 50f65aa698 | |||
| e12314a6fa | |||
| 15e377e678 | |||
| 7b1dab8546 | |||
| 93e9dc5c1e | |||
| 0dcb046576 | |||
| 5288510979 | |||
| 81481832d8 | |||
| 27e704ab80 | |||
| da339a83cd | |||
| 99780d3eb0 | |||
| aee0ec7dec | |||
| b8e8beb62b |
@@ -0,0 +1,40 @@
|
|||||||
|
# Lines starting with '#' are comments.
|
||||||
|
# Each line is a file pattern followed by one or more owners.
|
||||||
|
|
||||||
|
# More details are here: https://help.github.com/articles/about-codeowners/
|
||||||
|
|
||||||
|
# The '*' pattern is global owners.
|
||||||
|
|
||||||
|
# Order is important. The last matching pattern has the most precedence.
|
||||||
|
# The folders are ordered as follows:
|
||||||
|
|
||||||
|
# In each subsection folders are ordered first by depth, then alphabetically.
|
||||||
|
# This should make it easy to add new rules without breaking existing ones.
|
||||||
|
|
||||||
|
# Something weird not covered by anything else
|
||||||
|
* @futurechimp @mmsinclair
|
||||||
|
|
||||||
|
# Rust rules:
|
||||||
|
*.rs @durch @futurechimp @jstuczyn @neacsu
|
||||||
|
Cargo.* @durch @futurechimp @jstuczyn @neacsu
|
||||||
|
|
||||||
|
# JS rules:
|
||||||
|
*.js @mmsinclair @fmtabbara @Aid19801
|
||||||
|
*.ts @mmsinclair @fmtabbara @Aid19801
|
||||||
|
*.tsx @mmsinclair @fmtabbara @Aid19801
|
||||||
|
*.jsx @mmsinclair @fmtabbara @Aid19801
|
||||||
|
|
||||||
|
# Something looking like possible documentation rules:
|
||||||
|
*.md @mfahampshire
|
||||||
|
|
||||||
|
# our docker scripts
|
||||||
|
/docker/ @neacsu
|
||||||
|
|
||||||
|
# if there are any changes in the core crypto, I feel like Ania should take a look:
|
||||||
|
/common/crypto/ @aniampio
|
||||||
|
/common/nymsphinx/ @aniampio
|
||||||
|
|
||||||
|
# Explorer and wallet should probably get looked by the product team
|
||||||
|
/explorer/ @nymtech/product
|
||||||
|
/nym-wallet/ @nymtech/product
|
||||||
|
/wallet-web/ @nymtech/product
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an enhancement to the product
|
||||||
|
title: "[Feature Request]"
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is...
|
||||||
|
|
||||||
|
**Is your request a feature not related to an existing problem? A new feature.**
|
||||||
|
For example.
|
||||||
|
- Given I am using the nym wallet
|
||||||
|
- When I transfer nym tokens across the network
|
||||||
|
- Then I want to have an url link in the wallet which navigates outside the application to the nym-explorer
|
||||||
|
|
||||||
|
**Where does the feature fit in the Nym real estate?**
|
||||||
|
- Application / UI
|
||||||
|
|
||||||
|
**What is this solving?**
|
||||||
|
How will this improve the product...
|
||||||
|
|
||||||
|
**Is this an update to packages or libraries?**
|
||||||
|
If so, please list them. If not, please ignore this section.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
name: Report
|
||||||
|
about: To help identify and reproduce issues
|
||||||
|
title: "[Issue]"
|
||||||
|
labels: bug, bug-needs-triage, qa
|
||||||
|
assignees: tommyv1987
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the issue**
|
||||||
|
A clear and concise description of what the issue is...
|
||||||
|
|
||||||
|
**Expected behaviour**
|
||||||
|
A clear and concise description of what you expected to happen...
|
||||||
|
|
||||||
|
**Stack Traces**
|
||||||
|
If there are stack traces or logs, please provide them here...
|
||||||
|
|
||||||
|
**Steps to Reproduce**
|
||||||
|
Steps to reproduce the behaviour, if you're familiar with BDD syntax, please write it in this style:
|
||||||
|
- Given I was doing X
|
||||||
|
- And I installed Y
|
||||||
|
- When I actioned Y
|
||||||
|
- Then I expect Z
|
||||||
|
|
||||||
|
*An example:*
|
||||||
|
- Given I was setting up a mix-node following the instructions in the docs
|
||||||
|
- And I successfully bonded my node via the the wallet
|
||||||
|
- When I went to start my mixnode
|
||||||
|
- Then I was presented with an error
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots to help explain your problem...
|
||||||
|
|
||||||
|
**Which area of Nym were you using?**
|
||||||
|
- UI: [e.g. Websites - network-explorer, nym-website]
|
||||||
|
- Application: [e.g Gateway, Client, Wallet]
|
||||||
|
- OS: [e.g. Ubuntu 20.x, MacOs Big Sur, Windows 10]
|
||||||
|
- Browser: [e.g Chrome (if applicable)]
|
||||||
|
- Version: [e.g. nym binary(0.11.0), browser(94.0)]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Please provide any other information
|
||||||
@@ -1,42 +1,102 @@
|
|||||||
name: Continuous integration
|
name: Continuous integration
|
||||||
|
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
matrix_prep:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: ${{ matrix.rust == 'nightly' }}
|
outputs:
|
||||||
strategy:
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
matrix:
|
|
||||||
rust: [stable, beta, nightly]
|
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
# creates the matrix strategy from build_matrix_includes.json
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- id: set-matrix
|
||||||
|
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||||
|
with:
|
||||||
|
inputFile: '.github/workflows/build_matrix_includes.json'
|
||||||
|
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
||||||
|
build:
|
||||||
|
needs: matrix_prep
|
||||||
|
strategy:
|
||||||
|
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.os == 'windows-latest' }}
|
||||||
|
steps:
|
||||||
|
- name: Install Dependencies (Linux)
|
||||||
|
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
|
||||||
- uses: actions-rs/toolchain@v1
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
toolchain: ${{ matrix.rust }}
|
toolchain: ${{ matrix.rust }}
|
||||||
override: true
|
override: true
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- name: Build all binaries
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --all
|
args: --all
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- name: Run all tests
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --all
|
args: --all
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- name: Check formatting
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: fmt
|
command: fmt
|
||||||
args: --all -- --check
|
args: --all -- --check
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- uses: actions-rs/clippy-check@v1
|
||||||
|
name: Clippy checks
|
||||||
|
# if: matrix.os == 'ubuntu-latest' && matrix.rust == 'stable'
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
args: --all-features
|
||||||
|
|
||||||
|
- name: Run clippy
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: -- -D warnings
|
args: -- -D warnings
|
||||||
|
|
||||||
|
# COCONUT stuff
|
||||||
|
- name: Reclaim some disk space (because Windows is being annoying)
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.os == 'windows-latest' }}
|
||||||
|
with:
|
||||||
|
command: clean
|
||||||
|
|
||||||
|
- name: Build all binaries with coconut enabled
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
args: --all --features=coconut
|
||||||
|
|
||||||
|
- name: Run all tests with coconut enabled
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --all --features=coconut
|
||||||
|
|
||||||
|
- name: Run clippy with coconut enabled
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
|
with:
|
||||||
|
command: clippy
|
||||||
|
args: --features=coconut -- -D warnings
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"os":"ubuntu-latest",
|
||||||
|
"rust":"stable",
|
||||||
|
"runOnEvent":"always"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"os":"windows-latest",
|
||||||
|
"rust":"stable",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"macos-latest",
|
||||||
|
"rust":"stable",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"os":"ubuntu-latest",
|
||||||
|
"rust":"beta",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"windows-latest",
|
||||||
|
"rust":"beta",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"macos-latest",
|
||||||
|
"rust":"beta",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"os":"ubuntu-latest",
|
||||||
|
"rust":"nightly",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"windows-latest",
|
||||||
|
"rust":"nightly",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"macos-latest",
|
||||||
|
"rust":"nightly",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
name: Clippy check
|
|
||||||
|
|
||||||
on: push
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
clippy_check:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v1
|
|
||||||
- run: rustup component add clippy
|
|
||||||
- uses: actions-rs/clippy-check@v1
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
args: --all-features
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"rust":"stable",
|
||||||
|
"runOnEvent":"always"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rust":"beta",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rust":"nightly",
|
||||||
|
"runOnEvent":"pull_request"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
name: ERC20 Bridge Contract
|
||||||
|
|
||||||
|
on: [ push, pull_request ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
matrix_prep:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
|
steps:
|
||||||
|
# creates the matrix strategy from build_matrix_includes.json
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- id: set-matrix
|
||||||
|
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||||
|
with:
|
||||||
|
inputFile: '.github/workflows/contract_matrix_includes.json'
|
||||||
|
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
||||||
|
erc20-bridge-contract:
|
||||||
|
needs: matrix_prep
|
||||||
|
strategy:
|
||||||
|
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||||
|
# since it's going to be compiled into wasm, there's absolutely
|
||||||
|
# no point in running CI on different OS-es
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: ${{ matrix.rust == 'nightly' }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
target: wasm32-unknown-unknown
|
||||||
|
override: true
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: '-C link-arg=-s'
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
args: --manifest-path contracts/erc20-bridge/Cargo.toml --target wasm32-unknown-unknown
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --manifest-path contracts/erc20-bridge/Cargo.toml
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --manifest-path contracts/erc20-bridge/Cargo.toml -- --check
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
|
with:
|
||||||
|
command: clippy
|
||||||
|
args: --manifest-path contracts/erc20-bridge/Cargo.toml -- -D warnings
|
||||||
@@ -1,16 +1,34 @@
|
|||||||
name: Mixnet Contract
|
name: Mixnet Contract
|
||||||
|
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
matrix_prep:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
|
steps:
|
||||||
|
# creates the matrix strategy from build_matrix_includes.json
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- id: set-matrix
|
||||||
|
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||||
|
with:
|
||||||
|
inputFile: '.github/workflows/contract_matrix_includes.json'
|
||||||
|
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
||||||
|
mixnet-contract:
|
||||||
# since it's going to be compiled into wasm, there's absolutely
|
# since it's going to be compiled into wasm, there's absolutely
|
||||||
# no point in running CI on different OS-es
|
# no point in running CI on different OS-es
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: ${{ matrix.rust == 'nightly' }}
|
continue-on-error: ${{ matrix.rust == 'nightly' }}
|
||||||
|
needs: matrix_prep
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||||
rust: [ stable, beta, nightly ]
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
@@ -23,6 +41,8 @@ jobs:
|
|||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- uses: actions-rs/cargo@v1
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: '-C link-arg=-s'
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --manifest-path contracts/mixnet/Cargo.toml --target wasm32-unknown-unknown
|
args: --manifest-path contracts/mixnet/Cargo.toml --target wasm32-unknown-unknown
|
||||||
@@ -38,6 +58,7 @@ jobs:
|
|||||||
args: --manifest-path contracts/mixnet/Cargo.toml -- --check
|
args: --manifest-path contracts/mixnet/Cargo.toml -- --check
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: --manifest-path contracts/mixnet/Cargo.toml -- -D warnings
|
args: --manifest-path contracts/mixnet/Cargo.toml -- -D warnings
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
name: Linting for Network Explorer (eslint/prettier)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'explorer/**'
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: explorer
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: custom-runner-linux
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '14'
|
||||||
|
- run: npm install
|
||||||
|
- name: Run ESLint
|
||||||
|
# GitHub should automatically annotate the PR
|
||||||
|
run: npm run lint
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
name: CI for Network Explorer
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'explorer/**'
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: explorer
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: custom-runner-linux
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install rsync
|
||||||
|
run: sudo apt-get install rsync
|
||||||
|
- uses: rlespinasse/github-slug-action@v3.x
|
||||||
|
- uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: '14'
|
||||||
|
- run: npm install
|
||||||
|
continue-on-error: true
|
||||||
|
- run: npm run test
|
||||||
|
continue-on-error: true
|
||||||
|
- run: npm run build
|
||||||
|
continue-on-error: true
|
||||||
|
- name: Deploy branch to CI www
|
||||||
|
continue-on-error: true
|
||||||
|
uses: easingthemes/ssh-deploy@main
|
||||||
|
env:
|
||||||
|
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
|
||||||
|
ARGS: "-rltgoDzvO --delete"
|
||||||
|
SOURCE: "explorer/dist/"
|
||||||
|
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
|
||||||
|
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
|
||||||
|
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/network-explorer-${{ env.GITHUB_REF_SLUG }}
|
||||||
|
EXCLUDE: "/dist/, /node_modules/"
|
||||||
|
- name: Keybase - Node Install
|
||||||
|
run: npm install
|
||||||
|
working-directory: .github/workflows/support-files/messages
|
||||||
|
- name: Keybase - Send Notification
|
||||||
|
env:
|
||||||
|
NYM_PROJECT_NAME: "Network Explorer"
|
||||||
|
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
|
||||||
|
NYM_CI_WWW_LOCATION: "network-explorer-${{ env.GITHUB_REF_SLUG }}"
|
||||||
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
|
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||||
|
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
||||||
|
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
||||||
|
KEYBASE_NYM_CHANNEL: "ci-network-explorer"
|
||||||
|
IS_SUCCESS: "${{ job.status == 'success' }}"
|
||||||
|
uses: docker://keybaseio/client:stable-node
|
||||||
|
with:
|
||||||
|
args: .github/workflows/support-files/messages/entry_point_notifications.sh
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
name: Webdriverio tests for nym wallet
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- "nym-wallet/**"
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: nym-wallet
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: wallet tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Tauri dependencies
|
||||||
|
run: >
|
||||||
|
sudo apt-get update &&
|
||||||
|
sudo apt-get install -y
|
||||||
|
libgtk-3-dev
|
||||||
|
libgtksourceview-3.0-dev
|
||||||
|
webkit2gtk-4.0
|
||||||
|
libappindicator3-dev
|
||||||
|
webkit2gtk-driver
|
||||||
|
xvfb
|
||||||
|
|
||||||
|
- name: Install minimal stable
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
|
||||||
|
- name: Node v16
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 16.x
|
||||||
|
|
||||||
|
- name: Install yarn for building application
|
||||||
|
run: yarn install
|
||||||
|
|
||||||
|
- name: Build application
|
||||||
|
run: yarn run webpack:build & yarn run tauri:build
|
||||||
|
|
||||||
|
- name: Check binary exists
|
||||||
|
run: |
|
||||||
|
cd target/release/
|
||||||
|
(test -f nym-wallet && echo nym binary exists) || echo wallet does not exist
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install
|
||||||
|
working-directory: nym-wallet/webdriver
|
||||||
|
|
||||||
|
- name: Remove existing user datafile
|
||||||
|
uses: JesseTG/rm@v1.0.2
|
||||||
|
with:
|
||||||
|
path: nym-wallet/webdriver/common/data/user-data.json
|
||||||
|
|
||||||
|
- name: Create user data json file
|
||||||
|
id: create-json
|
||||||
|
uses: jsdaniell/create-json@1.1.2
|
||||||
|
with:
|
||||||
|
name: "user-data.json"
|
||||||
|
json: ${{ secrets.WALLET_USERDATA }}
|
||||||
|
dir: "nym-wallet/webdriver/common/data/"
|
||||||
|
|
||||||
|
- name: Install tauri-driver
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: install
|
||||||
|
args: tauri-driver
|
||||||
|
|
||||||
|
- name: Launch tests
|
||||||
|
run: xvfb-run yarn test:runall
|
||||||
|
working-directory: nym-wallet/webdriver
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
.idea
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"trailingComma": "all",
|
||||||
|
"singleQuote": true,
|
||||||
|
"printWidth": 80,
|
||||||
|
"tabWidth": 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# pass exit codes out to GitHub Actions
|
||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
# change to the directory that contains this script
|
||||||
|
cd "${0%/*}"
|
||||||
|
|
||||||
|
# run the node script
|
||||||
|
node send_message.js
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥
|
||||||
|
> :rocket: {{ env.NYM_PROJECT_NAME }}
|
||||||
|
> 🔴 **FAILURE** :cry:
|
||||||
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
|
||||||
|
Commit message:
|
||||||
|
```
|
||||||
|
{{ env.GIT_COMMIT_MESSAGE }}
|
||||||
|
```
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "send-keybase-message",
|
||||||
|
"description": "Sends a notification message with the keybase package that fails when piped into the keybase CLI",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"format": "prettier --write send_message.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"handlebars": "^4.7.7",
|
||||||
|
"keybase-bot": "^3.6.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "2.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
const Bot = require('keybase-bot');
|
||||||
|
const Handlebars = require('handlebars');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const data = { env: process.env };
|
||||||
|
// const data = { ...PASTE TEST DATA HERE ... }; // -- DEV: uncomment to set test data
|
||||||
|
|
||||||
|
// validation of environment
|
||||||
|
if(!(process.env.NYM_PROJECT_NAME || data.env.NYM_PROJECT_NAME)) {
|
||||||
|
throw new Error('Please set env var NYM_PROJECT_NAME with the project name for displaying in notification messages');
|
||||||
|
}
|
||||||
|
const keybaseChannel = process.env.KEYBASE_NYM_CHANNEL || data.env.KEYBASE_NYM_CHANNEL;
|
||||||
|
if(!keybaseChannel) {
|
||||||
|
throw new Error('Please set env var KEYBASE_NYM_CHANNEL with the channel name for the notification message');
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract the git branch name
|
||||||
|
const GIT_BRANCH_NAME = (process.env.GITHUB_REF || data.env.GITHUB_REF).split('/').slice(2).join('/');
|
||||||
|
|
||||||
|
data.env.GIT_BRANCH_NAME = GIT_BRANCH_NAME;
|
||||||
|
const source = fs
|
||||||
|
.readFileSync(process.env.IS_SUCCESS === 'true' ? 'success' : 'failure')
|
||||||
|
.toString();
|
||||||
|
const template = Handlebars.compile(source);
|
||||||
|
const result = template(data);
|
||||||
|
|
||||||
|
// -- DEV: uncomment to show what is available in the handlebars template / show the result
|
||||||
|
// console.dir({ data }, { depth: null });
|
||||||
|
// console.log(result);
|
||||||
|
|
||||||
|
const bot = new Bot();
|
||||||
|
try {
|
||||||
|
const username = process.env.KEYBASE_NYMBOT_USERNAME;
|
||||||
|
const paperkey = process.env.KEYBASE_NYMBOT_PAPERKEY;
|
||||||
|
|
||||||
|
if(!username) {
|
||||||
|
throw new Error('Username is not defined. Please set env var KEYBASE_NYMBOT_USERNAME');
|
||||||
|
}
|
||||||
|
if(!paperkey) {
|
||||||
|
throw new Error('Paperkey is not defined. Please set env var KEYBASE_NYMBOT_PAPERKEY');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Initialising keybase with user "${username}" and key: "${'*'.repeat(paperkey.length)}"...`);
|
||||||
|
await bot.init(username, paperkey, { verbose: false });
|
||||||
|
|
||||||
|
const channel = {
|
||||||
|
name: 'nymtech_bot',
|
||||||
|
membersType: 'team',
|
||||||
|
topicName: keybaseChannel,
|
||||||
|
topic_type: 'CHAT',
|
||||||
|
};
|
||||||
|
const message = {
|
||||||
|
body: result,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(`Sending to ${channel.name}#${channel.topicName}...`);
|
||||||
|
await bot.chat.send(channel, message);
|
||||||
|
|
||||||
|
console.log('Message sent!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
process.exitCode = -1;
|
||||||
|
} finally {
|
||||||
|
await bot.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩
|
||||||
|
> :rocket: {{ env.NYM_PROJECT_NAME }} ➡️➡️➡️➡️➡️ **View output:** https://{{ env.NYM_CI_WWW_LOCATION }}.{{ env.NYM_CI_WWW_BASE }}/
|
||||||
|
> ✅ **SUCCESS**
|
||||||
|
> `branch` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/tree/{{ env.GIT_BRANCH_NAME }}
|
||||||
|
> `commit` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/commit/{{ env.GITHUB_SHA }}
|
||||||
|
> `build ` {{ env.GITHUB_SERVER_URL }}/{{ env.GITHUB_REPOSITORY }}/actions/runs/{{ env.GITHUB_RUN_ID }}
|
||||||
|
|
||||||
|
Commit message:
|
||||||
|
```
|
||||||
|
{{ env.GIT_COMMIT_MESSAGE }}
|
||||||
|
```
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
name: Publish Tauri Wallet
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- nym-wallet-*
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Run a one-line script
|
||||||
|
run: echo Hello, world!
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
name: Generate TS types
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- "explorer/**"
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- "explorer/**"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nym-wallet-types:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
steps:
|
||||||
|
- name: Prepare
|
||||||
|
run: sudo apt-get update && sudo apt-get install -y libpango1.0-dev libatk1.0-dev libgdk-pixbuf2.0-dev libsoup2.4-dev librust-gdk-dev libwebkit2gtk-4.0-dev
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
- name: Generate TS
|
||||||
|
run: cd nym-wallet/src-tauri && cargo test
|
||||||
|
- uses: EndBug/add-and-commit@v7.2.1 # https://github.com/marketplace/actions/add-commit
|
||||||
|
with:
|
||||||
|
add: '["nym-wallet"]'
|
||||||
|
message: "[ci skip] Generate TS types"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
name: Wasm Client
|
name: Wasm Client
|
||||||
|
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ci:
|
wasm:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
@@ -16,10 +19,16 @@ jobs:
|
|||||||
override: true
|
override: true
|
||||||
components: rustfmt, clippy
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
# token credentials (non-coconut) don't work for wasm right now
|
||||||
|
# - uses: actions-rs/cargo@v1
|
||||||
|
# with:
|
||||||
|
# command: build
|
||||||
|
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
||||||
|
|
||||||
- uses: actions-rs/cargo@v1
|
- uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown --features=coconut
|
||||||
|
|
||||||
# for some reason this does not seem to work correctly, leave it for later, building is good enough for now
|
# for some reason this does not seem to work correctly, leave it for later, building is good enough for now
|
||||||
# - uses: actions-rs/cargo@v1
|
# - uses: actions-rs/cargo@v1
|
||||||
@@ -36,4 +45,4 @@ jobs:
|
|||||||
# - uses: actions-rs/cargo@v1
|
# - uses: actions-rs/cargo@v1
|
||||||
# with:
|
# with:
|
||||||
# command: clippy
|
# command: clippy
|
||||||
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
|
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ target
|
|||||||
/.vscode/settings.json
|
/.vscode/settings.json
|
||||||
validator/.vscode
|
validator/.vscode
|
||||||
sample-configs/validator-config.toml
|
sample-configs/validator-config.toml
|
||||||
.vscode
|
|
||||||
scripts/deploy_qa.sh
|
scripts/deploy_qa.sh
|
||||||
scripts/run_gate.sh
|
scripts/run_gate.sh
|
||||||
scripts/run_mix.sh
|
scripts/run_mix.sh
|
||||||
@@ -26,3 +25,12 @@ v6-topology.json
|
|||||||
/explorer/public/downloads/mixmining.json
|
/explorer/public/downloads/mixmining.json
|
||||||
/explorer/public/downloads/topology.json
|
/explorer/public/downloads/topology.json
|
||||||
/clients/validator/examples/nym-driver-example/current-contract.txt
|
/clients/validator/examples/nym-driver-example/current-contract.txt
|
||||||
|
validator-api/v4.json
|
||||||
|
validator-api/v6.json
|
||||||
|
**/node_modules
|
||||||
|
validator-api/keypair
|
||||||
|
contracts/mixnet/code_id
|
||||||
|
contracts/mixnet/Justfile
|
||||||
|
contracts/mixnet/Makefile
|
||||||
|
validator-config
|
||||||
|
*.patch
|
||||||
@@ -1,6 +1,98 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [v0.10.1](https://github.com/nymtech/nym/tree/v0.10.1) (2021-05-24)
|
## [v0.11.0](https://github.com/nymtech/nym/tree/v0.11.0) (2021-07-21)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/nymtech/nym/compare/v0.10.1...v0.11.0)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Investigate why --clients-host and --mix-host are distinct for gateways [\#435](https://github.com/nymtech/nym/issues/435)
|
||||||
|
- Bugfix/verloc fixes and adjustments [\#618](https://github.com/nymtech/nym/pull/618) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Update the metrics endpoint [\#597](https://github.com/nymtech/nym/issues/597)
|
||||||
|
- Intercontinental problems [\#143](https://github.com/nymtech/nym/issues/143)
|
||||||
|
|
||||||
|
**Closed issues:**
|
||||||
|
|
||||||
|
- Rename `PagedResponse` into `PagedMixnodeResponse` [\#657](https://github.com/nymtech/nym/issues/657)
|
||||||
|
- Change `u64` layer type in contract code [\#648](https://github.com/nymtech/nym/issues/648)
|
||||||
|
- Change `String` types of sphinx and identity keys in contract code [\#647](https://github.com/nymtech/nym/issues/647)
|
||||||
|
- Remove the terrible `decimal_sub_one` once we update contract/validators [\#639](https://github.com/nymtech/nym/issues/639)
|
||||||
|
- After update: failed to receive reply to our echo packet within 1.5s. Stopping the test [\#621](https://github.com/nymtech/nym/issues/621)
|
||||||
|
- update to v0.10.1, it show ERROR message "failed to receive reply to our echo packet within 1.5s" [\#620](https://github.com/nymtech/nym/issues/620)
|
||||||
|
- Make validator client send as much tokens for bonding as required [\#614](https://github.com/nymtech/nym/issues/614)
|
||||||
|
- Update mixnode `init` to not query for entire topology [\#610](https://github.com/nymtech/nym/issues/610)
|
||||||
|
- Potentially extend metrics with number of dropped packets [\#595](https://github.com/nymtech/nym/issues/595)
|
||||||
|
- Delegated staking for gateways [\#579](https://github.com/nymtech/nym/issues/579)
|
||||||
|
- Delegated staking for mixnodes [\#578](https://github.com/nymtech/nym/issues/578)
|
||||||
|
- Improved mixnode and gateway info [\#577](https://github.com/nymtech/nym/issues/577)
|
||||||
|
- Gateway bonding [\#576](https://github.com/nymtech/nym/issues/576)
|
||||||
|
- No graceful degradation on low traffic [\#513](https://github.com/nymtech/nym/issues/513)
|
||||||
|
- Network monitor should not update when 0 packets come back [\#456](https://github.com/nymtech/nym/issues/456)
|
||||||
|
- Add mixnode statistics endpoint [\#406](https://github.com/nymtech/nym/issues/406)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Return the vec instead of the cache wrapper for topology [\#695](https://github.com/nymtech/nym/pull/695) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Updated sign command [\#694](https://github.com/nymtech/nym/pull/694) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- got rid of denomination error in webwallet bonding interface [\#691](https://github.com/nymtech/nym/pull/691) ([mfahampshire](https://github.com/mfahampshire))
|
||||||
|
- Docker testing env [\#687](https://github.com/nymtech/nym/pull/687) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Changed Layer serde behaviour for easier usage [\#686](https://github.com/nymtech/nym/pull/686) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Merge the nym-wallet-web repo into a nym directory [\#684](https://github.com/nymtech/nym/pull/684) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Temporarily using non-cached gateways so we can get our next version … [\#683](https://github.com/nymtech/nym/pull/683) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Updating wallet URL in mixnode startup output [\#682](https://github.com/nymtech/nym/pull/682) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/node status api [\#680](https://github.com/nymtech/nym/pull/680) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Using specific commit of rocket cors [\#678](https://github.com/nymtech/nym/pull/678) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Disables nightly clippy CI [\#677](https://github.com/nymtech/nym/pull/677) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Minimize read/write cache contention [\#676](https://github.com/nymtech/nym/pull/676) ([durch](https://github.com/durch))
|
||||||
|
- Feature/validator client upgrade [\#675](https://github.com/nymtech/nym/pull/675) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Use cached topology for clients [\#674](https://github.com/nymtech/nym/pull/674) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Use rocket 0.5-rc1, remove rocket-contrib [\#672](https://github.com/nymtech/nym/pull/672) ([durch](https://github.com/durch))
|
||||||
|
- Feature/validator api config [\#671](https://github.com/nymtech/nym/pull/671) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Fix a dependabot nag [\#670](https://github.com/nymtech/nym/pull/670) ([durch](https://github.com/durch))
|
||||||
|
- Removed standalone network-monitor [\#669](https://github.com/nymtech/nym/pull/669) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Remove mut where possible, parallel cache requests [\#668](https://github.com/nymtech/nym/pull/668) ([durch](https://github.com/durch))
|
||||||
|
- Rework validator client requests [\#667](https://github.com/nymtech/nym/pull/667) ([durch](https://github.com/durch))
|
||||||
|
- Generalize cache, and cache gateways [\#666](https://github.com/nymtech/nym/pull/666) ([durch](https://github.com/durch))
|
||||||
|
- Validator API server [\#665](https://github.com/nymtech/nym/pull/665) ([durch](https://github.com/durch))
|
||||||
|
- Layer selection [\#664](https://github.com/nymtech/nym/pull/664) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Removing validator binaries, these should go into Github releases [\#663](https://github.com/nymtech/nym/pull/663) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Rename network-monitor [\#662](https://github.com/nymtech/nym/pull/662) ([durch](https://github.com/durch))
|
||||||
|
- Adds @neacsu as code owner [\#661](https://github.com/nymtech/nym/pull/661) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/total delegation field [\#660](https://github.com/nymtech/nym/pull/660) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- contracts: Removed mixnode location from the bonding process [\#659](https://github.com/nymtech/nym/pull/659) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Use thiserror for validator-client [\#658](https://github.com/nymtech/nym/pull/658) ([durch](https://github.com/durch))
|
||||||
|
- Feature/configurable verloc http ports [\#656](https://github.com/nymtech/nym/pull/656) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/describe location [\#655](https://github.com/nymtech/nym/pull/655) ([neacsu](https://github.com/neacsu))
|
||||||
|
- Feature/host ip split [\#654](https://github.com/nymtech/nym/pull/654) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/cosmwasm 0.14.1 update [\#653](https://github.com/nymtech/nym/pull/653) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Allow passing optional explicit bond value [\#652](https://github.com/nymtech/nym/pull/652) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Introduced type aliases for mixnode and gateway keys [\#650](https://github.com/nymtech/nym/pull/650) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bugfix/delegation type fixes [\#649](https://github.com/nymtech/nym/pull/649) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Removing the ancient explorer in preparation for a new dawn. [\#645](https://github.com/nymtech/nym/pull/645) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Testing code owners again [\#644](https://github.com/nymtech/nym/pull/644) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- TypeScript client v0.12.0 [\#641](https://github.com/nymtech/nym/pull/641) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/reverse contract mapping [\#640](https://github.com/nymtech/nym/pull/640) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bump websockets from 8.1 to 9.1 in /clients/native/examples/python-examples/websocket [\#638](https://github.com/nymtech/nym/pull/638) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Chore/clippy nightly fixes [\#636](https://github.com/nymtech/nym/pull/636) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/delegated staking [\#635](https://github.com/nymtech/nym/pull/635) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bump ws from 6.2.1 to 6.2.2 in /clients/validator [\#634](https://github.com/nymtech/nym/pull/634) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump ws from 6.2.1 to 6.2.2 in /clients/native/examples/js-examples/websocket [\#633](https://github.com/nymtech/nym/pull/633) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump ws from 6.2.1 to 6.2.2 in /clients/webassembly/js-example [\#632](https://github.com/nymtech/nym/pull/632) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Feature/stats endpoint [\#631](https://github.com/nymtech/nym/pull/631) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Updated all js related dependencies [\#629](https://github.com/nymtech/nym/pull/629) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/per layer count [\#628](https://github.com/nymtech/nym/pull/628) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Changed rewarding behaviour on not found bonds [\#627](https://github.com/nymtech/nym/pull/627) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bump dns-packet from 1.3.1 to 1.3.4 in /clients/native/examples/js-examples/websocket [\#626](https://github.com/nymtech/nym/pull/626) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump dns-packet from 1.3.1 to 1.3.4 in /clients/webassembly/js-example [\#625](https://github.com/nymtech/nym/pull/625) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Feature/update validator binaries [\#624](https://github.com/nymtech/nym/pull/624) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Checking for required bond rather than using hardcoded value [\#623](https://github.com/nymtech/nym/pull/623) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bump browserslist from 4.14.1 to 4.16.6 in /clients/native/examples/js-examples/websocket [\#619](https://github.com/nymtech/nym/pull/619) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Changed omitted print to a debug call [\#617](https://github.com/nymtech/nym/pull/617) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
|
||||||
|
## [v0.10.1](https://github.com/nymtech/nym/tree/v0.10.1) (2021-05-25)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.10.0...v0.10.1)
|
[Full Changelog](https://github.com/nymtech/nym/compare/v0.10.0...v0.10.1)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
opt-level = "s"
|
opt-level = "s"
|
||||||
|
overflow-checks = true
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
@@ -11,19 +12,23 @@ panic = "abort"
|
|||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
|
"clients/client-core",
|
||||||
"clients/native",
|
"clients/native",
|
||||||
"clients/native/websocket-requests",
|
"clients/native/websocket-requests",
|
||||||
"clients/socks5",
|
"clients/socks5",
|
||||||
|
"clients/tauri-client/src-tauri",
|
||||||
"clients/webassembly",
|
"clients/webassembly",
|
||||||
"clients/client-core",
|
|
||||||
"common/client-libs/gateway-client",
|
"common/client-libs/gateway-client",
|
||||||
"common/client-libs/metrics-client",
|
|
||||||
"common/client-libs/mixnet-client",
|
"common/client-libs/mixnet-client",
|
||||||
"common/client-libs/validator-client",
|
"common/client-libs/validator-client",
|
||||||
|
"common/coconut-interface",
|
||||||
"common/config",
|
"common/config",
|
||||||
|
"common/credentials",
|
||||||
"common/crypto",
|
"common/crypto",
|
||||||
|
"common/erc20-bridge-contract",
|
||||||
"common/mixnet-contract",
|
"common/mixnet-contract",
|
||||||
"common/mixnode-common",
|
"common/mixnode-common",
|
||||||
|
"common/network-defaults",
|
||||||
"common/nonexhaustive-delayqueue",
|
"common/nonexhaustive-delayqueue",
|
||||||
"common/nymsphinx",
|
"common/nymsphinx",
|
||||||
"common/nymsphinx/acknowledgements",
|
"common/nymsphinx/acknowledgements",
|
||||||
@@ -36,15 +41,16 @@ members = [
|
|||||||
"common/nymsphinx/params",
|
"common/nymsphinx/params",
|
||||||
"common/nymsphinx/types",
|
"common/nymsphinx/types",
|
||||||
"common/pemstore",
|
"common/pemstore",
|
||||||
"common/socks5/requests",
|
|
||||||
"common/socks5/proxy-helpers",
|
"common/socks5/proxy-helpers",
|
||||||
|
"common/socks5/requests",
|
||||||
"common/topology",
|
"common/topology",
|
||||||
"common/wasm-utils",
|
"common/wasm-utils",
|
||||||
|
"explorer-api",
|
||||||
"gateway",
|
"gateway",
|
||||||
"gateway/gateway-requests",
|
"gateway/gateway-requests",
|
||||||
"mixnode",
|
"mixnode",
|
||||||
"network-monitor",
|
|
||||||
"service-providers/network-requester",
|
"service-providers/network-requester",
|
||||||
|
"validator-api",
|
||||||
]
|
]
|
||||||
|
|
||||||
default-members = [
|
default-members = [
|
||||||
@@ -54,7 +60,7 @@ default-members = [
|
|||||||
"gateway",
|
"gateway",
|
||||||
"service-providers/network-requester",
|
"service-providers/network-requester",
|
||||||
"mixnode",
|
"mixnode",
|
||||||
"network-monitor",
|
"validator-api",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = ["explorer"]
|
exclude = ["explorer", "contracts", "tokenomics-py"]
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ SPDX-License-Identifier: Apache-2.0
|
|||||||
|
|
||||||
## The Nym Privacy Platform
|
## The Nym Privacy Platform
|
||||||
|
|
||||||
This repository contains the Nym mixnet.
|
|
||||||
|
|
||||||
The platform is composed of multiple Rust crates. Top-level executable binary crates include:
|
The platform is composed of multiple Rust crates. Top-level executable binary crates include:
|
||||||
|
|
||||||
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
|
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
|
||||||
@@ -15,6 +13,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
|||||||
* nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices.
|
* nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices.
|
||||||
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||||
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
||||||
|
* nym-wallet (currently in development)- a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||||
|
|
||||||
[](https://opensource.org/licenses/Apache-2.0)
|
[](https://opensource.org/licenses/Apache-2.0)
|
||||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||||
@@ -22,7 +21,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
|||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs).
|
Platform build instructions are available on [our docs site](https://nymtech.net/docs/0.11.0/overview/index/).
|
||||||
|
|
||||||
### Developing
|
### Developing
|
||||||
|
|
||||||
@@ -32,6 +31,46 @@ There's a `.env.sample-dev` file provided which you can rename to `.env` if you
|
|||||||
|
|
||||||
You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel.
|
You can chat to us in [Keybase](https://keybase.io). Download their chat app, then click **Teams -> Join a team**. Type **nymtech.friends** into the team name and hit **continue**. For general chat, hang out in the **#general** channel. Our development takes places in the **#dev** channel. Node operators should be in the **#node-operators** channel.
|
||||||
|
|
||||||
|
### Rewards
|
||||||
|
|
||||||
|
Node, node operator and delegator rewards are determined according to the principles laid out in the section 6 of [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf). Below is a TLDR of the variables and formulas involved in calculating the epoch rewards. Initial reward pool is set to 250 million Nym, making the circulating supply 750 million Nym.
|
||||||
|
|
||||||
|
|Symbol|Definition|
|
||||||
|
|---|---|
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=R">|global share of rewards available, starts at 2% of the reward pool.
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=R_{i}">|node reward for mixnode `i`.
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=\sigma_{i}">|ratio of total node stake (node bond + all delegations) to the token circulating supply.
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=\lambda_{i}">|ratio of stake operator has plaged to their node to the token circulating supply.
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=\omega_{i}">|fraction of total effort undertaken by node `i`, set to `1/k` in testnet Milhon.
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=k">|number of nodes stakeholders are incentivised to create, set by the validators, a matter of governance. Currently determined by the `active set` size, and set to 5000 in testnet Milhon.
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=\alpha">|Sybil attack resistance parameter - the higher this parameter is set the stronger the reduction in competitivness gets for a Sybil attacker.
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=PM_{i}">|declared profit margin of operator `i`, defaults to 10% in testnet Milhon.
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=PF_{i}">|uptime of node `i`, scaled to 0 - 1, for the rewarding epoch
|
||||||
|
|<img src="https://render.githubusercontent.com/render/math?math=PP_{i}">|cost of operating node `i` for the duration of the rewarding eopoch, set to 40 Nym for testnet Milhon.
|
||||||
|
|
||||||
|
Node reward for node `i` is determined as:
|
||||||
|
|
||||||
|
<img src="https://render.githubusercontent.com/render/math?math=R_{i}=PF_{i} \cdot R \cdot (\sigma^'_{i} \cdot \omega_{i} \cdot k %2b \alpha \cdot \lambda^'_{i} \cdot \sigma^'_{i} \cdot k)/(1 %2b \alpha)">
|
||||||
|
|
||||||
|
where:
|
||||||
|
|
||||||
|
<img src="https://render.githubusercontent.com/render/math?math=\sigma^'_{i} = min\{\sigma_{i}, 1/k\}">
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
<img src="https://render.githubusercontent.com/render/math?math=\lambda^'_{i} = min\{\lambda_{i}, 1/k\}">
|
||||||
|
|
||||||
|
Operator of node `i` is credited with the following amount:
|
||||||
|
|
||||||
|
<img src="https://render.githubusercontent.com/render/math?math=min\{PP_{i},R_{i})\} %2b max\{0, (PM_{i} %2b (1 - PM_{i}) \cdot \lambda_{i}/\delta_{i}) \cdot (R_{i} - PP_{i})\}">
|
||||||
|
|
||||||
|
Delegate with stake `s` recieves:
|
||||||
|
|
||||||
|
<img src="https://render.githubusercontent.com/render/math?math=max\{0, (1-PM_{i}) \cdot (s^'/\sigma_{i}) \cdot (R_{i} - PP_{i})\}">
|
||||||
|
|
||||||
|
where `s'` is stake `s` scaled over total token circulating supply.
|
||||||
|
|
||||||
### Licensing and copyright information
|
### Licensing and copyright information
|
||||||
|
|
||||||
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
|
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "client-core"
|
name = "client-core"
|
||||||
version = "0.10.1"
|
version = "0.11.0"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
sled = "0.34"
|
sled = "0.34"
|
||||||
tokio = { version = "1.4", features = ["macros"] }
|
tokio = { version = "1.4", features = ["macros"] }
|
||||||
|
url = { version ="2.2", features = ["serde"] }
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
config = { path = "../../common/config" }
|
config = { path = "../../common/config" }
|
||||||
@@ -28,4 +29,7 @@ topology = { path = "../../common/topology" }
|
|||||||
validator-client = { path = "../../common/client-libs/validator-client" }
|
validator-client = { path = "../../common/client-libs/validator-client" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
coconut = []
|
||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::mix_traffic::BatchMixMessageSender;
|
use crate::client::mix_traffic::BatchMixMessageSender;
|
||||||
use crate::client::topology_control::TopologyAccessor;
|
use crate::client::topology_control::TopologyAccessor;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use crate::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use crypto::asymmetric::{encryption, identity};
|
use crypto::asymmetric::{encryption, identity};
|
||||||
@@ -72,8 +61,8 @@ impl KeyManager {
|
|||||||
// I have absolutely no idea why the compiler insists it's unused. The call happens during client::init::execute
|
// I have absolutely no idea why the compiler insists it's unused. The call happens during client::init::execute
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
/// After shared key with the gateway is derived, puts its ownership to this instance of a [`KeyManager`].
|
/// After shared key with the gateway is derived, puts its ownership to this instance of a [`KeyManager`].
|
||||||
pub fn insert_gateway_shared_key(&mut self, gateway_shared_key: SharedKeys) {
|
pub fn insert_gateway_shared_key(&mut self, gateway_shared_key: Arc<SharedKeys>) {
|
||||||
self.gateway_shared_key = Some(Arc::new(gateway_shared_key))
|
self.gateway_shared_key = Some(gateway_shared_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loads previously stored keys from the disk.
|
/// Loads previously stored keys from the disk.
|
||||||
@@ -127,12 +116,12 @@ impl KeyManager {
|
|||||||
),
|
),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
pemstore::store_key(self.ack_key.as_ref(), &client_pathfinder.ack_key())?;
|
pemstore::store_key(self.ack_key.as_ref(), client_pathfinder.ack_key())?;
|
||||||
|
|
||||||
match self.gateway_shared_key.as_ref() {
|
match self.gateway_shared_key.as_ref() {
|
||||||
None => warn!("No gateway shared key available to store!"),
|
None => warn!("No gateway shared key available to store!"),
|
||||||
Some(gate_key) => {
|
Some(gate_key) => {
|
||||||
pemstore::store_key(gate_key.as_ref(), &client_pathfinder.gateway_shared_key())?
|
pemstore::store_key(gate_key.as_ref(), client_pathfinder.gateway_shared_key())?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,8 +143,7 @@ impl KeyManager {
|
|||||||
// hence it's up to us to ensure it's called in correct context
|
// hence it's up to us to ensure it's called in correct context
|
||||||
pub fn gateway_shared_key(&self) -> Arc<SharedKeys> {
|
pub fn gateway_shared_key(&self) -> Arc<SharedKeys> {
|
||||||
Arc::clone(
|
Arc::clone(
|
||||||
&self
|
self.gateway_shared_key
|
||||||
.gateway_shared_key
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("tried to unwrap empty gateway key!"),
|
.expect("tried to unwrap empty gateway key!"),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
@@ -51,7 +40,7 @@ impl MixTrafficController {
|
|||||||
async fn on_messages(&mut self, mut mix_packets: Vec<MixPacket>) {
|
async fn on_messages(&mut self, mut mix_packets: Vec<MixPacket>) {
|
||||||
debug_assert!(!mix_packets.is_empty());
|
debug_assert!(!mix_packets.is_empty());
|
||||||
|
|
||||||
let success = if mix_packets.len() == 1 {
|
let result = if mix_packets.len() == 1 {
|
||||||
let mix_packet = mix_packets.pop().unwrap();
|
let mix_packet = mix_packets.pop().unwrap();
|
||||||
self.gateway_client.send_mix_packet(mix_packet).await
|
self.gateway_client.send_mix_packet(mix_packet).await
|
||||||
} else {
|
} else {
|
||||||
@@ -60,7 +49,7 @@ impl MixTrafficController {
|
|||||||
.await
|
.await
|
||||||
};
|
};
|
||||||
|
|
||||||
match success {
|
match result {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to send sphinx packet(s) to the gateway! - {:?}", e);
|
error!("Failed to send sphinx packet(s) to the gateway! - {:?}", e);
|
||||||
self.consecutive_gateway_failure_count += 1;
|
self.consecutive_gateway_failure_count += 1;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use super::action_controller::{Action, ActionSender};
|
use super::action_controller::{Action, ActionSender};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use super::PendingAcknowledgement;
|
use super::PendingAcknowledgement;
|
||||||
use crate::client::real_messages_control::acknowledgement_control::RetransmissionRequestSender;
|
use crate::client::real_messages_control::acknowledgement_control::RetransmissionRequestSender;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use super::action_controller::{Action, ActionSender};
|
use super::action_controller::{Action, ActionSender};
|
||||||
use super::PendingAcknowledgement;
|
use super::PendingAcknowledgement;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
acknowledgement_listener::AcknowledgementListener, action_controller::ActionController,
|
acknowledgement_listener::AcknowledgementListener, action_controller::ActionController,
|
||||||
@@ -24,7 +13,6 @@ use crate::client::{inbound_messages::InputMessageReceiver, topology_control::To
|
|||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use gateway_client::AcknowledgementReceiver;
|
use gateway_client::AcknowledgementReceiver;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::params::PacketMode;
|
|
||||||
use nymsphinx::{
|
use nymsphinx::{
|
||||||
acknowledgements::AckKey,
|
acknowledgements::AckKey,
|
||||||
addressing::clients::Recipient,
|
addressing::clients::Recipient,
|
||||||
@@ -131,14 +119,6 @@ pub(super) struct Config {
|
|||||||
|
|
||||||
/// Average delay a data packet is going to get delayed at a single mixnode.
|
/// Average delay a data packet is going to get delayed at a single mixnode.
|
||||||
average_packet_delay: Duration,
|
average_packet_delay: Duration,
|
||||||
|
|
||||||
/// Mode of all mix packets created - VPN or Mix. They indicate whether packets should get delayed
|
|
||||||
/// and keys reused.
|
|
||||||
packet_mode: PacketMode,
|
|
||||||
|
|
||||||
/// If the mode of the client is set to VPN it specifies number of packets created with the
|
|
||||||
/// same initial secret until it gets rotated.
|
|
||||||
vpn_key_reuse_limit: Option<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@@ -147,16 +127,12 @@ impl Config {
|
|||||||
ack_wait_multiplier: f64,
|
ack_wait_multiplier: f64,
|
||||||
average_ack_delay: Duration,
|
average_ack_delay: Duration,
|
||||||
average_packet_delay: Duration,
|
average_packet_delay: Duration,
|
||||||
packet_mode: PacketMode,
|
|
||||||
vpn_key_reuse_limit: Option<usize>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Config {
|
Config {
|
||||||
ack_wait_addition,
|
ack_wait_addition,
|
||||||
ack_wait_multiplier,
|
ack_wait_multiplier,
|
||||||
average_ack_delay,
|
average_ack_delay,
|
||||||
average_packet_delay,
|
average_packet_delay,
|
||||||
packet_mode,
|
|
||||||
vpn_key_reuse_limit,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,8 +173,6 @@ where
|
|||||||
ack_recipient,
|
ack_recipient,
|
||||||
config.average_packet_delay,
|
config.average_packet_delay,
|
||||||
config.average_ack_delay,
|
config.average_ack_delay,
|
||||||
config.packet_mode,
|
|
||||||
config.vpn_key_reuse_limit,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// will listen for any acks coming from the network
|
// will listen for any acks coming from the network
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use super::action_controller::{Action, ActionSender};
|
use super::action_controller::{Action, ActionSender};
|
||||||
use super::PendingAcknowledgement;
|
use super::PendingAcknowledgement;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use super::action_controller::{Action, ActionSender};
|
use super::action_controller::{Action, ActionSender};
|
||||||
use super::SentPacketNotificationReceiver;
|
use super::SentPacketNotificationReceiver;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// INPUT: InputMessage from user
|
// INPUT: InputMessage from user
|
||||||
// INPUT2: Acks from mix
|
// INPUT2: Acks from mix
|
||||||
@@ -30,7 +19,6 @@ use gateway_client::AcknowledgementReceiver;
|
|||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::acknowledgements::AckKey;
|
use nymsphinx::acknowledgements::AckKey;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::params::PacketMode;
|
|
||||||
use rand::{rngs::OsRng, CryptoRng, Rng};
|
use rand::{rngs::OsRng, CryptoRng, Rng};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -62,20 +50,9 @@ pub struct Config {
|
|||||||
|
|
||||||
/// Average delay an acknowledgement packet is going to get delayed at a single mixnode.
|
/// Average delay an acknowledgement packet is going to get delayed at a single mixnode.
|
||||||
average_ack_delay_duration: Duration,
|
average_ack_delay_duration: Duration,
|
||||||
|
|
||||||
/// Mode of all mix packets created - VPN or Mix. They indicate whether packets should get delayed
|
|
||||||
/// and keys reused.
|
|
||||||
packet_mode: PacketMode,
|
|
||||||
|
|
||||||
/// If the mode of the client is set to VPN it specifies number of packets created with the
|
|
||||||
/// same initial secret until it gets rotated.
|
|
||||||
vpn_key_reuse_limit: Option<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
// at this point I'm not entirely sure how to deal with this warning without
|
|
||||||
// some considerable refactoring
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ack_key: Arc<AckKey>,
|
ack_key: Arc<AckKey>,
|
||||||
ack_wait_multiplier: f64,
|
ack_wait_multiplier: f64,
|
||||||
@@ -84,8 +61,6 @@ impl Config {
|
|||||||
average_message_sending_delay: Duration,
|
average_message_sending_delay: Duration,
|
||||||
average_packet_delay_duration: Duration,
|
average_packet_delay_duration: Duration,
|
||||||
self_recipient: Recipient,
|
self_recipient: Recipient,
|
||||||
packet_mode: PacketMode,
|
|
||||||
vpn_key_reuse_limit: Option<usize>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Config {
|
Config {
|
||||||
ack_key,
|
ack_key,
|
||||||
@@ -95,8 +70,6 @@ impl Config {
|
|||||||
average_message_sending_delay,
|
average_message_sending_delay,
|
||||||
average_packet_delay_duration,
|
average_packet_delay_duration,
|
||||||
average_ack_delay_duration,
|
average_ack_delay_duration,
|
||||||
packet_mode,
|
|
||||||
vpn_key_reuse_limit,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,8 +110,6 @@ impl RealMessagesController<OsRng> {
|
|||||||
config.ack_wait_multiplier,
|
config.ack_wait_multiplier,
|
||||||
config.average_ack_delay_duration,
|
config.average_ack_delay_duration,
|
||||||
config.average_packet_delay_duration,
|
config.average_packet_delay_duration,
|
||||||
config.packet_mode,
|
|
||||||
config.vpn_key_reuse_limit,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let ack_control = AcknowledgementController::new(
|
let ack_control = AcknowledgementController::new(
|
||||||
@@ -174,7 +145,7 @@ impl RealMessagesController<OsRng> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn run(&mut self, vpn_mode: bool) {
|
pub(super) async fn run(&mut self) {
|
||||||
let mut out_queue_control = self.out_queue_control.take().unwrap();
|
let mut out_queue_control = self.out_queue_control.take().unwrap();
|
||||||
let mut ack_control = self.ack_control.take().unwrap();
|
let mut ack_control = self.ack_control.take().unwrap();
|
||||||
|
|
||||||
@@ -182,7 +153,7 @@ impl RealMessagesController<OsRng> {
|
|||||||
// the task to ever finish. This will of course change once we introduce
|
// the task to ever finish. This will of course change once we introduce
|
||||||
// graceful shutdowns.
|
// graceful shutdowns.
|
||||||
let out_queue_control_fut = tokio::spawn(async move {
|
let out_queue_control_fut = tokio::spawn(async move {
|
||||||
out_queue_control.run_out_queue_control(vpn_mode).await;
|
out_queue_control.run_out_queue_control().await;
|
||||||
error!("The out queue controller has finished execution!");
|
error!("The out queue controller has finished execution!");
|
||||||
out_queue_control
|
out_queue_control
|
||||||
});
|
});
|
||||||
@@ -201,9 +172,9 @@ impl RealMessagesController<OsRng> {
|
|||||||
|
|
||||||
// &Handle is only passed for consistency sake with other client modules, but I think
|
// &Handle is only passed for consistency sake with other client modules, but I think
|
||||||
// when we get to refactoring, we should apply gateway approach and make it implicit
|
// when we get to refactoring, we should apply gateway approach and make it implicit
|
||||||
pub fn start(mut self, handle: &Handle, vpn_mode: bool) -> JoinHandle<Self> {
|
pub fn start(mut self, handle: &Handle) -> JoinHandle<Self> {
|
||||||
handle.spawn(async move {
|
handle.spawn(async move {
|
||||||
self.run(vpn_mode).await;
|
self.run().await;
|
||||||
self
|
self
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::mix_traffic::BatchMixMessageSender;
|
use crate::client::mix_traffic::BatchMixMessageSender;
|
||||||
use crate::client::real_messages_control::acknowledgement_control::SentPacketNotificationSender;
|
use crate::client::real_messages_control::acknowledgement_control::SentPacketNotificationSender;
|
||||||
@@ -260,15 +249,6 @@ where
|
|||||||
tokio::task::yield_now().await;
|
tokio::task::yield_now().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_batch_received(&mut self, real_messages: Vec<RealMessage>) {
|
|
||||||
let mut mix_packets = Vec::with_capacity(real_messages.len());
|
|
||||||
for real_message in real_messages.into_iter() {
|
|
||||||
self.sent_notify(real_message.fragment_id);
|
|
||||||
mix_packets.push(real_message.mix_packet);
|
|
||||||
}
|
|
||||||
self.mix_tx.unbounded_send(mix_packets).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send messages at certain rate and if no real traffic is available, send cover message.
|
// Send messages at certain rate and if no real traffic is available, send cover message.
|
||||||
async fn run_normal_out_queue(&mut self) {
|
async fn run_normal_out_queue(&mut self) {
|
||||||
// we should set initial delay only when we actually start the stream
|
// we should set initial delay only when we actually start the stream
|
||||||
@@ -282,20 +262,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send real message as soon as it's available and don't inject ANY cover traffic.
|
pub(crate) async fn run_out_queue_control(&mut self) {
|
||||||
async fn run_vpn_out_queue(&mut self) {
|
debug!("Starting out queue controller...");
|
||||||
while let Some(next_messages) = self.real_receiver.next().await {
|
self.run_normal_out_queue().await
|
||||||
self.on_batch_received(next_messages).await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn run_out_queue_control(&mut self, vpn_mode: bool) {
|
|
||||||
if vpn_mode {
|
|
||||||
debug!("Starting out queue controller in vpn mode...");
|
|
||||||
self.run_vpn_out_queue().await
|
|
||||||
} else {
|
|
||||||
debug!("Starting out queue controller...");
|
|
||||||
self.run_normal_out_queue().await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::reply_key_storage::ReplyKeyStorage;
|
use crate::client::reply_key_storage::ReplyKeyStorage;
|
||||||
use crypto::asymmetric::encryption;
|
use crypto::asymmetric::encryption;
|
||||||
@@ -196,7 +185,7 @@ impl ReceivedMessagesBuffer {
|
|||||||
let zero_iv = stream_cipher::zero_iv::<ReplySurbEncryptionAlgorithm>();
|
let zero_iv = stream_cipher::zero_iv::<ReplySurbEncryptionAlgorithm>();
|
||||||
|
|
||||||
let mut reply_msg = stream_cipher::decrypt::<ReplySurbEncryptionAlgorithm>(
|
let mut reply_msg = stream_cipher::decrypt::<ReplySurbEncryptionAlgorithm>(
|
||||||
&reply_key.inner(),
|
reply_key.inner(),
|
||||||
&zero_iv,
|
&zero_iv,
|
||||||
reply_ciphertext,
|
reply_ciphertext,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::anonymous_replies::{
|
use nymsphinx::anonymous_replies::{
|
||||||
@@ -29,7 +18,7 @@ pub enum ReplyKeyStorageError {
|
|||||||
/// Permanent storage for keys in all sent [`ReplySURB`]
|
/// Permanent storage for keys in all sent [`ReplySURB`]
|
||||||
///
|
///
|
||||||
/// Each sent out [`ReplySURB`] has a new key associated with it that is going to be used for
|
/// Each sent out [`ReplySURB`] has a new key associated with it that is going to be used for
|
||||||
/// payload encryption. In order to decrypt whatever reply we receive, we need to know which
|
/// payload encryption. In order to -decrypt whatever reply we receive, we need to know which
|
||||||
/// key to use for that purpose. We do it based on received `H(t)` which has to be included
|
/// key to use for that purpose. We do it based on received `H(t)` which has to be included
|
||||||
/// with each reply.
|
/// with each reply.
|
||||||
/// Moreover, there is no restriction when the [`ReplySURB`] might get used so we need to
|
/// Moreover, there is no restriction when the [`ReplySURB`] might get used so we need to
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::params::DEFAULT_NUM_MIX_HOPS;
|
use nymsphinx::params::DEFAULT_NUM_MIX_HOPS;
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::thread_rng;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time;
|
use std::time;
|
||||||
@@ -23,6 +14,7 @@ use tokio::runtime::Handle;
|
|||||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use topology::{nym_topology_from_bonds, NymTopology};
|
use topology::{nym_topology_from_bonds, NymTopology};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
// I'm extremely curious why compiler NEVER complained about lack of Debug here before
|
// I'm extremely curious why compiler NEVER complained about lack of Debug here before
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -71,9 +63,9 @@ impl<'a> TopologyReadPermit<'a> {
|
|||||||
Some(topology_ref) => {
|
Some(topology_ref) => {
|
||||||
// see if it's possible to route the packet to both gateways
|
// see if it's possible to route the packet to both gateways
|
||||||
if !topology_ref.can_construct_path_through(DEFAULT_NUM_MIX_HOPS)
|
if !topology_ref.can_construct_path_through(DEFAULT_NUM_MIX_HOPS)
|
||||||
|| !topology_ref.gateway_exists(&ack_recipient.gateway())
|
|| !topology_ref.gateway_exists(ack_recipient.gateway())
|
||||||
|| if let Some(packet_recipient) = packet_recipient {
|
|| if let Some(packet_recipient) = packet_recipient {
|
||||||
!topology_ref.gateway_exists(&packet_recipient.gateway())
|
!topology_ref.gateway_exists(packet_recipient.gateway())
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -115,7 +107,7 @@ impl TopologyAccessor {
|
|||||||
self.inner.read().await.into()
|
self.inner.read().await.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_global_topology(&mut self, new_topology: Option<NymTopology>) {
|
async fn update_global_topology(&self, new_topology: Option<NymTopology>) {
|
||||||
self.inner.write().await.update(new_topology);
|
self.inner.write().await.update(new_topology);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,54 +128,128 @@ impl Default for TopologyAccessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct TopologyRefresherConfig {
|
pub struct TopologyRefresherConfig {
|
||||||
available_validators: Vec<String>,
|
validator_api_urls: Vec<Url>,
|
||||||
mixnet_contract_address: String,
|
|
||||||
refresh_rate: time::Duration,
|
refresh_rate: time::Duration,
|
||||||
|
client_version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TopologyRefresherConfig {
|
impl TopologyRefresherConfig {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
available_validators: Vec<String>,
|
validator_api_urls: Vec<Url>,
|
||||||
mixnet_contract_address: String,
|
|
||||||
refresh_rate: time::Duration,
|
refresh_rate: time::Duration,
|
||||||
|
client_version: String,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
TopologyRefresherConfig {
|
TopologyRefresherConfig {
|
||||||
available_validators,
|
validator_api_urls,
|
||||||
mixnet_contract_address,
|
|
||||||
refresh_rate,
|
refresh_rate,
|
||||||
|
client_version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TopologyRefresher {
|
pub struct TopologyRefresher {
|
||||||
validator_client: validator_client::Client,
|
validator_client: validator_client::ApiClient,
|
||||||
|
client_version: String,
|
||||||
|
|
||||||
|
validator_api_urls: Vec<Url>,
|
||||||
topology_accessor: TopologyAccessor,
|
topology_accessor: TopologyAccessor,
|
||||||
refresh_rate: Duration,
|
refresh_rate: Duration,
|
||||||
|
|
||||||
|
currently_used_api: usize,
|
||||||
was_latest_valid: bool,
|
was_latest_valid: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TopologyRefresher {
|
impl TopologyRefresher {
|
||||||
pub fn new(cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
|
pub fn new(mut cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
|
||||||
let validator_client_config =
|
cfg.validator_api_urls.shuffle(&mut thread_rng());
|
||||||
validator_client::Config::new(cfg.available_validators, cfg.mixnet_contract_address);
|
|
||||||
let validator_client = validator_client::Client::new(validator_client_config);
|
|
||||||
|
|
||||||
TopologyRefresher {
|
TopologyRefresher {
|
||||||
validator_client,
|
validator_client: validator_client::ApiClient::new(cfg.validator_api_urls[0].clone()),
|
||||||
|
client_version: cfg.client_version,
|
||||||
|
validator_api_urls: cfg.validator_api_urls,
|
||||||
topology_accessor,
|
topology_accessor,
|
||||||
refresh_rate: cfg.refresh_rate,
|
refresh_rate: cfg.refresh_rate,
|
||||||
|
currently_used_api: 0,
|
||||||
was_latest_valid: true,
|
was_latest_valid: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_current_compatible_topology(&mut self) -> Option<NymTopology> {
|
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");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.currently_used_api = (self.currently_used_api + 1) % self.validator_api_urls.len();
|
||||||
|
self.validator_client
|
||||||
|
.change_validator_api(self.validator_api_urls[self.currently_used_api].clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies whether nodes a reasonably distributed among all mix layers.
|
||||||
|
///
|
||||||
|
/// In ideal world we would have 33% nodes on layer 1, 33% on layer 2 and 33% on layer 3.
|
||||||
|
/// However, this is a rather unrealistic expectation, instead we check whether there exists
|
||||||
|
/// a layer with more than 66% of nodes or with fewer than 15% and if so, we trigger a failure.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `topology`: active topology constructed from validator api data
|
||||||
|
/// * `mixnodes_count`: total number of active mixnodes
|
||||||
|
fn check_layer_distribution(
|
||||||
|
&self,
|
||||||
|
active_topology: &NymTopology,
|
||||||
|
mixnodes_count: usize,
|
||||||
|
) -> bool {
|
||||||
|
let mixes = active_topology.mixes();
|
||||||
|
if active_topology.gateways().is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trivial check to see if have at least a single node on each layer (regardless of active set size)
|
||||||
|
if mixes.get(&1).is_none() || mixes.get(&2).is_none() || mixes.get(&3).is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let upper_bound = (mixnodes_count as f32 * 0.66) as usize;
|
||||||
|
let lower_bound = (mixnodes_count as f32 * 0.15) as usize;
|
||||||
|
|
||||||
|
let layer1 = mixes.get(&1).unwrap().len();
|
||||||
|
let layer2 = mixes.get(&2).unwrap().len();
|
||||||
|
let layer3 = mixes.get(&3).unwrap().len();
|
||||||
|
|
||||||
|
if layer1 < lower_bound || layer1 > upper_bound {
|
||||||
|
warn!(
|
||||||
|
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||||
|
mixnodes_count, layer1, layer2, layer3
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if layer2 < lower_bound || layer2 > upper_bound {
|
||||||
|
warn!(
|
||||||
|
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||||
|
mixnodes_count, layer1, layer2, layer3
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if layer3 < lower_bound || layer3 > upper_bound {
|
||||||
|
warn!(
|
||||||
|
"nodes: {}, layer1: {}, layer2: {}, layer3: {}",
|
||||||
|
mixnodes_count, layer1, layer2, layer3
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_current_compatible_topology(&self) -> Option<NymTopology> {
|
||||||
// TODO: optimization for the future:
|
// TODO: optimization for the future:
|
||||||
// only refresh mixnodes on timer and refresh gateways only when
|
// only refresh mixnodes on timer and refresh gateways only when
|
||||||
// we have to send to a new, unknown, gateway
|
// we have to send to a new, unknown, gateway
|
||||||
|
|
||||||
let mixnodes = match self.validator_client.get_mix_nodes().await {
|
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("failed to get network mixnodes - {}", err);
|
error!("failed to get network mixnodes - {}", err);
|
||||||
return None;
|
return None;
|
||||||
@@ -191,7 +257,7 @@ impl TopologyRefresher {
|
|||||||
Ok(mixes) => mixes,
|
Ok(mixes) => mixes,
|
||||||
};
|
};
|
||||||
|
|
||||||
let gateways = match self.validator_client.get_gateways().await {
|
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("failed to get network gateways - {}", err);
|
error!("failed to get network gateways - {}", err);
|
||||||
return None;
|
return None;
|
||||||
@@ -199,17 +265,26 @@ impl TopologyRefresher {
|
|||||||
Ok(gateways) => gateways,
|
Ok(gateways) => gateways,
|
||||||
};
|
};
|
||||||
|
|
||||||
let topology = nym_topology_from_bonds(mixnodes, gateways);
|
let mixnodes_count = mixnodes.len();
|
||||||
|
let topology =
|
||||||
|
nym_topology_from_bonds(mixnodes, gateways).filter_system_version(&self.client_version);
|
||||||
|
|
||||||
// TODO: I didn't want to change it now, but the expected system version should rather be put in config
|
if !self.check_layer_distribution(&topology, mixnodes_count) {
|
||||||
// rather than pulled from package version of `client_core`
|
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used.");
|
||||||
Some(topology.filter_system_version(env!("CARGO_PKG_VERSION")))
|
None
|
||||||
|
} else {
|
||||||
|
Some(topology)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn refresh(&mut self) {
|
pub async fn refresh(&mut self) {
|
||||||
trace!("Refreshing the topology");
|
trace!("Refreshing the topology");
|
||||||
let new_topology = self.get_current_compatible_topology().await;
|
let new_topology = self.get_current_compatible_topology().await;
|
||||||
|
|
||||||
|
if new_topology.is_none() {
|
||||||
|
self.use_next_validator_api();
|
||||||
|
}
|
||||||
|
|
||||||
if new_topology.is_none() && self.was_latest_valid {
|
if new_topology.is_none() && self.was_latest_valid {
|
||||||
// if we failed to grab this topology, but the one before it was alright, let's assume
|
// if we failed to grab this topology, but the one before it was alright, let's assume
|
||||||
// validator had a tiny hiccup and use the old data
|
// validator had a tiny hiccup and use the old data
|
||||||
|
|||||||
@@ -1,35 +1,18 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use config::{deserialize_duration, deserialize_validators, NymConfig};
|
use config::defaults::*;
|
||||||
|
use config::NymConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
pub mod persistence;
|
pub mod persistence;
|
||||||
|
|
||||||
pub const MISSING_VALUE: &str = "MISSING VALUE";
|
pub const MISSING_VALUE: &str = "MISSING VALUE";
|
||||||
|
|
||||||
// 'CLIENT'
|
|
||||||
pub const DEFAULT_VALIDATOR_REST_ENDPOINTS: &[&str] = &[
|
|
||||||
"http://testnet-finney-validator.nymtech.net:1317",
|
|
||||||
"http://testnet-finney-validator2.nymtech.net:1317",
|
|
||||||
"http://mixnet.club:1317",
|
|
||||||
];
|
|
||||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "hal1k0jntykt7e4g3y88ltc60czgjuqdy4c9c6gv94";
|
|
||||||
|
|
||||||
// 'DEBUG'
|
// 'DEBUG'
|
||||||
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
||||||
|
|
||||||
@@ -39,27 +22,15 @@ const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20)
|
|||||||
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
|
const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50);
|
||||||
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
|
const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min
|
||||||
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
|
const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000);
|
||||||
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_millis(1_500);
|
// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause
|
||||||
const DEFAULT_VPN_KEY_REUSE_LIMIT: usize = 1000;
|
// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the
|
||||||
|
// bandwidth bridging protocol, we can come back to a smaller timeout value
|
||||||
const ZERO_DELAY: Duration = Duration::from_nanos(0);
|
const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
||||||
|
|
||||||
// helper function to get default validators as a Vec<String>
|
|
||||||
pub fn default_validator_rest_endpoints() -> Vec<String> {
|
|
||||||
DEFAULT_VALIDATOR_REST_ENDPOINTS
|
|
||||||
.iter()
|
|
||||||
.map(|&endpoint| endpoint.to_string())
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn missing_string_value() -> String {
|
pub fn missing_string_value() -> String {
|
||||||
MISSING_VALUE.to_string()
|
MISSING_VALUE.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn missing_vec_string_value() -> Vec<String> {
|
|
||||||
vec![missing_string_value()]
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Config<T> {
|
pub struct Config<T> {
|
||||||
@@ -132,6 +103,17 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self::Client::<T>::default_reply_encryption_key_store_path(&id);
|
self::Client::<T>::default_reply_encryption_key_store_path(&id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
if self
|
||||||
|
.client
|
||||||
|
.backup_bandwidth_token_keys_dir
|
||||||
|
.as_os_str()
|
||||||
|
.is_empty()
|
||||||
|
{
|
||||||
|
self.client.backup_bandwidth_token_keys_dir =
|
||||||
|
self::Client::<T>::default_backup_bandwidth_token_keys_dir(&id);
|
||||||
|
}
|
||||||
|
|
||||||
self.client.id = id;
|
self.client.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,12 +125,18 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.gateway_listener = gateway_listener.into();
|
self.client.gateway_listener = gateway_listener.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_custom_validators(&mut self, validators: Vec<String>) {
|
#[cfg(not(feature = "coconut"))]
|
||||||
self.client.validator_rest_urls = validators;
|
pub fn with_eth_private_key<S: Into<String>>(&mut self, eth_private_key: S) {
|
||||||
|
self.client.eth_private_key = eth_private_key.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_mixnet_contract<S: Into<String>>(&mut self, contract_address: S) {
|
#[cfg(not(feature = "coconut"))]
|
||||||
self.client.mixnet_contract_address = contract_address.into();
|
pub fn with_eth_endpoint<S: Into<String>>(&mut self, eth_endpoint: S) {
|
||||||
|
self.client.eth_endpoint = eth_endpoint.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_custom_validator_apis(&mut self, validator_api_urls: Vec<Url>) {
|
||||||
|
self.client.validator_api_urls = validator_api_urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_high_default_traffic_volume(&mut self) {
|
pub fn set_high_default_traffic_volume(&mut self) {
|
||||||
@@ -157,14 +145,6 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.debug.message_sending_average_delay = Duration::from_millis(4); // 250 "real" messages / s
|
self.debug.message_sending_average_delay = Duration::from_millis(4); // 250 "real" messages / s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_vpn_mode(&mut self, vpn_mode: bool) {
|
|
||||||
self.client.vpn_mode = vpn_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_vpn_key_reuse_limit(&mut self, reuse_limit: usize) {
|
|
||||||
self.debug.vpn_key_reuse_limit = Some(reuse_limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_custom_version(&mut self, version: &str) {
|
pub fn set_custom_version(&mut self, version: &str) {
|
||||||
self.client.version = version.to_string();
|
self.client.version = version.to_string();
|
||||||
}
|
}
|
||||||
@@ -205,12 +185,8 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.ack_key_file.clone()
|
self.client.ack_key_file.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_validator_rest_endpoints(&self) -> Vec<String> {
|
pub fn get_validator_api_endpoints(&self) -> Vec<Url> {
|
||||||
self.client.validator_rest_urls.clone()
|
self.client.validator_api_urls.clone()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_validator_mixnet_contract_address(&self) -> String {
|
|
||||||
self.client.mixnet_contract_address.clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gateway_id(&self) -> String {
|
pub fn get_gateway_id(&self) -> String {
|
||||||
@@ -221,21 +197,28 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.gateway_listener.clone()
|
self.client.gateway_listener.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn get_backup_bandwidth_token_keys_dir(&self) -> PathBuf {
|
||||||
|
self.client.backup_bandwidth_token_keys_dir.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn get_eth_endpoint(&self) -> String {
|
||||||
|
self.client.eth_endpoint.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
pub fn get_eth_private_key(&self) -> String {
|
||||||
|
self.client.eth_private_key.clone()
|
||||||
|
}
|
||||||
|
|
||||||
// Debug getters
|
// Debug getters
|
||||||
pub fn get_average_packet_delay(&self) -> Duration {
|
pub fn get_average_packet_delay(&self) -> Duration {
|
||||||
if self.client.vpn_mode {
|
self.debug.average_packet_delay
|
||||||
ZERO_DELAY
|
|
||||||
} else {
|
|
||||||
self.debug.average_packet_delay
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_average_ack_delay(&self) -> Duration {
|
pub fn get_average_ack_delay(&self) -> Duration {
|
||||||
if self.client.vpn_mode {
|
self.debug.average_ack_delay
|
||||||
ZERO_DELAY
|
|
||||||
} else {
|
|
||||||
self.debug.average_ack_delay
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_ack_wait_multiplier(&self) -> f64 {
|
pub fn get_ack_wait_multiplier(&self) -> f64 {
|
||||||
@@ -251,11 +234,7 @@ impl<T: NymConfig> Config<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_message_sending_average_delay(&self) -> Duration {
|
pub fn get_message_sending_average_delay(&self) -> Duration {
|
||||||
if self.client.vpn_mode {
|
self.debug.message_sending_average_delay
|
||||||
ZERO_DELAY
|
|
||||||
} else {
|
|
||||||
self.debug.message_sending_average_delay
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gateway_response_timeout(&self) -> Duration {
|
pub fn get_gateway_response_timeout(&self) -> Duration {
|
||||||
@@ -270,21 +249,6 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.debug.topology_resolution_timeout
|
self.debug.topology_resolution_timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_vpn_mode(&self) -> bool {
|
|
||||||
self.client.vpn_mode
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_vpn_key_reuse_limit(&self) -> Option<usize> {
|
|
||||||
match self.get_vpn_mode() {
|
|
||||||
false => None,
|
|
||||||
true => Some(
|
|
||||||
self.debug
|
|
||||||
.vpn_key_reuse_limit
|
|
||||||
.unwrap_or(DEFAULT_VPN_KEY_REUSE_LIMIT),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_version(&self) -> &str {
|
pub fn get_version(&self) -> &str {
|
||||||
&self.client.version
|
&self.client.version
|
||||||
}
|
}
|
||||||
@@ -309,23 +273,8 @@ pub struct Client<T> {
|
|||||||
/// ID specifies the human readable ID of this particular client.
|
/// ID specifies the human readable ID of this particular client.
|
||||||
id: String,
|
id: String,
|
||||||
|
|
||||||
/// URL to the validator server for obtaining network topology.
|
/// Addresses to APIs running on validator from which the client gets the view of the network.
|
||||||
#[serde(
|
validator_api_urls: Vec<Url>,
|
||||||
deserialize_with = "deserialize_validators",
|
|
||||||
default = "missing_vec_string_value",
|
|
||||||
alias = "validator_rest_url"
|
|
||||||
)]
|
|
||||||
validator_rest_urls: Vec<String>,
|
|
||||||
|
|
||||||
/// Address of the validator contract managing the network.
|
|
||||||
#[serde(default = "missing_string_value")]
|
|
||||||
mixnet_contract_address: String,
|
|
||||||
|
|
||||||
/// Special mode of the system such that all messages are sent as soon as they are received
|
|
||||||
/// and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
|
||||||
/// 'Debug' values will have no effect.
|
|
||||||
#[serde(default)]
|
|
||||||
vpn_mode: bool,
|
|
||||||
|
|
||||||
/// Path to file containing private identity key.
|
/// Path to file containing private identity key.
|
||||||
private_identity_key_file: PathBuf,
|
private_identity_key_file: PathBuf,
|
||||||
@@ -358,6 +307,20 @@ pub struct Client<T> {
|
|||||||
/// Address of the gateway listener to which all client requests should be sent.
|
/// Address of the gateway listener to which all client requests should be sent.
|
||||||
gateway_listener: String,
|
gateway_listener: String,
|
||||||
|
|
||||||
|
/// Path to directory containing public/private keys used for bandwidth token purchase.
|
||||||
|
/// Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
|
||||||
|
/// The public key is the name of the file, while the private key is the content.
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
backup_bandwidth_token_keys_dir: PathBuf,
|
||||||
|
|
||||||
|
/// Ethereum private key.
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_private_key: String,
|
||||||
|
|
||||||
|
/// Address to an Ethereum full node.
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_endpoint: String,
|
||||||
|
|
||||||
/// nym_home_directory specifies absolute path to the home nym Clients directory.
|
/// nym_home_directory specifies absolute path to the home nym Clients directory.
|
||||||
/// It is expected to use default value and hence .toml file should not redefine this field.
|
/// It is expected to use default value and hence .toml file should not redefine this field.
|
||||||
nym_root_directory: PathBuf,
|
nym_root_directory: PathBuf,
|
||||||
@@ -372,9 +335,7 @@ impl<T: NymConfig> Default for Client<T> {
|
|||||||
Client {
|
Client {
|
||||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||||
id: "".to_string(),
|
id: "".to_string(),
|
||||||
validator_rest_urls: default_validator_rest_endpoints(),
|
validator_api_urls: default_api_endpoints(),
|
||||||
mixnet_contract_address: DEFAULT_MIXNET_CONTRACT_ADDRESS.to_string(),
|
|
||||||
vpn_mode: false,
|
|
||||||
private_identity_key_file: Default::default(),
|
private_identity_key_file: Default::default(),
|
||||||
public_identity_key_file: Default::default(),
|
public_identity_key_file: Default::default(),
|
||||||
private_encryption_key_file: Default::default(),
|
private_encryption_key_file: Default::default(),
|
||||||
@@ -384,6 +345,12 @@ impl<T: NymConfig> Default for Client<T> {
|
|||||||
reply_encryption_key_store_path: Default::default(),
|
reply_encryption_key_store_path: Default::default(),
|
||||||
gateway_id: "".to_string(),
|
gateway_id: "".to_string(),
|
||||||
gateway_listener: "".to_string(),
|
gateway_listener: "".to_string(),
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
backup_bandwidth_token_keys_dir: Default::default(),
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_private_key: "".to_string(),
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
eth_endpoint: "".to_string(),
|
||||||
nym_root_directory: T::default_root_directory(),
|
nym_root_directory: T::default_root_directory(),
|
||||||
super_struct: Default::default(),
|
super_struct: Default::default(),
|
||||||
}
|
}
|
||||||
@@ -392,44 +359,43 @@ impl<T: NymConfig> Default for Client<T> {
|
|||||||
|
|
||||||
impl<T: NymConfig> Client<T> {
|
impl<T: NymConfig> Client<T> {
|
||||||
fn default_private_identity_key_file(id: &str) -> PathBuf {
|
fn default_private_identity_key_file(id: &str) -> PathBuf {
|
||||||
T::default_data_directory(id).join("private_identity.pem")
|
T::default_data_directory(Some(id)).join("private_identity.pem")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_public_identity_key_file(id: &str) -> PathBuf {
|
fn default_public_identity_key_file(id: &str) -> PathBuf {
|
||||||
T::default_data_directory(id).join("public_identity.pem")
|
T::default_data_directory(Some(id)).join("public_identity.pem")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_private_encryption_key_file(id: &str) -> PathBuf {
|
fn default_private_encryption_key_file(id: &str) -> PathBuf {
|
||||||
T::default_data_directory(id).join("private_encryption.pem")
|
T::default_data_directory(Some(id)).join("private_encryption.pem")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_public_encryption_key_file(id: &str) -> PathBuf {
|
fn default_public_encryption_key_file(id: &str) -> PathBuf {
|
||||||
T::default_data_directory(id).join("public_encryption.pem")
|
T::default_data_directory(Some(id)).join("public_encryption.pem")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_gateway_shared_key_file(id: &str) -> PathBuf {
|
fn default_gateway_shared_key_file(id: &str) -> PathBuf {
|
||||||
T::default_data_directory(id).join("gateway_shared.pem")
|
T::default_data_directory(Some(id)).join("gateway_shared.pem")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_ack_key_file(id: &str) -> PathBuf {
|
fn default_ack_key_file(id: &str) -> PathBuf {
|
||||||
T::default_data_directory(id).join("ack_key.pem")
|
T::default_data_directory(Some(id)).join("ack_key.pem")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_reply_encryption_key_store_path(id: &str) -> PathBuf {
|
fn default_reply_encryption_key_store_path(id: &str) -> PathBuf {
|
||||||
T::default_data_directory(id).join("reply_key_store")
|
T::default_data_directory(Some(id)).join("reply_key_store")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
fn default_backup_bandwidth_token_keys_dir(id: &str) -> PathBuf {
|
||||||
|
T::default_data_directory(Some(id)).join("backup_bandwidth_token_keys")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Logging {}
|
pub struct Logging {}
|
||||||
|
|
||||||
impl Default for Logging {
|
|
||||||
fn default() -> Self {
|
|
||||||
Logging {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||||
#[serde(default, deny_unknown_fields)]
|
#[serde(default, deny_unknown_fields)]
|
||||||
pub struct Debug {
|
pub struct Debug {
|
||||||
@@ -437,20 +403,14 @@ pub struct Debug {
|
|||||||
/// sent packet is going to be delayed at any given mix node.
|
/// sent packet is going to be delayed at any given mix node.
|
||||||
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
/// So for a packet going through three mix nodes, on average, it will take three times this value
|
||||||
/// until the packet reaches its destination.
|
/// until the packet reaches its destination.
|
||||||
#[serde(
|
#[serde(with = "humantime_serde")]
|
||||||
deserialize_with = "deserialize_duration",
|
|
||||||
serialize_with = "humantime_serde::serialize"
|
|
||||||
)]
|
|
||||||
average_packet_delay: Duration,
|
average_packet_delay: Duration,
|
||||||
|
|
||||||
/// The parameter of Poisson distribution determining how long, on average,
|
/// The parameter of Poisson distribution determining how long, on average,
|
||||||
/// sent acknowledgement is going to be delayed at any given mix node.
|
/// sent acknowledgement is going to be delayed at any given mix node.
|
||||||
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
/// So for an ack going through three mix nodes, on average, it will take three times this value
|
||||||
/// until the packet reaches its destination.
|
/// until the packet reaches its destination.
|
||||||
#[serde(
|
#[serde(with = "humantime_serde")]
|
||||||
deserialize_with = "deserialize_duration",
|
|
||||||
serialize_with = "humantime_serde::serialize"
|
|
||||||
)]
|
|
||||||
average_ack_delay: Duration,
|
average_ack_delay: Duration,
|
||||||
|
|
||||||
/// Value multiplied with the expected round trip time of an acknowledgement packet before
|
/// Value multiplied with the expected round trip time of an acknowledgement packet before
|
||||||
@@ -461,58 +421,36 @@ pub struct Debug {
|
|||||||
/// Value added to the expected round trip time of an acknowledgement packet before
|
/// Value added to the expected round trip time of an acknowledgement packet before
|
||||||
/// it is assumed it was lost and retransmission of the data packet happens.
|
/// it is assumed it was lost and retransmission of the data packet happens.
|
||||||
/// In an ideal network with 0 latency, this value would have been 0.
|
/// In an ideal network with 0 latency, this value would have been 0.
|
||||||
#[serde(
|
#[serde(with = "humantime_serde")]
|
||||||
deserialize_with = "deserialize_duration",
|
|
||||||
serialize_with = "humantime_serde::serialize"
|
|
||||||
)]
|
|
||||||
ack_wait_addition: Duration,
|
ack_wait_addition: Duration,
|
||||||
|
|
||||||
/// The parameter of Poisson distribution determining how long, on average,
|
/// The parameter of Poisson distribution determining how long, on average,
|
||||||
/// it is going to take for another loop cover traffic message to be sent.
|
/// it is going to take for another loop cover traffic message to be sent.
|
||||||
#[serde(
|
#[serde(with = "humantime_serde")]
|
||||||
deserialize_with = "deserialize_duration",
|
|
||||||
serialize_with = "humantime_serde::serialize"
|
|
||||||
)]
|
|
||||||
loop_cover_traffic_average_delay: Duration,
|
loop_cover_traffic_average_delay: Duration,
|
||||||
|
|
||||||
/// The parameter of Poisson distribution determining how long, on average,
|
/// The parameter of Poisson distribution determining how long, on average,
|
||||||
/// it is going to take another 'real traffic stream' message to be sent.
|
/// it is going to take another 'real traffic stream' message to be sent.
|
||||||
/// If no real packets are available and cover traffic is enabled,
|
/// If no real packets are available and cover traffic is enabled,
|
||||||
/// a loop cover message is sent instead in order to preserve the rate.
|
/// a loop cover message is sent instead in order to preserve the rate.
|
||||||
#[serde(
|
#[serde(with = "humantime_serde")]
|
||||||
deserialize_with = "deserialize_duration",
|
|
||||||
serialize_with = "humantime_serde::serialize"
|
|
||||||
)]
|
|
||||||
message_sending_average_delay: Duration,
|
message_sending_average_delay: Duration,
|
||||||
|
|
||||||
/// How long we're willing to wait for a response to a message sent to the gateway,
|
/// How long we're willing to wait for a response to a message sent to the gateway,
|
||||||
/// before giving up on it.
|
/// before giving up on it.
|
||||||
#[serde(
|
#[serde(with = "humantime_serde")]
|
||||||
deserialize_with = "deserialize_duration",
|
|
||||||
serialize_with = "humantime_serde::serialize"
|
|
||||||
)]
|
|
||||||
gateway_response_timeout: Duration,
|
gateway_response_timeout: Duration,
|
||||||
|
|
||||||
/// The uniform delay every which clients are querying the directory server
|
/// The uniform delay every which clients are querying the directory server
|
||||||
/// to try to obtain a compatible network topology to send sphinx packets through.
|
/// to try to obtain a compatible network topology to send sphinx packets through.
|
||||||
#[serde(
|
#[serde(with = "humantime_serde")]
|
||||||
deserialize_with = "deserialize_duration",
|
|
||||||
serialize_with = "humantime_serde::serialize"
|
|
||||||
)]
|
|
||||||
topology_refresh_rate: Duration,
|
topology_refresh_rate: Duration,
|
||||||
|
|
||||||
/// During topology refresh, test packets are sent through every single possible network
|
/// During topology refresh, test packets are sent through every single possible network
|
||||||
/// path. This timeout determines waiting period until it is decided that the packet
|
/// path. This timeout determines waiting period until it is decided that the packet
|
||||||
/// did not reach its destination.
|
/// did not reach its destination.
|
||||||
#[serde(
|
#[serde(with = "humantime_serde")]
|
||||||
deserialize_with = "deserialize_duration",
|
|
||||||
serialize_with = "humantime_serde::serialize"
|
|
||||||
)]
|
|
||||||
topology_resolution_timeout: Duration,
|
topology_resolution_timeout: Duration,
|
||||||
|
|
||||||
/// If the mode of the client is set to VPN it specifies number of packets created with the
|
|
||||||
/// same initial secret until it gets rotated.
|
|
||||||
vpn_key_reuse_limit: Option<usize>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Debug {
|
impl Default for Debug {
|
||||||
@@ -527,7 +465,6 @@ impl Default for Debug {
|
|||||||
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT,
|
||||||
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE,
|
||||||
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT,
|
||||||
vpn_key_reuse_limit: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
|||||||
@@ -1,15 +1,4 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
pub mod key_pathfinder;
|
pub mod key_pathfinder;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "0.10.1"
|
version = "0.11.0"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
rust-version = "1.56"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ futures = "0.3" # bunch of futures stuff, however, now that I think about it, it
|
|||||||
# the AsyncRead, AsyncWrite, Stream, Sink, etc. traits could be used from tokio
|
# the AsyncRead, AsyncWrite, Stream, Sink, etc. traits could be used from tokio
|
||||||
# channels should really be replaced with crossbeam due to that implementation being more efficient
|
# channels should really be replaced with crossbeam due to that implementation being more efficient
|
||||||
# and the single instance of abortable we have should really be refactored anyway
|
# and the single instance of abortable we have should really be refactored anyway
|
||||||
url = "2.1" # I think we should just replace it with String
|
url = "2.2"
|
||||||
|
|
||||||
clap = "2.33.0" # for the command line arguments
|
clap = "2.33.0" # for the command line arguments
|
||||||
dirs = "3.0" # for determining default store directories in config
|
dirs = "3.0" # for determining default store directories in config
|
||||||
@@ -31,6 +32,8 @@ tokio-tungstenite = "0.14" # websocket
|
|||||||
|
|
||||||
## internal
|
## internal
|
||||||
client-core = { path = "../client-core" }
|
client-core = { path = "../client-core" }
|
||||||
|
coconut-interface = { path = "../../common/coconut-interface", optional = true }
|
||||||
|
credentials = { path = "../../common/credentials", optional = true }
|
||||||
config = { path = "../../common/config" }
|
config = { path = "../../common/config" }
|
||||||
crypto = { path = "../../common/crypto" }
|
crypto = { path = "../../common/crypto" }
|
||||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||||
@@ -42,5 +45,8 @@ websocket-requests = { path = "websocket-requests" }
|
|||||||
validator-client = { path = "../../common/client-libs/validator-client" }
|
validator-client = { path = "../../common/client-libs/validator-client" }
|
||||||
version-checker = { path = "../../common/version-checker" }
|
version-checker = { path = "../../common/version-checker" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_json = "1.0" # for the "textsend" example
|
serde_json = "1.0" # for the "textsend" example
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"author": "Dave Hrycyszyn",
|
"author": "Dave Hrycyszyn",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^9.8.0",
|
"autoprefixer": "^10.2.6",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"webpack": "^4.42.1",
|
"webpack": "^4.42.1",
|
||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.11",
|
||||||
|
|||||||
@@ -36,31 +36,42 @@
|
|||||||
},
|
},
|
||||||
"websockets": {
|
"websockets": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5",
|
"sha256:0dd4eb8e0bbf365d6f652711ce21b8fd2b596f873d32aabb0fbb53ec604418cc",
|
||||||
"sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5",
|
"sha256:1d0971cc7251aeff955aa742ec541ee8aaea4bb2ebf0245748fbec62f744a37e",
|
||||||
"sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308",
|
"sha256:1d6b4fddb12ab9adf87b843cd4316c4bd602db8d5efd2fb83147f0458fe85135",
|
||||||
"sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb",
|
"sha256:230a3506df6b5f446fed2398e58dcaafdff12d67fe1397dff196411a9e820d02",
|
||||||
"sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a",
|
"sha256:276d2339ebf0df4f45df453923ebd2270b87900eda5dfd4a6b0cfa15f82111c3",
|
||||||
"sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c",
|
"sha256:2cf04601633a4ec176b9cc3d3e73789c037641001dbfaf7c411f89cd3e04fcaf",
|
||||||
"sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170",
|
"sha256:3ddff38894c7857c476feb3538dd847514379d6dc844961dc99f04b0384b1b1b",
|
||||||
"sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422",
|
"sha256:48c222feb3ced18f3dc61168ca18952a22fb88e5eb8902d2bf1b50faefdc34a2",
|
||||||
"sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8",
|
"sha256:51d04df04ed9d08077d10ccbe21e6805791b78eac49d16d30a1f1fe2e44ba0af",
|
||||||
"sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485",
|
"sha256:597c28f3aa7a09e8c070a86b03107094ee5cdafcc0d55f2f2eac92faac8dc67d",
|
||||||
"sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f",
|
"sha256:5c8f0d82ea2468282e08b0cf5307f3ad022290ed50c45d5cb7767957ca782880",
|
||||||
"sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8",
|
"sha256:7189e51955f9268b2bdd6cc537e0faa06f8fffda7fb386e5922c6391de51b077",
|
||||||
"sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc",
|
"sha256:7df3596838b2a0c07c6f6d67752c53859a54993d4f062689fdf547cb56d0f84f",
|
||||||
"sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779",
|
"sha256:826ccf85d4514609219725ba4a7abd569228c2c9f1968e8be05be366f68291ec",
|
||||||
"sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989",
|
"sha256:836d14eb53b500fd92bd5db2fc5894f7c72b634f9c2a28f546f75967503d8e25",
|
||||||
"sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1",
|
"sha256:85db8090ba94e22d964498a47fdd933b8875a1add6ebc514c7ac8703eb97bbf0",
|
||||||
"sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092",
|
"sha256:85e701a6c316b7067f1e8675c638036a796fe5116783a4c932e7eb8e305a3ffe",
|
||||||
"sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824",
|
"sha256:900589e19200be76dd7cbaa95e9771605b5ce3f62512d039fb3bc5da9014912a",
|
||||||
"sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d",
|
"sha256:9147868bb0cc01e6846606cd65cbf9c58598f187b96d14dd1ca17338b08793bb",
|
||||||
"sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55",
|
"sha256:9e7fdc775fe7403dbd8bc883ba59576a6232eac96dacb56512daacf7af5d618d",
|
||||||
"sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36",
|
"sha256:ab5ee15d3462198c794c49ccd31773d8a2b8c17d622aa184f669d2b98c2f0857",
|
||||||
"sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"
|
"sha256:ad893d889bc700a5835e0a95a3e4f2c39e91577ab232a3dc03c262a0f8fc4b5c",
|
||||||
|
"sha256:b2e71c4670ebe1067fa8632f0d081e47254ee2d3d409de54168b43b0ba9147e0",
|
||||||
|
"sha256:b43b13e5622c5a53ab12f3272e6f42f1ce37cd5b6684b2676cb365403295cd40",
|
||||||
|
"sha256:b4ad84b156cf50529b8ac5cc1638c2cf8680490e3fccb6121316c8c02620a2e4",
|
||||||
|
"sha256:be5fd35e99970518547edc906efab29afd392319f020c3c58b0e1a158e16ed20",
|
||||||
|
"sha256:caa68c95bc1776d3521f81eeb4d5b9438be92514ec2a79fececda814099c8314",
|
||||||
|
"sha256:d144b350045c53c8ff09aa1cfa955012dd32f00c7e0862c199edcabb1a8b32da",
|
||||||
|
"sha256:d2c2d9b24d3c65b5a02cac12cbb4e4194e590314519ed49db2f67ef561c3cf58",
|
||||||
|
"sha256:e9e5fd6dbdf95d99bc03732ded1fc8ef22ebbc05999ac7e0c7bf57fe6e4e5ae2",
|
||||||
|
"sha256:ebf459a1c069f9866d8569439c06193c586e72c9330db1390af7c6a0a32c4afd",
|
||||||
|
"sha256:f31722f1c033c198aa4a39a01905951c00bd1c74f922e8afc1b1c62adbcdd56a",
|
||||||
|
"sha256:f68c352a68e5fdf1e97288d5cec9296664c590c25932a8476224124aaf90dbcd"
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==8.1"
|
"version": "==9.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"develop": {}
|
"develop": {}
|
||||||
|
|||||||
@@ -1,28 +1,16 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::template::config_template;
|
use crate::client::config::template::config_template;
|
||||||
use client_core::config::Config as BaseConfig;
|
use client_core::config::Config as BaseConfig;
|
||||||
pub use client_core::config::MISSING_VALUE;
|
pub use client_core::config::MISSING_VALUE;
|
||||||
|
use config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
mod template;
|
mod template;
|
||||||
|
|
||||||
const DEFAULT_LISTENING_PORT: u16 = 1977;
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, PartialEq, Serialize, Clone, Copy)]
|
#[derive(Debug, Deserialize, PartialEq, Serialize, Clone, Copy)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub enum SocketType {
|
pub enum SocketType {
|
||||||
@@ -128,7 +116,7 @@ impl Default for Socket {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Socket {
|
Socket {
|
||||||
socket_type: SocketType::WebSocket,
|
socket_type: SocketType::WebSocket,
|
||||||
listening_port: DEFAULT_LISTENING_PORT,
|
listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,11 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
pub(crate) fn config_template() -> &'static str {
|
pub(crate) fn config_template() -> &'static str {
|
||||||
// While using normal toml marshalling would have been way simpler with less overhead,
|
// While using normal toml marshalling would have been way simpler with less overhead,
|
||||||
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
||||||
// particular fields.
|
// particular fields.
|
||||||
// Note: any changes to the template must be reflected in the appropriate structs in mod.rs.
|
// Note: any changes to the template must be reflected in the appropriate structs in verloc.
|
||||||
r#"
|
r#"
|
||||||
# This is a TOML config file.
|
# This is a TOML config file.
|
||||||
# For more information, see https://github.com/toml-lang/toml
|
# For more information, see https://github.com/toml-lang/toml
|
||||||
@@ -30,21 +19,13 @@ version = '{{ client.version }}'
|
|||||||
# Human readable ID of this particular client.
|
# Human readable ID of this particular client.
|
||||||
id = '{{ client.id }}'
|
id = '{{ client.id }}'
|
||||||
|
|
||||||
# URL to the validator server for obtaining network topology.
|
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||||
validator_rest_urls = [
|
validator_api_urls = [
|
||||||
{{#each client.validator_rest_urls }}
|
{{#each client.validator_api_urls }}
|
||||||
'{{this}}',
|
'{{this}}',
|
||||||
{{/each}}
|
{{/each}}
|
||||||
]
|
]
|
||||||
|
|
||||||
# Address of the validator contract managing the network.
|
|
||||||
mixnet_contract_address = '{{ client.mixnet_contract_address }}'
|
|
||||||
|
|
||||||
# Special mode of the system such that all messages are sent as soon as they are received
|
|
||||||
# and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
|
||||||
# 'Debug' values will have no effect.
|
|
||||||
vpn_mode = {{ client.vpn_mode }}
|
|
||||||
|
|
||||||
# Path to file containing private identity key.
|
# Path to file containing private identity key.
|
||||||
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
||||||
|
|
||||||
@@ -61,6 +42,17 @@ public_encryption_key_file = '{{ client.public_encryption_key_file }}'
|
|||||||
# sent but not received back.
|
# sent but not received back.
|
||||||
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
||||||
|
|
||||||
|
# Path to directory containing public/private keys used for bandwidth token purchase.
|
||||||
|
# Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
|
||||||
|
# The public key is the name of the file, while the private key is the content.
|
||||||
|
backup_bandwidth_token_keys_dir = '{{ client.backup_bandwidth_token_keys_dir }}'
|
||||||
|
|
||||||
|
# Ethereum private key.
|
||||||
|
eth_private_key = '{{ client.eth_private_key }}'
|
||||||
|
|
||||||
|
# Addess to an Ethereum full node.
|
||||||
|
eth_endpoint = '{{ client.eth_endpoint }}'
|
||||||
|
|
||||||
##### additional client config options #####
|
##### additional client config options #####
|
||||||
|
|
||||||
# ID of the gateway from which the client should be fetching messages.
|
# ID of the gateway from which the client should be fetching messages.
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::{Config, SocketType};
|
use crate::client::config::{Config, SocketType};
|
||||||
use crate::websocket;
|
use crate::websocket;
|
||||||
@@ -43,10 +32,11 @@ use log::*;
|
|||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
use nymsphinx::anonymous_replies::ReplySurb;
|
use nymsphinx::anonymous_replies::ReplySurb;
|
||||||
use nymsphinx::params::PacketMode;
|
|
||||||
use nymsphinx::receiver::ReconstructedMessage;
|
use nymsphinx::receiver::ReconstructedMessage;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
|
use gateway_client::bandwidth::BandwidthController;
|
||||||
|
|
||||||
pub(crate) mod config;
|
pub(crate) mod config;
|
||||||
|
|
||||||
pub struct NymClient {
|
pub struct NymClient {
|
||||||
@@ -130,12 +120,6 @@ impl NymClient {
|
|||||||
input_receiver: InputMessageReceiver,
|
input_receiver: InputMessageReceiver,
|
||||||
mix_sender: BatchMixMessageSender,
|
mix_sender: BatchMixMessageSender,
|
||||||
) {
|
) {
|
||||||
let packet_mode = if self.config.get_base().get_vpn_mode() {
|
|
||||||
PacketMode::Vpn
|
|
||||||
} else {
|
|
||||||
PacketMode::Mix
|
|
||||||
};
|
|
||||||
|
|
||||||
let controller_config = real_messages_control::Config::new(
|
let controller_config = real_messages_control::Config::new(
|
||||||
self.key_manager.ack_key(),
|
self.key_manager.ack_key(),
|
||||||
self.config.get_base().get_ack_wait_multiplier(),
|
self.config.get_base().get_ack_wait_multiplier(),
|
||||||
@@ -144,8 +128,6 @@ impl NymClient {
|
|||||||
self.config.get_base().get_message_sending_average_delay(),
|
self.config.get_base().get_message_sending_average_delay(),
|
||||||
self.config.get_base().get_average_packet_delay(),
|
self.config.get_base().get_average_packet_delay(),
|
||||||
self.as_mix_recipient(),
|
self.as_mix_recipient(),
|
||||||
packet_mode,
|
|
||||||
self.config.get_base().get_vpn_key_reuse_limit(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("Starting real traffic stream...");
|
info!("Starting real traffic stream...");
|
||||||
@@ -162,7 +144,7 @@ impl NymClient {
|
|||||||
topology_accessor,
|
topology_accessor,
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
)
|
)
|
||||||
.start(self.runtime.handle(), self.config.get_base().get_vpn_mode());
|
.start(self.runtime.handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer controlling all messages fetched from provider
|
// buffer controlling all messages fetched from provider
|
||||||
@@ -200,44 +182,53 @@ impl NymClient {
|
|||||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
||||||
.expect("provided gateway id is invalid!");
|
.expect("provided gateway id is invalid!");
|
||||||
|
|
||||||
let mut gateway_client = GatewayClient::new(
|
|
||||||
gateway_address,
|
|
||||||
self.key_manager.identity_keypair(),
|
|
||||||
gateway_identity,
|
|
||||||
Some(self.key_manager.gateway_shared_key()),
|
|
||||||
mixnet_message_sender,
|
|
||||||
ack_sender,
|
|
||||||
self.config.get_base().get_gateway_response_timeout(),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.runtime.block_on(async {
|
self.runtime.block_on(async {
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
let bandwidth_controller = BandwidthController::new(
|
||||||
|
self.config.get_base().get_validator_api_endpoints(),
|
||||||
|
*self.key_manager.identity_keypair().public_key(),
|
||||||
|
);
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let bandwidth_controller = BandwidthController::new(
|
||||||
|
self.config.get_base().get_eth_endpoint(),
|
||||||
|
self.config.get_base().get_eth_private_key(),
|
||||||
|
self.config.get_base().get_backup_bandwidth_token_keys_dir(),
|
||||||
|
)
|
||||||
|
.expect("Could not create bandwidth controller");
|
||||||
|
|
||||||
|
let mut gateway_client = GatewayClient::new(
|
||||||
|
gateway_address,
|
||||||
|
self.key_manager.identity_keypair(),
|
||||||
|
gateway_identity,
|
||||||
|
Some(self.key_manager.gateway_shared_key()),
|
||||||
|
mixnet_message_sender,
|
||||||
|
ack_sender,
|
||||||
|
self.config.get_base().get_gateway_response_timeout(),
|
||||||
|
Some(bandwidth_controller),
|
||||||
|
);
|
||||||
|
|
||||||
gateway_client
|
gateway_client
|
||||||
.authenticate_and_start()
|
.authenticate_and_start()
|
||||||
.await
|
.await
|
||||||
.expect("could not authenticate and start up the gateway connection")
|
.expect("could not authenticate and start up the gateway connection");
|
||||||
});
|
|
||||||
|
|
||||||
gateway_client
|
gateway_client
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// future responsible for periodically polling directory server and updating
|
// future responsible for periodically polling directory server and updating
|
||||||
// the current global view of topology
|
// the current global view of topology
|
||||||
fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
||||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||||
self.config.get_base().get_validator_rest_endpoints(),
|
self.config.get_base().get_validator_api_endpoints(),
|
||||||
self.config
|
|
||||||
.get_base()
|
|
||||||
.get_validator_mixnet_contract_address(),
|
|
||||||
self.config.get_base().get_topology_refresh_rate(),
|
self.config.get_base().get_topology_refresh_rate(),
|
||||||
|
env!("CARGO_PKG_VERSION").to_string(),
|
||||||
);
|
);
|
||||||
let mut topology_refresher =
|
let mut topology_refresher =
|
||||||
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
||||||
// before returning, block entire runtime to refresh the current network view so that any
|
// before returning, block entire runtime to refresh the current network view so that any
|
||||||
// components depending on topology would see a non-empty view
|
// components depending on topology would see a non-empty view
|
||||||
info!(
|
info!("Obtaining initial network topology");
|
||||||
"Obtaining initial network topology from {}",
|
|
||||||
self.config.get_base().get_validator_rest_endpoints()[0]
|
|
||||||
);
|
|
||||||
self.runtime.block_on(topology_refresher.refresh());
|
self.runtime.block_on(topology_refresher.refresh());
|
||||||
|
|
||||||
// TODO: a slightly more graceful termination here
|
// TODO: a slightly more graceful termination here
|
||||||
@@ -390,9 +381,7 @@ impl NymClient {
|
|||||||
sphinx_message_sender.clone(),
|
sphinx_message_sender.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if !self.config.get_base().get_vpn_mode() {
|
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
||||||
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.config.get_socket_type() {
|
match self.config.get_socket_type() {
|
||||||
SocketType::WebSocket => {
|
SocketType::WebSocket => {
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use crate::commands::override_config;
|
use crate::commands::override_config;
|
||||||
@@ -25,13 +14,15 @@ use nymsphinx::addressing::clients::Recipient;
|
|||||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
|
use rand::thread_rng;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use topology::{filter::VersionFilterable, gateway};
|
use topology::{filter::VersionFilterable, gateway};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||||
App::new("init")
|
let app = App::new("init")
|
||||||
.about("Initialise a Nym client. Do this first!")
|
.about("Initialise a Nym client. Do this first!")
|
||||||
.arg(Arg::with_name("id")
|
.arg(Arg::with_name("id")
|
||||||
.long("id")
|
.long("id")
|
||||||
@@ -49,11 +40,6 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.help("Comma separated list of rest endpoints of the validators")
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("mixnet-contract")
|
|
||||||
.long("mixnet-contract")
|
|
||||||
.help("Address of the validator contract managing the network")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("disable-socket")
|
.arg(Arg::with_name("disable-socket")
|
||||||
.long("disable-socket")
|
.long("disable-socket")
|
||||||
.help("Whether to not start the websocket")
|
.help("Whether to not start the websocket")
|
||||||
@@ -64,31 +50,34 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.help("Port for the socket (if applicable) to listen on in all subsequent runs")
|
.help("Port for the socket (if applicable) to listen on in all subsequent runs")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("vpn-mode")
|
|
||||||
.long("vpn-mode")
|
|
||||||
.help("Set the vpn mode of the client")
|
|
||||||
.long_help(
|
|
||||||
r#"
|
|
||||||
Special mode of the system such that all messages are sent as soon as they are received
|
|
||||||
and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
|
||||||
'Debug' values will have no effect.
|
|
||||||
"#
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("fastmode")
|
.arg(Arg::with_name("fastmode")
|
||||||
.long("fastmode")
|
.long("fastmode")
|
||||||
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
||||||
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
||||||
)
|
);
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let app = app
|
||||||
|
.arg(Arg::with_name("eth_endpoint")
|
||||||
|
.long("eth_endpoint")
|
||||||
|
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true))
|
||||||
|
.arg(Arg::with_name("eth_private_key")
|
||||||
|
.long("eth_private_key")
|
||||||
|
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true));
|
||||||
|
|
||||||
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn register_with_gateway(
|
async fn register_with_gateway(
|
||||||
gateway: &gateway::Node,
|
gateway: &gateway::Node,
|
||||||
our_identity: Arc<identity::KeyPair>,
|
our_identity: Arc<identity::KeyPair>,
|
||||||
) -> SharedKeys {
|
) -> Arc<SharedKeys> {
|
||||||
let timeout = Duration::from_millis(1500);
|
let timeout = Duration::from_millis(1500);
|
||||||
let mut gateway_client = GatewayClient::new_init(
|
let mut gateway_client = GatewayClient::new_init(
|
||||||
gateway.client_listener.clone(),
|
gateway.clients_address(),
|
||||||
gateway.identity_key,
|
gateway.identity_key,
|
||||||
our_identity.clone(),
|
our_identity.clone(),
|
||||||
timeout,
|
timeout,
|
||||||
@@ -98,20 +87,21 @@ async fn register_with_gateway(
|
|||||||
.await
|
.await
|
||||||
.expect("failed to establish connection with the gateway!");
|
.expect("failed to establish connection with the gateway!");
|
||||||
gateway_client
|
gateway_client
|
||||||
.register()
|
.perform_initial_authentication()
|
||||||
.await
|
.await
|
||||||
.expect("failed to register with the gateway!")
|
.expect("failed to register with the gateway!")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn gateway_details(
|
async fn gateway_details(
|
||||||
validator_servers: Vec<String>,
|
validator_servers: Vec<Url>,
|
||||||
mixnet_contract: &str,
|
|
||||||
chosen_gateway_id: Option<&str>,
|
chosen_gateway_id: Option<&str>,
|
||||||
) -> gateway::Node {
|
) -> gateway::Node {
|
||||||
let validator_client_config = validator_client::Config::new(validator_servers, mixnet_contract);
|
let validator_api = validator_servers
|
||||||
let mut validator_client = validator_client::Client::new(validator_client_config);
|
.choose(&mut thread_rng())
|
||||||
|
.expect("The list of validator apis is empty");
|
||||||
|
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||||
|
|
||||||
let gateways = validator_client.get_gateways().await.unwrap();
|
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||||
let valid_gateways = gateways
|
let valid_gateways = gateways
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|gateway| gateway.try_into().ok())
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
@@ -177,7 +167,7 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
|
|
||||||
let id = matches.value_of("id").unwrap(); // required for now
|
let id = matches.value_of("id").unwrap(); // required for now
|
||||||
|
|
||||||
let already_init = if Config::default_config_file_path(id).exists() {
|
let already_init = if Config::default_config_file_path(Some(id)).exists() {
|
||||||
println!("Client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
|
println!("Client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@@ -205,8 +195,7 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
|
|
||||||
let registration_fut = async {
|
let registration_fut = async {
|
||||||
let gate_details = gateway_details(
|
let gate_details = gateway_details(
|
||||||
config.get_base().get_validator_rest_endpoints(),
|
config.get_base().get_validator_api_endpoints(),
|
||||||
&config.get_base().get_validator_mixnet_contract_address(),
|
|
||||||
chosen_gateway_id,
|
chosen_gateway_id,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@@ -215,7 +204,7 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
.with_gateway_id(gate_details.identity_key.to_base58_string());
|
.with_gateway_id(gate_details.identity_key.to_base58_string());
|
||||||
let shared_keys =
|
let shared_keys =
|
||||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||||
(shared_keys, gate_details.client_listener)
|
(shared_keys, gate_details.clients_address())
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||||
|
|||||||
@@ -1,27 +1,22 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::{Config, SocketType};
|
use crate::client::config::{Config, SocketType};
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
pub(crate) mod init;
|
pub(crate) mod init;
|
||||||
pub(crate) mod run;
|
pub(crate) mod run;
|
||||||
pub(crate) mod upgrade;
|
pub(crate) mod upgrade;
|
||||||
|
|
||||||
fn parse_validators(raw: &str) -> Vec<String> {
|
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
raw.split(',')
|
raw.split(',')
|
||||||
.map(|raw_validator| raw_validator.trim().into())
|
.map(|raw_validator| {
|
||||||
|
raw_validator
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.expect("one of the provided validator api urls is invalid")
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,11 +24,7 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
|||||||
if let Some(raw_validators) = matches.value_of("validators") {
|
if let Some(raw_validators) = matches.value_of("validators") {
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_custom_validators(parse_validators(raw_validators));
|
.set_custom_validator_apis(parse_validators(raw_validators));
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(contract_address) = matches.value_of("mixnet-contract") {
|
|
||||||
config.get_base_mut().set_mixnet_contract(contract_address)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(gateway_id) = matches.value_of("gateway") {
|
if let Some(gateway_id) = matches.value_of("gateway") {
|
||||||
@@ -44,10 +35,6 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
|||||||
config = config.with_socket(SocketType::None);
|
config = config.with_socket(SocketType::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present("vpn-mode") {
|
|
||||||
config.get_base_mut().set_vpn_mode(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(port) = matches.value_of("port").map(|port| port.parse::<u16>()) {
|
if let Some(port) = matches.value_of("port").map(|port| port.parse::<u16>()) {
|
||||||
if let Err(err) = port {
|
if let Err(err) = port {
|
||||||
// if port was overridden, it must be parsable
|
// if port was overridden, it must be parsable
|
||||||
@@ -56,5 +43,14 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
|||||||
config = config.with_port(port.unwrap());
|
config = config.with_port(port.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
|
||||||
|
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
if let Some(eth_private_key) = matches.value_of("eth_private_key") {
|
||||||
|
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||||
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use crate::client::NymClient;
|
use crate::client::NymClient;
|
||||||
@@ -21,7 +10,7 @@ use log::*;
|
|||||||
use version_checker::is_minor_version_compatible;
|
use version_checker::is_minor_version_compatible;
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||||
App::new("run")
|
let app = App::new("run")
|
||||||
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
|
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
|
||||||
.arg(Arg::with_name("id")
|
.arg(Arg::with_name("id")
|
||||||
.long("id")
|
.long("id")
|
||||||
@@ -35,11 +24,6 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.help("Comma separated list rest rest endpoints of the validators")
|
.help("Comma separated list rest rest endpoints of the validators")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("mixnet-contract")
|
|
||||||
.long("mixnet-contract")
|
|
||||||
.help("Address of the validator contract managing the network")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("gateway")
|
.arg(Arg::with_name("gateway")
|
||||||
.long("gateway")
|
.long("gateway")
|
||||||
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
||||||
@@ -49,23 +33,24 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.long("disable-socket")
|
.long("disable-socket")
|
||||||
.help("Whether to not start the websocket")
|
.help("Whether to not start the websocket")
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("vpn-mode")
|
|
||||||
.long("vpn-mode")
|
|
||||||
.help("Set the vpn mode of the client")
|
|
||||||
.long_help(
|
|
||||||
r#"
|
|
||||||
Special mode of the system such that all messages are sent as soon as they are received
|
|
||||||
and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
|
||||||
'Debug' values will have no effect.
|
|
||||||
"#
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("port")
|
.arg(Arg::with_name("port")
|
||||||
.short("p")
|
.short("p")
|
||||||
.long("port")
|
.long("port")
|
||||||
.help("Port for the socket (if applicable) to listen on")
|
.help("Port for the socket (if applicable) to listen on")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
);
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let app = app
|
||||||
|
.arg(Arg::with_name("eth_endpoint")
|
||||||
|
.long("eth_endpoint")
|
||||||
|
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
|
||||||
|
.takes_value(true))
|
||||||
|
.arg(Arg::with_name("eth_private_key")
|
||||||
|
.long("eth_private_key")
|
||||||
|
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
|
||||||
|
.takes_value(true));
|
||||||
|
|
||||||
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
// this only checks compatibility between config the binary. It does not take into consideration
|
// this only checks compatibility between config the binary. It does not take into consideration
|
||||||
@@ -90,7 +75,7 @@ fn version_check(cfg: &Config) -> bool {
|
|||||||
pub fn execute(matches: &ArgMatches) {
|
pub fn execute(matches: &ArgMatches) {
|
||||||
let id = matches.value_of("id").unwrap();
|
let id = matches.value_of("id").unwrap();
|
||||||
|
|
||||||
let mut config = match Config::load_from_file(id) {
|
let mut config = match Config::load_from_file(Some(id)) {
|
||||||
Ok(cfg) => cfg,
|
Ok(cfg) => cfg,
|
||||||
Err(err) => {
|
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: {})", id, err);
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::{Config, MISSING_VALUE};
|
use crate::client::config::{Config, MISSING_VALUE};
|
||||||
use clap::{App, Arg, ArgMatches};
|
use clap::{App, Arg, ArgMatches};
|
||||||
use client_core::config::{default_validator_rest_endpoints, DEFAULT_MIXNET_CONTRACT_ADDRESS};
|
use config::defaults::default_api_endpoints;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::process;
|
use std::process;
|
||||||
use version_checker::{parse_version, Version};
|
use version_checker::Version;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||||
|
print_failed_upgrade(from_version, to_version);
|
||||||
|
process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||||
println!(
|
println!(
|
||||||
@@ -41,28 +36,29 @@ fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||||
App::new("upgrade").about("Try to upgrade the client")
|
eprintln!(
|
||||||
.arg(
|
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
|
||||||
Arg::with_name("id")
|
config_version, package_version
|
||||||
.long("id")
|
);
|
||||||
.help("Id of the nym-client we want to upgrade")
|
process::exit(1)
|
||||||
.takes_value(true)
|
|
||||||
.required(true),
|
|
||||||
)
|
|
||||||
// the rest of arguments depend on the upgrade path
|
|
||||||
.arg(Arg::with_name("current version")
|
|
||||||
.long("current-version")
|
|
||||||
.help("REQUIRED FOR PRE-0.9.0 UPGRADES. Specifies current version of the configuration file to help to determine a valid upgrade path. Valid formats include '0.8.1', 'v0.8.1' or 'V0.8.1'")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unsupported_upgrade(config_version: Version, package_version: Version) -> ! {
|
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||||
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, package_version);
|
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, current_version);
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||||
|
App::new("upgrade").about("Try to upgrade the client").arg(
|
||||||
|
Arg::with_name("id")
|
||||||
|
.long("id")
|
||||||
|
.help("Id of the nym-client we want to upgrade")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_config_version(config: &Config) -> Version {
|
fn parse_config_version(config: &Config) -> Version {
|
||||||
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
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);
|
||||||
@@ -97,146 +93,28 @@ fn parse_package_version() -> Version {
|
|||||||
version
|
version
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_090_upgrade(from: &str, mut config: Config) -> Config {
|
fn minor_0_12_upgrade(
|
||||||
// this is not extracted to separate function as you only have to manually pass version
|
|
||||||
// if upgrading from pre090 version
|
|
||||||
let from = match from.strip_prefix('v') {
|
|
||||||
Some(stripped) => stripped,
|
|
||||||
None => from,
|
|
||||||
};
|
|
||||||
|
|
||||||
let from = match from.strip_prefix('V') {
|
|
||||||
Some(stripped) => stripped,
|
|
||||||
None => from,
|
|
||||||
};
|
|
||||||
|
|
||||||
let from_version = parse_version(from).expect("invalid version provided!");
|
|
||||||
if from_version.major == 0 && from_version.minor < 8 {
|
|
||||||
// technically this could be implemented, but is there any point in that?
|
|
||||||
eprintln!("upgrading client from before v0.8.0 is not supported. Please run `init` with new binary instead");
|
|
||||||
process::exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from_version.major == 0 && from_version.minor >= 9) || from_version.major >= 1 {
|
|
||||||
eprintln!("self reported version is higher than 0.9.0. Those releases should have already contained version numbers in config! Make sure you provided correct version");
|
|
||||||
process::exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: current is guaranteed to not have any `build` information suffix (nor pre-release
|
|
||||||
// information), as this was asserted at the beginning of this command)
|
|
||||||
//
|
|
||||||
// upgrade to current (if it's a 0.9.X) or try to upgrade to 0.9.0 as an intermediate
|
|
||||||
// step in future upgrades (so, for example, we might go 0.8.0 -> 0.9.0 -> 0.10.0)
|
|
||||||
// this way we don't need to have all the crazy paths on how to upgrade from any version to any
|
|
||||||
// other version. We just upgrade one minor version at a time.
|
|
||||||
let current = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
|
||||||
let to_version = if current.major == 0 && current.minor == 9 {
|
|
||||||
current
|
|
||||||
} else {
|
|
||||||
Version::new(0, 9, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
if config.get_base().get_validator_rest_endpoints()[0] != MISSING_VALUE {
|
|
||||||
eprintln!("existing config seems to have specified new validator rest endpoint which was only introduced in 0.9.0! Can't perform upgrade.");
|
|
||||||
print_failed_upgrade(&from_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
print_start_upgrade(&from_version, &to_version);
|
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Setting validator REST endpoint to to {:?}",
|
|
||||||
default_validator_rest_endpoints()
|
|
||||||
);
|
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validators(default_validator_rest_endpoints());
|
|
||||||
|
|
||||||
config.save_to_file(None).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
|
||||||
print_failed_upgrade(&from_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
print_successful_upgrade(from_version, to_version);
|
|
||||||
|
|
||||||
config
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
changes:
|
|
||||||
- introduction of mixnet contract address field
|
|
||||||
- change to default validator rest endpoint
|
|
||||||
*/
|
|
||||||
fn minor_010_upgrade(
|
|
||||||
mut config: Config,
|
mut config: Config,
|
||||||
_matches: &ArgMatches,
|
_matches: &ArgMatches,
|
||||||
config_version: &Version,
|
config_version: &Version,
|
||||||
package_version: &Version,
|
package_version: &Version,
|
||||||
) -> Config {
|
) -> Config {
|
||||||
let to_version = if package_version.major == 0 && package_version.minor == 10 {
|
let to_version = if package_version.major == 0 && package_version.minor == 12 {
|
||||||
package_version.clone()
|
package_version.clone()
|
||||||
} else {
|
} else {
|
||||||
Version::new(0, 10, 0)
|
Version::new(0, 12, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
print_start_upgrade(&config_version, &to_version);
|
print_start_upgrade(&config_version, &to_version);
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
|
||||||
|
|
||||||
if config.get_base().get_validator_mixnet_contract_address() != MISSING_VALUE {
|
|
||||||
eprintln!("existing config seems to have specified mixnet contract address which was only introduced in 0.10.0! Can't perform upgrade.");
|
|
||||||
print_failed_upgrade(&config_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Setting mixnet contract address to {}",
|
"Setting validator API endpoints to {:?}",
|
||||||
DEFAULT_MIXNET_CONTRACT_ADDRESS
|
default_api_endpoints()
|
||||||
);
|
);
|
||||||
|
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_mixnet_contract(DEFAULT_MIXNET_CONTRACT_ADDRESS);
|
.set_custom_validator_apis(default_api_endpoints());
|
||||||
|
|
||||||
// The default validator endpoint changed
|
|
||||||
println!(
|
|
||||||
"Setting validator REST endpoint to to {:?}",
|
|
||||||
default_validator_rest_endpoints()
|
|
||||||
);
|
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validators(default_validator_rest_endpoints());
|
|
||||||
|
|
||||||
config.save_to_file(None).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
|
||||||
print_failed_upgrade(&config_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
print_successful_upgrade(config_version, to_version);
|
|
||||||
|
|
||||||
config
|
|
||||||
}
|
|
||||||
|
|
||||||
// no changes but version number
|
|
||||||
fn patch_010_upgrade(
|
|
||||||
mut config: Config,
|
|
||||||
_matches: &ArgMatches,
|
|
||||||
config_version: &Version,
|
|
||||||
package_version: &Version,
|
|
||||||
) -> Config {
|
|
||||||
let to_version = package_version;
|
|
||||||
|
|
||||||
print_start_upgrade(&config_version, &to_version);
|
|
||||||
|
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
@@ -264,11 +142,11 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version
|
|||||||
|
|
||||||
config = match config_version.major {
|
config = match config_version.major {
|
||||||
0 => match config_version.minor {
|
0 => match config_version.minor {
|
||||||
9 => minor_010_upgrade(config, &matches, &config_version, &package_version),
|
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||||
10 => patch_010_upgrade(config, &matches, &config_version, &package_version),
|
11 => minor_0_12_upgrade(config, matches, &config_version, &package_version),
|
||||||
_ => unsupported_upgrade(config_version, package_version),
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
},
|
},
|
||||||
_ => unsupported_upgrade(config_version, package_version),
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,22 +156,14 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
|
|
||||||
let id = matches.value_of("id").unwrap();
|
let id = matches.value_of("id").unwrap();
|
||||||
|
|
||||||
let mut existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
|
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)
|
process::exit(1)
|
||||||
});
|
});
|
||||||
|
|
||||||
// versions fields were added in 0.9.0
|
|
||||||
if existing_config.get_base().get_version() == MISSING_VALUE {
|
if existing_config.get_base().get_version() == MISSING_VALUE {
|
||||||
let self_reported_version = matches.value_of("current version").unwrap_or_else(|| {
|
eprintln!("the existing configuration file does not seem to contain version number.");
|
||||||
eprintln!(
|
process::exit(1);
|
||||||
"trying to upgrade from pre v0.9.0 without providing current system version!"
|
|
||||||
);
|
|
||||||
process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
// upgrades up to 0.9.0
|
|
||||||
existing_config = pre_090_upgrade(self_reported_version, existing_config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// here be upgrade path to 0.9.X and beyond based on version number from config
|
// here be upgrade path to 0.9.X and beyond based on version number from config
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod websocket;
|
pub mod websocket;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use clap::{App, ArgMatches};
|
use clap::{App, ArgMatches};
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use client_core::client::{
|
use client_core::client::{
|
||||||
inbound_messages::{InputMessage, InputMessageSender},
|
inbound_messages::{InputMessage, InputMessageSender},
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use super::handler::Handler;
|
use super::handler::Handler;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
pub(crate) mod handler;
|
pub(crate) mod handler;
|
||||||
pub(crate) mod listener;
|
pub(crate) mod listener;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod requests;
|
pub mod requests;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// all variable size data is always prefixed with u64 length
|
// all variable size data is always prefixed with u64 length
|
||||||
// tags are u8
|
// tags are u8
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// all variable size data is always prefixed with u64 length
|
// all variable size data is always prefixed with u64 length
|
||||||
// tags are u8
|
// tags are u8
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::error::ErrorKind;
|
use crate::error::ErrorKind;
|
||||||
use crate::requests::ClientRequest;
|
use crate::requests::ClientRequest;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "0.10.1"
|
version = "0.11.0"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
rust-version = "1.56"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "nym_socks5"
|
name = "nym_socks5"
|
||||||
@@ -20,9 +21,12 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
|||||||
serde = { version = "1.0", features = ["derive"] } # for config serialization/deserialization
|
serde = { version = "1.0", features = ["derive"] } # for config serialization/deserialization
|
||||||
snafu = "0.6"
|
snafu = "0.6"
|
||||||
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] }
|
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] }
|
||||||
|
url = "2.2"
|
||||||
|
|
||||||
# internal
|
# internal
|
||||||
client-core = { path = "../client-core" }
|
client-core = { path = "../client-core" }
|
||||||
|
coconut-interface = { path = "../../common/coconut-interface", optional = true }
|
||||||
|
credentials = { path = "../../common/credentials", optional = true }
|
||||||
config = { path = "../../common/config" }
|
config = { path = "../../common/config" }
|
||||||
crypto = { path = "../../common/crypto" }
|
crypto = { path = "../../common/crypto" }
|
||||||
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
gateway-client = { path = "../../common/client-libs/gateway-client" }
|
||||||
@@ -35,3 +39,6 @@ pemstore = { path = "../../common/pemstore" }
|
|||||||
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
|
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
|
||||||
validator-client = { path = "../../common/client-libs/validator-client" }
|
validator-client = { path = "../../common/client-libs/validator-client" }
|
||||||
version-checker = { path = "../../common/version-checker" }
|
version-checker = { path = "../../common/version-checker" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
coconut = ["coconut-interface", "credentials", "gateway-requests/coconut", "gateway-client/coconut"]
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::template::config_template;
|
use crate::client::config::template::config_template;
|
||||||
use client_core::config::Config as BaseConfig;
|
use client_core::config::Config as BaseConfig;
|
||||||
pub use client_core::config::MISSING_VALUE;
|
pub use client_core::config::MISSING_VALUE;
|
||||||
|
use config::defaults::DEFAULT_SOCKS5_LISTENING_PORT;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -22,8 +12,6 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
mod template;
|
mod template;
|
||||||
|
|
||||||
const DEFAULT_LISTENING_PORT: u16 = 1080;
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
#[derive(Debug, Default, Deserialize, PartialEq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@@ -114,7 +102,7 @@ pub struct Socks5 {
|
|||||||
impl Socks5 {
|
impl Socks5 {
|
||||||
pub fn new<S: Into<String>>(provider_mix_address: S) -> Self {
|
pub fn new<S: Into<String>>(provider_mix_address: S) -> Self {
|
||||||
Socks5 {
|
Socks5 {
|
||||||
listening_port: DEFAULT_LISTENING_PORT,
|
listening_port: DEFAULT_SOCKS5_LISTENING_PORT,
|
||||||
provider_mix_address: provider_mix_address.into(),
|
provider_mix_address: provider_mix_address.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,7 +111,7 @@ impl Socks5 {
|
|||||||
impl Default for Socks5 {
|
impl Default for Socks5 {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Socks5 {
|
Socks5 {
|
||||||
listening_port: DEFAULT_LISTENING_PORT,
|
listening_port: DEFAULT_SOCKS5_LISTENING_PORT,
|
||||||
provider_mix_address: "".into(),
|
provider_mix_address: "".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,11 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
pub(crate) fn config_template() -> &'static str {
|
pub(crate) fn config_template() -> &'static str {
|
||||||
// While using normal toml marshalling would have been way simpler with less overhead,
|
// While using normal toml marshalling would have been way simpler with less overhead,
|
||||||
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
// I think it's useful to have comments attached to the saved config file to explain behaviour of
|
||||||
// particular fields.
|
// particular fields.
|
||||||
// Note: any changes to the template must be reflected in the appropriate structs in mod.rs.
|
// Note: any changes to the template must be reflected in the appropriate structs in verloc.
|
||||||
r#"
|
r#"
|
||||||
# This is a TOML config file.
|
# This is a TOML config file.
|
||||||
# For more information, see https://github.com/toml-lang/toml
|
# For more information, see https://github.com/toml-lang/toml
|
||||||
@@ -30,21 +19,13 @@ version = '{{ client.version }}'
|
|||||||
# Human readable ID of this particular client.
|
# Human readable ID of this particular client.
|
||||||
id = '{{ client.id }}'
|
id = '{{ client.id }}'
|
||||||
|
|
||||||
# URL to the validator server for obtaining network topology.
|
# Addresses to APIs running on validator from which the client gets the view of the network.
|
||||||
validator_rest_urls = [
|
validator_api_urls = [
|
||||||
{{#each client.validator_rest_urls }}
|
{{#each client.validator_api_urls }}
|
||||||
'{{this}}',
|
'{{this}}',
|
||||||
{{/each}}
|
{{/each}}
|
||||||
]
|
]
|
||||||
|
|
||||||
# Address of the validator contract managing the network.
|
|
||||||
mixnet_contract_address = '{{ client.mixnet_contract_address }}'
|
|
||||||
|
|
||||||
# Special mode of the system such that all messages are sent as soon as they are received
|
|
||||||
# and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
|
||||||
# 'Debug' values will have no effect.
|
|
||||||
vpn_mode = {{ client.vpn_mode }}
|
|
||||||
|
|
||||||
# Path to file containing private identity key.
|
# Path to file containing private identity key.
|
||||||
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
private_identity_key_file = '{{ client.private_identity_key_file }}'
|
||||||
|
|
||||||
@@ -61,6 +42,17 @@ public_encryption_key_file = '{{ client.public_encryption_key_file }}'
|
|||||||
# sent but not received back.
|
# sent but not received back.
|
||||||
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
reply_encryption_key_store_path = '{{ client.reply_encryption_key_store_path }}'
|
||||||
|
|
||||||
|
# Path to directory containing public/private keys used for bandwidth token purchase.
|
||||||
|
# Those are saved in case of emergency, to be able to reclaim bandwidth tokens.
|
||||||
|
# The public key is the name of the file, while the private key is the content.
|
||||||
|
backup_bandwidth_token_keys_dir = '{{ client.backup_bandwidth_token_keys_dir }}'
|
||||||
|
|
||||||
|
# Ethereum private key.
|
||||||
|
eth_private_key = '{{ client.eth_private_key }}'
|
||||||
|
|
||||||
|
# Addess to an Ethereum full node.
|
||||||
|
eth_endpoint = '{{ client.eth_endpoint }}'
|
||||||
|
|
||||||
##### additional client config options #####
|
##### additional client config options #####
|
||||||
|
|
||||||
# ID of the gateway from which the client should be fetching messages.
|
# ID of the gateway from which the client should be fetching messages.
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use crate::socks::{
|
use crate::socks::{
|
||||||
@@ -43,9 +32,10 @@ use gateway_client::{
|
|||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
use nymsphinx::params::PacketMode;
|
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
|
use gateway_client::bandwidth::BandwidthController;
|
||||||
|
|
||||||
pub(crate) mod config;
|
pub(crate) mod config;
|
||||||
|
|
||||||
pub struct NymClient {
|
pub struct NymClient {
|
||||||
@@ -118,12 +108,6 @@ impl NymClient {
|
|||||||
input_receiver: InputMessageReceiver,
|
input_receiver: InputMessageReceiver,
|
||||||
mix_sender: BatchMixMessageSender,
|
mix_sender: BatchMixMessageSender,
|
||||||
) {
|
) {
|
||||||
let packet_mode = if self.config.get_base().get_vpn_mode() {
|
|
||||||
PacketMode::Vpn
|
|
||||||
} else {
|
|
||||||
PacketMode::Mix
|
|
||||||
};
|
|
||||||
|
|
||||||
let controller_config = client_core::client::real_messages_control::Config::new(
|
let controller_config = client_core::client::real_messages_control::Config::new(
|
||||||
self.key_manager.ack_key(),
|
self.key_manager.ack_key(),
|
||||||
self.config.get_base().get_ack_wait_multiplier(),
|
self.config.get_base().get_ack_wait_multiplier(),
|
||||||
@@ -132,8 +116,6 @@ impl NymClient {
|
|||||||
self.config.get_base().get_message_sending_average_delay(),
|
self.config.get_base().get_message_sending_average_delay(),
|
||||||
self.config.get_base().get_average_packet_delay(),
|
self.config.get_base().get_average_packet_delay(),
|
||||||
self.as_mix_recipient(),
|
self.as_mix_recipient(),
|
||||||
packet_mode,
|
|
||||||
self.config.get_base().get_vpn_key_reuse_limit(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("Starting real traffic stream...");
|
info!("Starting real traffic stream...");
|
||||||
@@ -150,7 +132,7 @@ impl NymClient {
|
|||||||
topology_accessor,
|
topology_accessor,
|
||||||
reply_key_storage,
|
reply_key_storage,
|
||||||
)
|
)
|
||||||
.start(self.runtime.handle(), self.config.get_base().get_vpn_mode());
|
.start(self.runtime.handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer controlling all messages fetched from provider
|
// buffer controlling all messages fetched from provider
|
||||||
@@ -188,44 +170,53 @@ impl NymClient {
|
|||||||
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
let gateway_identity = identity::PublicKey::from_base58_string(gateway_id)
|
||||||
.expect("provided gateway id is invalid!");
|
.expect("provided gateway id is invalid!");
|
||||||
|
|
||||||
let mut gateway_client = GatewayClient::new(
|
|
||||||
gateway_address,
|
|
||||||
self.key_manager.identity_keypair(),
|
|
||||||
gateway_identity,
|
|
||||||
Some(self.key_manager.gateway_shared_key()),
|
|
||||||
mixnet_message_sender,
|
|
||||||
ack_sender,
|
|
||||||
self.config.get_base().get_gateway_response_timeout(),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.runtime.block_on(async {
|
self.runtime.block_on(async {
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
let bandwidth_controller = BandwidthController::new(
|
||||||
|
self.config.get_base().get_validator_api_endpoints(),
|
||||||
|
*self.key_manager.identity_keypair().public_key(),
|
||||||
|
);
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let bandwidth_controller = BandwidthController::new(
|
||||||
|
self.config.get_base().get_eth_endpoint(),
|
||||||
|
self.config.get_base().get_eth_private_key(),
|
||||||
|
self.config.get_base().get_backup_bandwidth_token_keys_dir(),
|
||||||
|
)
|
||||||
|
.expect("Could not create bandwidth controller");
|
||||||
|
|
||||||
|
let mut gateway_client = GatewayClient::new(
|
||||||
|
gateway_address,
|
||||||
|
self.key_manager.identity_keypair(),
|
||||||
|
gateway_identity,
|
||||||
|
Some(self.key_manager.gateway_shared_key()),
|
||||||
|
mixnet_message_sender,
|
||||||
|
ack_sender,
|
||||||
|
self.config.get_base().get_gateway_response_timeout(),
|
||||||
|
Some(bandwidth_controller),
|
||||||
|
);
|
||||||
|
|
||||||
gateway_client
|
gateway_client
|
||||||
.authenticate_and_start()
|
.authenticate_and_start()
|
||||||
.await
|
.await
|
||||||
.expect("could not authenticate and start up the gateway connection")
|
.expect("could not authenticate and start up the gateway connection");
|
||||||
});
|
|
||||||
|
|
||||||
gateway_client
|
gateway_client
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// future responsible for periodically polling directory server and updating
|
// future responsible for periodically polling directory server and updating
|
||||||
// the current global view of topology
|
// the current global view of topology
|
||||||
fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
fn start_topology_refresher(&mut self, topology_accessor: TopologyAccessor) {
|
||||||
let topology_refresher_config = TopologyRefresherConfig::new(
|
let topology_refresher_config = TopologyRefresherConfig::new(
|
||||||
self.config.get_base().get_validator_rest_endpoints(),
|
self.config.get_base().get_validator_api_endpoints(),
|
||||||
self.config
|
|
||||||
.get_base()
|
|
||||||
.get_validator_mixnet_contract_address(),
|
|
||||||
self.config.get_base().get_topology_refresh_rate(),
|
self.config.get_base().get_topology_refresh_rate(),
|
||||||
|
env!("CARGO_PKG_VERSION").to_string(),
|
||||||
);
|
);
|
||||||
let mut topology_refresher =
|
let mut topology_refresher =
|
||||||
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
TopologyRefresher::new(topology_refresher_config, topology_accessor);
|
||||||
// before returning, block entire runtime to refresh the current network view so that any
|
// before returning, block entire runtime to refresh the current network view so that any
|
||||||
// components depending on topology would see a non-empty view
|
// components depending on topology would see a non-empty view
|
||||||
info!(
|
info!("Obtaining initial network topology");
|
||||||
"Obtaining initial network topology from {}",
|
|
||||||
self.config.get_base().get_validator_rest_endpoints()[0]
|
|
||||||
);
|
|
||||||
self.runtime.block_on(topology_refresher.refresh());
|
self.runtime.block_on(topology_refresher.refresh());
|
||||||
|
|
||||||
// TODO: a slightly more graceful termination here
|
// TODO: a slightly more graceful termination here
|
||||||
@@ -340,9 +331,8 @@ impl NymClient {
|
|||||||
input_receiver,
|
input_receiver,
|
||||||
sphinx_message_sender.clone(),
|
sphinx_message_sender.clone(),
|
||||||
);
|
);
|
||||||
if !self.config.get_base().get_vpn_mode() {
|
|
||||||
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
self.start_cover_traffic_stream(shared_topology_accessor, sphinx_message_sender);
|
||||||
}
|
|
||||||
self.start_socks5_listener(received_buffer_request_sender, input_sender);
|
self.start_socks5_listener(received_buffer_request_sender, input_sender);
|
||||||
|
|
||||||
info!("Client startup finished!");
|
info!("Client startup finished!");
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use crate::commands::override_config;
|
use crate::commands::override_config;
|
||||||
@@ -23,14 +12,15 @@ use gateway_client::GatewayClient;
|
|||||||
use gateway_requests::registration::handshake::SharedKeys;
|
use gateway_requests::registration::handshake::SharedKeys;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
use rand::{prelude::SliceRandom, rngs::OsRng};
|
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use topology::{filter::VersionFilterable, gateway};
|
use topology::{filter::VersionFilterable, gateway};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||||
App::new("init")
|
let app = App::new("init")
|
||||||
.about("Initialise a Nym client. Do this first!")
|
.about("Initialise a Nym client. Do this first!")
|
||||||
.arg(Arg::with_name("id")
|
.arg(Arg::with_name("id")
|
||||||
.long("id")
|
.long("id")
|
||||||
@@ -54,42 +44,40 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.help("Comma separated list of rest endpoints of the validators")
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("mixnet-contract")
|
|
||||||
.long("mixnet-contract")
|
|
||||||
.help("Address of the validator contract managing the network")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("port")
|
.arg(Arg::with_name("port")
|
||||||
.short("p")
|
.short("p")
|
||||||
.long("port")
|
.long("port")
|
||||||
.help("Port for the socket to listen on in all subsequent runs")
|
.help("Port for the socket to listen on in all subsequent runs")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("vpn-mode")
|
|
||||||
.long("vpn-mode")
|
|
||||||
.help("Set the vpn mode of the client")
|
|
||||||
.long_help(
|
|
||||||
r#"
|
|
||||||
Special mode of the system such that all messages are sent as soon as they are received
|
|
||||||
and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
|
||||||
'Debug' values will have no effect.
|
|
||||||
"#
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("fastmode")
|
.arg(Arg::with_name("fastmode")
|
||||||
.long("fastmode")
|
.long("fastmode")
|
||||||
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
||||||
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
||||||
)
|
);
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let app = app
|
||||||
|
.arg(Arg::with_name("eth_endpoint")
|
||||||
|
.long("eth_endpoint")
|
||||||
|
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true))
|
||||||
|
.arg(Arg::with_name("eth_private_key")
|
||||||
|
.long("eth_private_key")
|
||||||
|
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true));
|
||||||
|
|
||||||
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn register_with_gateway(
|
async fn register_with_gateway(
|
||||||
gateway: &gateway::Node,
|
gateway: &gateway::Node,
|
||||||
our_identity: Arc<identity::KeyPair>,
|
our_identity: Arc<identity::KeyPair>,
|
||||||
) -> SharedKeys {
|
) -> Arc<SharedKeys> {
|
||||||
let timeout = Duration::from_millis(1500);
|
let timeout = Duration::from_millis(1500);
|
||||||
let mut gateway_client = GatewayClient::new_init(
|
let mut gateway_client = GatewayClient::new_init(
|
||||||
gateway.client_listener.clone(),
|
gateway.clients_address(),
|
||||||
gateway.identity_key,
|
gateway.identity_key,
|
||||||
our_identity.clone(),
|
our_identity.clone(),
|
||||||
timeout,
|
timeout,
|
||||||
@@ -99,20 +87,21 @@ async fn register_with_gateway(
|
|||||||
.await
|
.await
|
||||||
.expect("failed to establish connection with the gateway!");
|
.expect("failed to establish connection with the gateway!");
|
||||||
gateway_client
|
gateway_client
|
||||||
.register()
|
.perform_initial_authentication()
|
||||||
.await
|
.await
|
||||||
.expect("failed to register with the gateway!")
|
.expect("failed to register with the gateway!")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn gateway_details(
|
async fn gateway_details(
|
||||||
validator_servers: Vec<String>,
|
validator_servers: Vec<Url>,
|
||||||
mixnet_contract: &str,
|
|
||||||
chosen_gateway_id: Option<&str>,
|
chosen_gateway_id: Option<&str>,
|
||||||
) -> gateway::Node {
|
) -> gateway::Node {
|
||||||
let validator_client_config = validator_client::Config::new(validator_servers, mixnet_contract);
|
let validator_api = validator_servers
|
||||||
let mut validator_client = validator_client::Client::new(validator_client_config);
|
.choose(&mut thread_rng())
|
||||||
|
.expect("The list of validator apis is empty");
|
||||||
|
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||||
|
|
||||||
let gateways = validator_client.get_gateways().await.unwrap();
|
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||||
let valid_gateways = gateways
|
let valid_gateways = gateways
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|gateway| gateway.try_into().ok())
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
@@ -179,7 +168,7 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
let id = matches.value_of("id").unwrap(); // required for now
|
let id = matches.value_of("id").unwrap(); // required for now
|
||||||
let provider_address = matches.value_of("provider").unwrap();
|
let provider_address = matches.value_of("provider").unwrap();
|
||||||
|
|
||||||
let already_init = if Config::default_config_file_path(id).exists() {
|
let already_init = if Config::default_config_file_path(Some(id)).exists() {
|
||||||
println!("Socks5 client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
|
println!("Socks5 client \"{}\" was already initialised before! Config information will be overwritten (but keys will be kept)!", id);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@@ -207,8 +196,7 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
|
|
||||||
let registration_fut = async {
|
let registration_fut = async {
|
||||||
let gate_details = gateway_details(
|
let gate_details = gateway_details(
|
||||||
config.get_base().get_validator_rest_endpoints(),
|
config.get_base().get_validator_api_endpoints(),
|
||||||
&config.get_base().get_validator_mixnet_contract_address(),
|
|
||||||
chosen_gateway_id,
|
chosen_gateway_id,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@@ -217,7 +205,7 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
.with_gateway_id(gate_details.identity_key.to_base58_string());
|
.with_gateway_id(gate_details.identity_key.to_base58_string());
|
||||||
let shared_keys =
|
let shared_keys =
|
||||||
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
register_with_gateway(&gate_details, key_manager.identity_keypair()).await;
|
||||||
(shared_keys, gate_details.client_listener)
|
(shared_keys, gate_details.clients_address())
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
// TODO: is there perhaps a way to make it work without having to spawn entire runtime?
|
||||||
|
|||||||
@@ -1,27 +1,22 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
pub(crate) mod init;
|
pub(crate) mod init;
|
||||||
pub(crate) mod run;
|
pub(crate) mod run;
|
||||||
pub(crate) mod upgrade;
|
pub(crate) mod upgrade;
|
||||||
|
|
||||||
fn parse_validators(raw: &str) -> Vec<String> {
|
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
raw.split(',')
|
raw.split(',')
|
||||||
.map(|raw_validator| raw_validator.trim().into())
|
.map(|raw_validator| {
|
||||||
|
raw_validator
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.expect("one of the provided validator api urls is invalid")
|
||||||
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,21 +24,13 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
|||||||
if let Some(raw_validators) = matches.value_of("validators") {
|
if let Some(raw_validators) = matches.value_of("validators") {
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_custom_validators(parse_validators(raw_validators));
|
.set_custom_validator_apis(parse_validators(raw_validators));
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(contract_address) = matches.value_of("mixnet-contract") {
|
|
||||||
config.get_base_mut().set_mixnet_contract(contract_address)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(gateway_id) = matches.value_of("gateway") {
|
if let Some(gateway_id) = matches.value_of("gateway") {
|
||||||
config.get_base_mut().with_gateway_id(gateway_id);
|
config.get_base_mut().with_gateway_id(gateway_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present("vpn-mode") {
|
|
||||||
config.get_base_mut().set_vpn_mode(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(port) = matches.value_of("port").map(|port| port.parse::<u16>()) {
|
if let Some(port) = matches.value_of("port").map(|port| port.parse::<u16>()) {
|
||||||
if let Err(err) = port {
|
if let Err(err) = port {
|
||||||
// if port was overridden, it must be parsable
|
// if port was overridden, it must be parsable
|
||||||
@@ -52,5 +39,14 @@ pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Confi
|
|||||||
config = config.with_port(port.unwrap());
|
config = config.with_port(port.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
if let Some(eth_endpoint) = matches.value_of("eth_endpoint") {
|
||||||
|
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
if let Some(eth_private_key) = matches.value_of("eth_private_key") {
|
||||||
|
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||||
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use crate::client::NymClient;
|
use crate::client::NymClient;
|
||||||
@@ -21,7 +10,7 @@ use log::*;
|
|||||||
use version_checker::is_minor_version_compatible;
|
use version_checker::is_minor_version_compatible;
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||||
App::new("run")
|
let app = App::new("run")
|
||||||
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
|
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
|
||||||
.arg(Arg::with_name("id")
|
.arg(Arg::with_name("id")
|
||||||
.long("id")
|
.long("id")
|
||||||
@@ -45,33 +34,29 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.help("Comma separated list of rest endpoints of the validators")
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("mixnet-contract")
|
|
||||||
.long("mixnet-contract")
|
|
||||||
.help("Address of the validator contract managing the network")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("gateway")
|
.arg(Arg::with_name("gateway")
|
||||||
.long("gateway")
|
.long("gateway")
|
||||||
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("vpn-mode")
|
|
||||||
.long("vpn-mode")
|
|
||||||
.help("Set the vpn mode of the client")
|
|
||||||
.long_help(
|
|
||||||
r#"
|
|
||||||
Special mode of the system such that all messages are sent as soon as they are received
|
|
||||||
and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
|
||||||
'Debug' values will have no effect.
|
|
||||||
"#
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("port")
|
.arg(Arg::with_name("port")
|
||||||
.short("p")
|
.short("p")
|
||||||
.long("port")
|
.long("port")
|
||||||
.help("Port for the socket to listen on")
|
.help("Port for the socket to listen on")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
);
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
let app = app
|
||||||
|
.arg(Arg::with_name("eth_endpoint")
|
||||||
|
.long("eth_endpoint")
|
||||||
|
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens")
|
||||||
|
.takes_value(true))
|
||||||
|
.arg(Arg::with_name("eth_private_key")
|
||||||
|
.long("eth_private_key")
|
||||||
|
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens")
|
||||||
|
.takes_value(true));
|
||||||
|
|
||||||
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
// this only checks compatibility between config the binary. It does not take into consideration
|
// this only checks compatibility between config the binary. It does not take into consideration
|
||||||
@@ -96,7 +81,7 @@ fn version_check(cfg: &Config) -> bool {
|
|||||||
pub fn execute(matches: &ArgMatches) {
|
pub fn execute(matches: &ArgMatches) {
|
||||||
let id = matches.value_of("id").unwrap();
|
let id = matches.value_of("id").unwrap();
|
||||||
|
|
||||||
let mut config = match Config::load_from_file(id) {
|
let mut config = match Config::load_from_file(Some(id)) {
|
||||||
Ok(cfg) => cfg,
|
Ok(cfg) => cfg,
|
||||||
Err(err) => {
|
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: {})", id, err);
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use crate::client::config::{Config, MISSING_VALUE};
|
use crate::client::config::{Config, MISSING_VALUE};
|
||||||
use clap::{App, Arg, ArgMatches};
|
use clap::{App, Arg, ArgMatches};
|
||||||
use client_core::config::{default_validator_rest_endpoints, DEFAULT_MIXNET_CONTRACT_ADDRESS};
|
use config::defaults::default_api_endpoints;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::process;
|
use std::process;
|
||||||
use version_checker::{parse_version, Version};
|
use version_checker::Version;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||||
|
print_failed_upgrade(from_version, to_version);
|
||||||
|
process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
fn print_start_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
||||||
println!(
|
println!(
|
||||||
@@ -41,28 +36,29 @@ fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||||
App::new("upgrade").about("Try to upgrade the client")
|
eprintln!(
|
||||||
.arg(
|
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
|
||||||
Arg::with_name("id")
|
config_version, package_version
|
||||||
.long("id")
|
);
|
||||||
.help("Id of the nym-socks5-client we want to upgrade")
|
process::exit(1)
|
||||||
.takes_value(true)
|
|
||||||
.required(true),
|
|
||||||
)
|
|
||||||
// the rest of arguments depend on the upgrade path
|
|
||||||
.arg(Arg::with_name("current version")
|
|
||||||
.long("current-version")
|
|
||||||
.help("REQUIRED FOR PRE-0.9.0 UPGRADES. Specifies current version of the configuration file to help to determine a valid upgrade path. Valid formats include '0.8.1', 'v0.8.1' or 'V0.8.1'")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unsupported_upgrade(config_version: Version, package_version: Version) -> ! {
|
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||||
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, package_version);
|
eprintln!("Cannot perform upgrade from {} to {}. Please let the developers know about this issue if you expected it to work!", config_version, current_version);
|
||||||
process::exit(1)
|
process::exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||||
|
App::new("upgrade").about("Try to upgrade the client").arg(
|
||||||
|
Arg::with_name("id")
|
||||||
|
.long("id")
|
||||||
|
.help("Id of the nym-client we want to upgrade")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_config_version(config: &Config) -> Version {
|
fn parse_config_version(config: &Config) -> Version {
|
||||||
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
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);
|
||||||
@@ -97,146 +93,28 @@ fn parse_package_version() -> Version {
|
|||||||
version
|
version
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_090_upgrade(from: &str, mut config: Config) -> Config {
|
fn minor_0_12_upgrade(
|
||||||
// this is not extracted to separate function as you only have to manually pass version
|
|
||||||
// if upgrading from pre090 version
|
|
||||||
let from = match from.strip_prefix('v') {
|
|
||||||
Some(stripped) => stripped,
|
|
||||||
None => from,
|
|
||||||
};
|
|
||||||
|
|
||||||
let from = match from.strip_prefix('V') {
|
|
||||||
Some(stripped) => stripped,
|
|
||||||
None => from,
|
|
||||||
};
|
|
||||||
|
|
||||||
let from_version = parse_version(from).expect("invalid version provided!");
|
|
||||||
if from_version.major == 0 && from_version.minor < 8 {
|
|
||||||
// technically this could be implemented, but is there any point in that?
|
|
||||||
eprintln!("upgrading client from before v0.8.0 is not supported. Please run `init` with new binary instead");
|
|
||||||
process::exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from_version.major == 0 && from_version.minor >= 9) || from_version.major >= 1 {
|
|
||||||
eprintln!("self reported version is higher than 0.9.0. Those releases should have already contained version numbers in config! Make sure you provided correct version");
|
|
||||||
process::exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// note: current is guaranteed to not have any `build` information suffix (nor pre-release
|
|
||||||
// information), as this was asserted at the beginning of this command)
|
|
||||||
//
|
|
||||||
// upgrade to current (if it's a 0.9.X) or try to upgrade to 0.9.0 as an intermediate
|
|
||||||
// step in future upgrades (so, for example, we might go 0.8.0 -> 0.9.0 -> 0.10.0)
|
|
||||||
// this way we don't need to have all the crazy paths on how to upgrade from any version to any
|
|
||||||
// other version. We just upgrade one minor version at a time.
|
|
||||||
let current = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
|
||||||
let to_version = if current.major == 0 && current.minor == 9 {
|
|
||||||
current
|
|
||||||
} else {
|
|
||||||
Version::new(0, 9, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
if config.get_base().get_validator_rest_endpoints()[0] != MISSING_VALUE {
|
|
||||||
eprintln!("existing config seems to have specified new validator rest endpoint which was only introduced in 0.9.0! Can't perform upgrade.");
|
|
||||||
print_failed_upgrade(&from_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
print_start_upgrade(&from_version, &to_version);
|
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Setting validator REST endpoint to {:?}",
|
|
||||||
default_validator_rest_endpoints()
|
|
||||||
);
|
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validators(default_validator_rest_endpoints());
|
|
||||||
|
|
||||||
config.save_to_file(None).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
|
||||||
print_failed_upgrade(&from_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
print_successful_upgrade(from_version, to_version);
|
|
||||||
|
|
||||||
config
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
changes:
|
|
||||||
- introduction of mixnet contract address field
|
|
||||||
- change to default validator rest endpoint
|
|
||||||
*/
|
|
||||||
fn minor_010_upgrade(
|
|
||||||
mut config: Config,
|
mut config: Config,
|
||||||
_matches: &ArgMatches,
|
_matches: &ArgMatches,
|
||||||
config_version: &Version,
|
config_version: &Version,
|
||||||
package_version: &Version,
|
package_version: &Version,
|
||||||
) -> Config {
|
) -> Config {
|
||||||
let to_version = if package_version.major == 0 && package_version.minor == 10 {
|
let to_version = if package_version.major == 0 && package_version.minor == 12 {
|
||||||
package_version.clone()
|
package_version.clone()
|
||||||
} else {
|
} else {
|
||||||
Version::new(0, 10, 0)
|
Version::new(0, 12, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
print_start_upgrade(&config_version, &to_version);
|
print_start_upgrade(&config_version, &to_version);
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
|
||||||
|
|
||||||
if config.get_base().get_validator_mixnet_contract_address() != MISSING_VALUE {
|
|
||||||
eprintln!("existing config seems to have specified mixnet contract address which was only introduced in 0.10.0! Can't perform upgrade.");
|
|
||||||
print_failed_upgrade(&config_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Setting mixnet contract address to {}",
|
"Setting validator API endpoints to {:?}",
|
||||||
DEFAULT_MIXNET_CONTRACT_ADDRESS
|
default_api_endpoints()
|
||||||
);
|
);
|
||||||
|
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_mixnet_contract(DEFAULT_MIXNET_CONTRACT_ADDRESS);
|
.set_custom_validator_apis(default_api_endpoints());
|
||||||
|
|
||||||
// The default validator endpoint changed
|
|
||||||
println!(
|
|
||||||
"Setting validator REST endpoint to to {:?}",
|
|
||||||
default_validator_rest_endpoints()
|
|
||||||
);
|
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validators(default_validator_rest_endpoints());
|
|
||||||
|
|
||||||
config.save_to_file(None).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
|
||||||
print_failed_upgrade(&config_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
print_successful_upgrade(config_version, to_version);
|
|
||||||
|
|
||||||
config
|
|
||||||
}
|
|
||||||
|
|
||||||
// no changes but version number
|
|
||||||
fn patch_010_upgrade(
|
|
||||||
mut config: Config,
|
|
||||||
_matches: &ArgMatches,
|
|
||||||
config_version: &Version,
|
|
||||||
package_version: &Version,
|
|
||||||
) -> Config {
|
|
||||||
let to_version = package_version;
|
|
||||||
|
|
||||||
print_start_upgrade(&config_version, &to_version);
|
|
||||||
|
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
@@ -264,11 +142,11 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version
|
|||||||
|
|
||||||
config = match config_version.major {
|
config = match config_version.major {
|
||||||
0 => match config_version.minor {
|
0 => match config_version.minor {
|
||||||
9 => minor_010_upgrade(config, &matches, &config_version, &package_version),
|
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||||
10 => patch_010_upgrade(config, &matches, &config_version, &package_version),
|
11 => minor_0_12_upgrade(config, matches, &config_version, &package_version),
|
||||||
_ => unsupported_upgrade(config_version, package_version),
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
},
|
},
|
||||||
_ => unsupported_upgrade(config_version, package_version),
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,22 +156,14 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
|
|
||||||
let id = matches.value_of("id").unwrap();
|
let id = matches.value_of("id").unwrap();
|
||||||
|
|
||||||
let mut existing_config = Config::load_from_file(id).unwrap_or_else(|err| {
|
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)
|
process::exit(1)
|
||||||
});
|
});
|
||||||
|
|
||||||
// versions fields were added in 0.9.0
|
|
||||||
if existing_config.get_base().get_version() == MISSING_VALUE {
|
if existing_config.get_base().get_version() == MISSING_VALUE {
|
||||||
let self_reported_version = matches.value_of("current version").unwrap_or_else(|| {
|
eprintln!("the existing configuration file does not seem to contain version number.");
|
||||||
eprintln!(
|
process::exit(1);
|
||||||
"trying to upgrade from pre v0.9.0 without providing current system version!"
|
|
||||||
);
|
|
||||||
process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
// upgrades up to 0.9.0
|
|
||||||
existing_config = pre_090_upgrade(self_reported_version, existing_config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// here be upgrade path to 0.9.X and beyond based on version number from config
|
// here be upgrade path to 0.9.X and beyond based on version number from config
|
||||||
|
|||||||
@@ -1,15 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod socks;
|
pub mod socks;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
// Copyright 2020 Nym Technologies SA
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
//
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use clap::{App, ArgMatches};
|
use clap::{App, ArgMatches};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.DS_Store
|
||||||
|
/node_modules/
|
||||||
|
/src/node_modules/@sapper/
|
||||||
|
yarn-error.log
|
||||||
|
/__sapper__/
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
On Ubuntu-ish systems (not tested on Debian but may work):
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt update && sudo apt install libwebkit2gtk-4.0-dev \
|
||||||
|
build-essential \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
libssl-dev \
|
||||||
|
libgtk-3-dev \
|
||||||
|
libappindicator3-dev \
|
||||||
|
patchelf \
|
||||||
|
librsvg2-dev```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
1. Start Sapper([docs](https://sapper.svelte.dev/docs/)) -> `yarn run dev`
|
||||||
|
2. Start Tauri([docs](https://tauri.studio/en/)) in another terminal -> `yarn tauri dev`
|
||||||
|
3. Start validator-api locally, or override `validator-urls` in `index.svelte`
|
||||||
|
|
||||||
|
## Getting around
|
||||||
|
|
||||||
|
+ Frontend -> `tauri-client/`
|
||||||
|
+ logic -> `tauri-client/src/routes/index.svelte`
|
||||||
|
+ assets -> `tauri-client/static`
|
||||||
|
+ Backend -> `tauri-client/src/src-tauri`
|
||||||
|
|
||||||
|
## Build standalone app
|
||||||
|
|
||||||
|
+ yarn tauri build [--debug]
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "TODO",
|
||||||
|
"description": "TODO",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "sapper dev",
|
||||||
|
"build": "sapper build --legacy",
|
||||||
|
"export": "sapper export --legacy",
|
||||||
|
"start": "node __sapper__/build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tauri-apps/api": "^1.0.0-beta.4",
|
||||||
|
"compression": "^1.7.1",
|
||||||
|
"polka": "next",
|
||||||
|
"qrious": "^4.0.2",
|
||||||
|
"sirv": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.0.0",
|
||||||
|
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.0.0",
|
||||||
|
"@babel/preset-env": "^7.0.0",
|
||||||
|
"@babel/runtime": "^7.0.0",
|
||||||
|
"@rollup/plugin-babel": "^5.0.0",
|
||||||
|
"@rollup/plugin-commonjs": "^14.0.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^8.0.0",
|
||||||
|
"@rollup/plugin-replace": "^2.4.0",
|
||||||
|
"@rollup/plugin-url": "^5.0.0",
|
||||||
|
"@tauri-apps/cli": "^1.0.0-beta.5",
|
||||||
|
"rollup": "^2.3.4",
|
||||||
|
"rollup-plugin-svelte": "^7.0.0",
|
||||||
|
"rollup-plugin-terser": "^7.0.0",
|
||||||
|
"sapper": "^0.28.0",
|
||||||
|
"sass": "^1.35.2",
|
||||||
|
"svelte": "^3.17.3",
|
||||||
|
"svelte-preprocess": "^4.7.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
import path from "path";
|
||||||
|
import resolve from "@rollup/plugin-node-resolve";
|
||||||
|
import replace from "@rollup/plugin-replace";
|
||||||
|
import commonjs from "@rollup/plugin-commonjs";
|
||||||
|
import url from "@rollup/plugin-url";
|
||||||
|
import svelte from "rollup-plugin-svelte";
|
||||||
|
import babel from "@rollup/plugin-babel";
|
||||||
|
import { terser } from "rollup-plugin-terser";
|
||||||
|
import config from "sapper/config/rollup.js";
|
||||||
|
import pkg from "./package.json";
|
||||||
|
import sveltePreprocess from "svelte-preprocess";
|
||||||
|
|
||||||
|
const mode = process.env.NODE_ENV;
|
||||||
|
const dev = mode === "development";
|
||||||
|
const legacy = !!process.env.SAPPER_LEGACY_BUILD;
|
||||||
|
|
||||||
|
const onwarn = (warning, onwarn) =>
|
||||||
|
(warning.code === "MISSING_EXPORT" && /'preload'/.test(warning.message)) ||
|
||||||
|
(warning.code === "CIRCULAR_DEPENDENCY" &&
|
||||||
|
/[/\\]@sapper[/\\]/.test(warning.message)) ||
|
||||||
|
onwarn(warning);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
client: {
|
||||||
|
input: config.client.input(),
|
||||||
|
output: config.client.output(),
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
preventAssignment: true,
|
||||||
|
values: {
|
||||||
|
"process.browser": true,
|
||||||
|
"process.env.NODE_ENV": JSON.stringify(mode),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
compilerOptions: {
|
||||||
|
dev,
|
||||||
|
hydratable: true,
|
||||||
|
},
|
||||||
|
preprocess: sveltePreprocess(),
|
||||||
|
}),
|
||||||
|
url({
|
||||||
|
sourceDir: path.resolve(__dirname, "src/node_modules/images"),
|
||||||
|
publicPath: "/client/",
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
browser: true,
|
||||||
|
dedupe: ["svelte"],
|
||||||
|
}),
|
||||||
|
commonjs(),
|
||||||
|
|
||||||
|
legacy &&
|
||||||
|
babel({
|
||||||
|
extensions: [".js", ".mjs", ".html", ".svelte"],
|
||||||
|
babelHelpers: "runtime",
|
||||||
|
exclude: ["node_modules/@babel/**"],
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
targets: "> 0.25%, not dead",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
"@babel/plugin-syntax-dynamic-import",
|
||||||
|
[
|
||||||
|
"@babel/plugin-transform-runtime",
|
||||||
|
{
|
||||||
|
useESModules: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
|
!dev &&
|
||||||
|
terser({
|
||||||
|
module: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
|
||||||
|
preserveEntrySignatures: false,
|
||||||
|
onwarn,
|
||||||
|
},
|
||||||
|
|
||||||
|
server: {
|
||||||
|
input: config.server.input(),
|
||||||
|
output: config.server.output(),
|
||||||
|
plugins: [
|
||||||
|
replace({
|
||||||
|
preventAssignment: true,
|
||||||
|
values: {
|
||||||
|
"process.browser": false,
|
||||||
|
"process.env.NODE_ENV": JSON.stringify(mode),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
svelte({
|
||||||
|
compilerOptions: {
|
||||||
|
dev,
|
||||||
|
generate: "ssr",
|
||||||
|
hydratable: true,
|
||||||
|
},
|
||||||
|
emitCss: false,
|
||||||
|
}),
|
||||||
|
url({
|
||||||
|
sourceDir: path.resolve(__dirname, "src/node_modules/images"),
|
||||||
|
publicPath: "/client/",
|
||||||
|
emitFiles: false, // already emitted by client build
|
||||||
|
}),
|
||||||
|
resolve({
|
||||||
|
dedupe: ["svelte"],
|
||||||
|
}),
|
||||||
|
commonjs(),
|
||||||
|
],
|
||||||
|
external: Object.keys(pkg.dependencies).concat(
|
||||||
|
require("module").builtinModules
|
||||||
|
),
|
||||||
|
preserveEntrySignatures: "strict",
|
||||||
|
onwarn,
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceworker: {
|
||||||
|
input: config.serviceworker.input(),
|
||||||
|
output: config.serviceworker.output(),
|
||||||
|
plugins: [
|
||||||
|
resolve(),
|
||||||
|
replace({
|
||||||
|
preventAssignment: true,
|
||||||
|
values: {
|
||||||
|
"process.browser": true,
|
||||||
|
"process.env.NODE_ENV": JSON.stringify(mode),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
commonjs(),
|
||||||
|
!dev && terser(),
|
||||||
|
],
|
||||||
|
preserveEntrySignatures: false,
|
||||||
|
onwarn,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
/**
|
||||||
|
* Run this script to convert the project to TypeScript. This is only guaranteed to work
|
||||||
|
* on the unmodified default template; if you have done code changes you are likely need
|
||||||
|
* to touch up the generated project manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { argv } = require('process');
|
||||||
|
|
||||||
|
const projectRoot = argv[2] || path.join(__dirname, '..');
|
||||||
|
|
||||||
|
const isRollup = fs.existsSync(path.join(projectRoot, "rollup.config.js"));
|
||||||
|
|
||||||
|
function warn(message) {
|
||||||
|
console.warn('Warning: ' + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceInFile(fileName, replacements) {
|
||||||
|
if (fs.existsSync(fileName)) {
|
||||||
|
let contents = fs.readFileSync(fileName, 'utf8');
|
||||||
|
let hadUpdates = false;
|
||||||
|
|
||||||
|
replacements.forEach(([from, to]) => {
|
||||||
|
const newContents = contents.replace(from, to);
|
||||||
|
|
||||||
|
const isAlreadyApplied = typeof to !== 'string' || contents.includes(to);
|
||||||
|
|
||||||
|
if (newContents !== contents) {
|
||||||
|
contents = newContents;
|
||||||
|
hadUpdates = true;
|
||||||
|
} else if (!isAlreadyApplied) {
|
||||||
|
warn(`Wanted to update "${from}" in ${fileName}, but did not find it.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hadUpdates) {
|
||||||
|
fs.writeFileSync(fileName, contents);
|
||||||
|
} else {
|
||||||
|
console.log(`${fileName} had already been updated.`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn(`Wanted to update ${fileName} but the file did not exist.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFile(fileName, contents) {
|
||||||
|
if (fs.existsSync(fileName)) {
|
||||||
|
warn(`Wanted to create ${fileName}, but it already existed. Leaving existing file.`);
|
||||||
|
} else {
|
||||||
|
fs.writeFileSync(fileName, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDepsToPackageJson() {
|
||||||
|
const pkgJSONPath = path.join(projectRoot, 'package.json');
|
||||||
|
const packageJSON = JSON.parse(fs.readFileSync(pkgJSONPath, 'utf8'));
|
||||||
|
packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
|
||||||
|
...(isRollup ? { '@rollup/plugin-typescript': '^6.0.0' } : { 'ts-loader': '^8.0.4' }),
|
||||||
|
'@tsconfig/svelte': '^1.0.10',
|
||||||
|
'@types/compression': '^1.7.0',
|
||||||
|
'@types/node': '^14.11.1',
|
||||||
|
'@types/polka': '^0.5.1',
|
||||||
|
'svelte-check': '^1.0.46',
|
||||||
|
'svelte-preprocess': '^4.3.0',
|
||||||
|
tslib: '^2.0.1',
|
||||||
|
typescript: '^4.0.3'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add script for checking
|
||||||
|
packageJSON.scripts = Object.assign(packageJSON.scripts, {
|
||||||
|
validate: 'svelte-check --ignore src/node_modules/@sapper'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Write the package JSON
|
||||||
|
fs.writeFileSync(pkgJSONPath, JSON.stringify(packageJSON, null, ' '));
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeJsExtensionToTs(dir) {
|
||||||
|
const elements = fs.readdirSync(dir, { withFileTypes: true });
|
||||||
|
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
if (elements[i].isDirectory()) {
|
||||||
|
changeJsExtensionToTs(path.join(dir, elements[i].name));
|
||||||
|
} else if (elements[i].name.match(/^[^_]((?!json).)*js$/)) {
|
||||||
|
fs.renameSync(path.join(dir, elements[i].name), path.join(dir, elements[i].name).replace('.js', '.ts'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSingleSvelteFile({ view, vars, contextModule }) {
|
||||||
|
replaceInFile(path.join(projectRoot, 'src', `${view}.svelte`), [
|
||||||
|
[/(?:<script)(( .*?)*?)>/gm, (m, attrs) => `<script${attrs}${!attrs.includes('lang="ts"') ? ' lang="ts"' : ''}>`],
|
||||||
|
...(vars ? vars.map(({ name, type }) => [`export let ${name};`, `export let ${name}: ${type};`]) : []),
|
||||||
|
...(contextModule ? contextModule.map(({ js, ts }) => [js, ts]) : [])
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch the *.svelte file to use TS
|
||||||
|
function updateSvelteFiles() {
|
||||||
|
[
|
||||||
|
{
|
||||||
|
view: 'components/Nav',
|
||||||
|
vars: [{ name: 'segment', type: 'string' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
view: 'routes/_layout',
|
||||||
|
vars: [{ name: 'segment', type: 'string' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
view: 'routes/_error',
|
||||||
|
vars: [
|
||||||
|
{ name: 'status', type: 'number' },
|
||||||
|
{ name: 'error', type: 'Error' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
view: 'routes/blog/index',
|
||||||
|
vars: [{ name: 'posts', type: '{ slug: string; title: string, html: any }[]' }],
|
||||||
|
contextModule: [
|
||||||
|
{
|
||||||
|
js: '.then(r => r.json())',
|
||||||
|
ts: '.then((r: { json: () => any; }) => r.json())'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
js: '.then(posts => {',
|
||||||
|
ts: '.then((posts: { slug: string; title: string, html: any }[]) => {'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
view: 'routes/blog/[slug]',
|
||||||
|
vars: [{ name: 'post', type: '{ slug: string; title: string, html: any }' }]
|
||||||
|
}
|
||||||
|
].forEach(updateSingleSvelteFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateRollupConfig() {
|
||||||
|
// Edit rollup config
|
||||||
|
replaceInFile(path.join(projectRoot, 'rollup.config.js'), [
|
||||||
|
// Edit imports
|
||||||
|
[
|
||||||
|
/'rollup-plugin-terser';\n(?!import sveltePreprocess)/,
|
||||||
|
`'rollup-plugin-terser';
|
||||||
|
import sveltePreprocess from 'svelte-preprocess';
|
||||||
|
import typescript from '@rollup/plugin-typescript';
|
||||||
|
`
|
||||||
|
],
|
||||||
|
// Edit inputs
|
||||||
|
[
|
||||||
|
/(?<!THIS_IS_UNDEFINED[^\n]*\n\s*)onwarn\(warning\);/,
|
||||||
|
`(warning.code === 'THIS_IS_UNDEFINED') ||\n\tonwarn(warning);`
|
||||||
|
],
|
||||||
|
[/input: config.client.input\(\)(?!\.replace)/, `input: config.client.input().replace(/\\.js$/, '.ts')`],
|
||||||
|
[
|
||||||
|
/input: config.server.input\(\)(?!\.replace)/,
|
||||||
|
`input: { server: config.server.input().server.replace(/\\.js$/, ".ts") }`
|
||||||
|
],
|
||||||
|
[
|
||||||
|
/input: config.serviceworker.input\(\)(?!\.replace)/,
|
||||||
|
`input: config.serviceworker.input().replace(/\\.js$/, '.ts')`
|
||||||
|
],
|
||||||
|
// Add preprocess
|
||||||
|
[/compilerOptions/g, 'preprocess: sveltePreprocess({ sourceMap: dev }),\n\t\t\t\tcompilerOptions'],
|
||||||
|
// Add TypeScript
|
||||||
|
[/commonjs\(\)(?!,\n\s*typescript)/g, 'commonjs(),\n\t\t\ttypescript({ sourceMap: dev })']
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateWebpackConfig() {
|
||||||
|
// Edit webpack config
|
||||||
|
replaceInFile(path.join(projectRoot, 'webpack.config.js'), [
|
||||||
|
// Edit imports
|
||||||
|
[
|
||||||
|
/require\('webpack-modules'\);\n(?!const sveltePreprocess)/,
|
||||||
|
`require('webpack-modules');\nconst sveltePreprocess = require('svelte-preprocess');\n`
|
||||||
|
],
|
||||||
|
// Edit extensions
|
||||||
|
[
|
||||||
|
/\['\.mjs', '\.js', '\.json', '\.svelte', '\.html'\]/,
|
||||||
|
`['.mjs', '.js', '.ts', '.json', '.svelte', '.html']`
|
||||||
|
],
|
||||||
|
// Edit entries
|
||||||
|
[
|
||||||
|
/entry: config\.client\.entry\(\)/,
|
||||||
|
`entry: { main: config.client.entry().main.replace(/\\.js$/, '.ts') }`
|
||||||
|
],
|
||||||
|
[
|
||||||
|
/entry: config\.server\.entry\(\)/,
|
||||||
|
`entry: { server: config.server.entry().server.replace(/\\.js$/, '.ts') }`
|
||||||
|
],
|
||||||
|
[
|
||||||
|
/entry: config\.serviceworker\.entry\(\)/,
|
||||||
|
`entry: { 'service-worker': config.serviceworker.entry()['service-worker'].replace(/\\.js$/, '.ts') }`
|
||||||
|
],
|
||||||
|
[
|
||||||
|
/loader: 'svelte-loader',\n\t\t\t\t\t\toptions: {/g,
|
||||||
|
'loader: \'svelte-loader\',\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tpreprocess: sveltePreprocess({ sourceMap: dev }),'
|
||||||
|
],
|
||||||
|
// Add TypeScript rules for client and server
|
||||||
|
[
|
||||||
|
/module: {\n\s*rules: \[\n\s*(?!{\n\s*test: \/\\\.ts\$\/)/g,
|
||||||
|
`module: {\n\t\t\trules: [\n\t\t\t\t{\n\t\t\t\t\ttest: /\\.ts$/,\n\t\t\t\t\tloader: 'ts-loader'\n\t\t\t\t},\n\t\t\t\t`
|
||||||
|
],
|
||||||
|
// Add TypeScript rules for serviceworker
|
||||||
|
[
|
||||||
|
/output: config\.serviceworker\.output\(\),\n\s*(?!module)/,
|
||||||
|
`output: config.serviceworker.output(),\n\t\tmodule: {\n\t\t\trules: [\n\t\t\t\t{\n\t\t\t\t\ttest: /\\.ts$/,\n\t\t\t\t\tloader: 'ts-loader'\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t`
|
||||||
|
],
|
||||||
|
// Edit outputs
|
||||||
|
[
|
||||||
|
/output: config\.serviceworker\.output\(\),\n\s*(?!resolve)/,
|
||||||
|
`output: config.serviceworker.output(),\n\t\tresolve: { extensions: ['.mjs', '.js', '.ts', '.json'] },\n\t\t`
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateServiceWorker() {
|
||||||
|
replaceInFile(path.join(projectRoot, 'src', 'service-worker.ts'), [
|
||||||
|
[`shell.concat(files);`, `(shell as string[]).concat(files as string[]);`],
|
||||||
|
[`self.skipWaiting();`, `((self as any) as ServiceWorkerGlobalScope).skipWaiting();`],
|
||||||
|
[`self.clients.claim();`, `((self as any) as ServiceWorkerGlobalScope).clients.claim();`],
|
||||||
|
[`fetchAndCache(request)`, `fetchAndCache(request: Request)`],
|
||||||
|
[`self.addEventListener('activate', event =>`, `self.addEventListener('activate', (event: ExtendableEvent) =>`],
|
||||||
|
[`self.addEventListener('install', event =>`, `self.addEventListener('install', (event: ExtendableEvent) =>`],
|
||||||
|
[`addEventListener('fetch', event =>`, `addEventListener('fetch', (event: FetchEvent) =>`],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTsConfig() {
|
||||||
|
const tsconfig = `{
|
||||||
|
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": ["DOM", "ES2017", "WebWorker"]
|
||||||
|
},
|
||||||
|
"include": ["src/**/*", "src/node_modules/**/*"],
|
||||||
|
"exclude": ["node_modules/*", "__sapper__/*", "static/*"]
|
||||||
|
}`;
|
||||||
|
|
||||||
|
createFile(path.join(projectRoot, 'tsconfig.json'), tsconfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds the extension recommendation
|
||||||
|
function configureVsCode() {
|
||||||
|
const dir = path.join(projectRoot, '.vscode');
|
||||||
|
|
||||||
|
if (!fs.existsSync(dir)) {
|
||||||
|
fs.mkdirSync(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
createFile(path.join(projectRoot, '.vscode', 'extensions.json'), `{"recommendations": ["svelte.svelte-vscode"]}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteThisScript() {
|
||||||
|
fs.unlinkSync(path.join(__filename));
|
||||||
|
|
||||||
|
// Check for Mac's DS_store file, and if it's the only one left remove it
|
||||||
|
const remainingFiles = fs.readdirSync(path.join(__dirname));
|
||||||
|
if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') {
|
||||||
|
fs.unlinkSync(path.join(__dirname, '.DS_store'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the scripts folder is empty
|
||||||
|
if (fs.readdirSync(path.join(__dirname)).length === 0) {
|
||||||
|
// Remove the scripts folder
|
||||||
|
fs.rmdirSync(path.join(__dirname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Adding TypeScript with ${isRollup ? "Rollup" : "webpack" }...`);
|
||||||
|
|
||||||
|
addDepsToPackageJson();
|
||||||
|
|
||||||
|
changeJsExtensionToTs(path.join(projectRoot, 'src'));
|
||||||
|
|
||||||
|
updateSvelteFiles();
|
||||||
|
|
||||||
|
if (isRollup) {
|
||||||
|
updateRollupConfig();
|
||||||
|
} else {
|
||||||
|
updateWebpackConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateServiceWorker();
|
||||||
|
|
||||||
|
createTsConfig();
|
||||||
|
|
||||||
|
configureVsCode();
|
||||||
|
|
||||||
|
// Delete this script, but not during testing
|
||||||
|
if (!argv[2]) {
|
||||||
|
deleteThisScript();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Converted to TypeScript.');
|
||||||
|
|
||||||
|
if (fs.existsSync(path.join(projectRoot, 'node_modules'))) {
|
||||||
|
console.log(`
|
||||||
|
Next:
|
||||||
|
1. run 'npm install' again to install TypeScript dependencies
|
||||||
|
2. run 'npm run build' for the @sapper imports in your project to work
|
||||||
|
`);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
/target/
|
||||||
|
WixTools
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
[package]
|
||||||
|
name = "app"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "A Tauri App"
|
||||||
|
authors = ["you"]
|
||||||
|
license = ""
|
||||||
|
repository = ""
|
||||||
|
default-run = "app"
|
||||||
|
edition = "2018"
|
||||||
|
build = "src/build.rs"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
tauri-build = { version = "1.0.0-beta.2" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde_json = "1.0"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
tauri = { version = "1.0.0-beta.4", features = [] }
|
||||||
|
tokio = "1.4"
|
||||||
|
url = "2.2"
|
||||||
|
|
||||||
|
coconut-interface = { path = "../../../common/coconut-interface" }
|
||||||
|
credentials = { path = "../../../common/credentials" }
|
||||||
|
validator-client = {path = "../../../common/client-libs/validator-client"}
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["custom-protocol"]
|
||||||
|
custom-protocol = ["tauri/custom-protocol"]
|
||||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 4.4 KiB |