Compare commits
571 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ca8cdcf5a | |||
| c8f2548090 | |||
| 62f20a905e | |||
| a3dd94507a | |||
| dd36b329d5 | |||
| 581af4a295 | |||
| 085761a9fb | |||
| 58537224df | |||
| 78a5dbbf05 | |||
| ab7f24dc1f | |||
| 289605f36b | |||
| 4f6bf3423b | |||
| 04a32156d4 | |||
| 427880d23f | |||
| a5e47dead8 | |||
| 297b7b2355 | |||
| d7f3abfe7d | |||
| 234952a6bb | |||
| 930561faf5 | |||
| 17507bc8c5 | |||
| 12f8e453ea | |||
| 97ef024b8a | |||
| 3dc94223ae | |||
| 50cd18a926 | |||
| e5051f98c5 | |||
| 2f69958e21 | |||
| d427591a66 | |||
| 0257c42ee9 | |||
| 8ebfc72da8 | |||
| 897d51cba0 | |||
| 1f1d91bd1e | |||
| 9d63a30b07 | |||
| 5b22b1c298 | |||
| 0302d9ae5d | |||
| eb6949528a | |||
| 41b77c3ad5 | |||
| 2f78f5eb26 | |||
| cdbd731f10 | |||
| 5cb4949d46 | |||
| 9ec0b30812 | |||
| 7e1cf2f105 | |||
| 04636a569a | |||
| 52f5b980a4 | |||
| 0e4f833715 | |||
| d22914c4dc | |||
| 7d506e6e2a | |||
| c7007de1ea | |||
| 10bf70b22b | |||
| d952f3233a | |||
| b1178b7ad5 | |||
| 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 | |||
| b4ef0ae4f3 | |||
| d9087bf2a9 | |||
| 2f29ee49db | |||
| abc5a58b19 | |||
| 01d7e3a5f2 | |||
| ea08fad2e0 | |||
| a47bbf1e67 | |||
| 1fe38b1b9c | |||
| ed489149dc | |||
| 190d3c4972 | |||
| ea62d01e65 | |||
| 97156c918b | |||
| d79013f1c1 | |||
| b69b221e62 | |||
| 266138dcf2 | |||
| a8299e867d | |||
| 7dc4d653c2 | |||
| 2f9e67e8b2 | |||
| 2c058bcbca | |||
| 528eba2faa | |||
| 7f7c37eeba | |||
| 18adb1f5bd | |||
| a521bc0f54 | |||
| 6f173ffebd | |||
| 7e31cbabe5 | |||
| e8e966b67a | |||
| 73af405400 | |||
| 037723eb90 | |||
| d432bebce8 | |||
| 0a3cffa1a1 | |||
| 796107c4c5 | |||
| fd0df9fe47 | |||
| 58a7f4ea5f | |||
| 725b8d6f8a | |||
| e5a1c1c97e | |||
| b894dbf243 | |||
| 92821c8d81 | |||
| af8360f363 | |||
| 8b12a31f73 | |||
| fd55eb678c | |||
| bb3ce645a4 | |||
| 4e339f1788 | |||
| dca9c7079c | |||
| 52a8909e77 | |||
| 9d2c445bb7 | |||
| 6a1c2fa5dd | |||
| 809c3f3607 | |||
| bebf0df2de | |||
| 5652eb7ee3 | |||
| b6ba8f8555 | |||
| 22bfd44065 | |||
| 3136346a01 | |||
| f536449f0c | |||
| 7659424f28 | |||
| eff40dd907 | |||
| 800af218a5 | |||
| f5c1b6dfdd | |||
| dfdfba5d2f | |||
| 047a483464 | |||
| 4a908e7e14 | |||
| bcf25135a1 | |||
| 087efbe553 | |||
| 2be0ab6474 | |||
| 9a1abfad9c | |||
| f7f119b100 | |||
| bd78f8833f | |||
| 4a081d6fa7 | |||
| 42268e044c | |||
| 48dda32c3e | |||
| a21ed92ac3 | |||
| ee71ae89f7 | |||
| a97377fdea | |||
| 1d4420820f | |||
| 596bc76cc6 | |||
| cc1b80229c | |||
| f07ac48a33 | |||
| 8abfc43fc8 | |||
| 7361d7a220 | |||
| 52d4ddb714 | |||
| ca60b8671c | |||
| 9e0bb80163 | |||
| ce7dcbc163 | |||
| cf93afb639 | |||
| 1119a9e55f | |||
| 51d2213819 | |||
| b567ee55f3 | |||
| 5ef77185a1 | |||
| 4ae8ae7231 | |||
| 2e7cd451ec | |||
| d301694404 | |||
| 752bce589b | |||
| 67c92b3e56 | |||
| d3570df968 | |||
| 261993ea90 | |||
| 0ae29eb5fa | |||
| 87408d4b7b | |||
| 503f723a64 | |||
| 9c72aac255 | |||
| 34a143696f | |||
| de22936ed1 | |||
| 9da9c95c80 | |||
| a7fe4697c5 | |||
| 1d9bced599 | |||
| a854118f19 | |||
| d496ee3031 | |||
| f29dd884f3 | |||
| e1181f756c | |||
| 4ca40fd3bc | |||
| 6483a62a7c | |||
| 83753af944 | |||
| 6f8ae53f0c | |||
| 2f867b75f2 | |||
| ea31e18d98 | |||
| d03af9de05 | |||
| 4013d0c939 | |||
| 3a261d22f5 | |||
| 2314baf0d3 | |||
| c882778583 | |||
| c67e0fee37 | |||
| 863aa4535a | |||
| 86c9ab2ef5 | |||
| 12faa23222 | |||
| 9cd463b22c | |||
| d7ec81ad0a | |||
| 2d3b4f4b91 | |||
| 131574cd3c | |||
| 8b29c612f8 | |||
| 9c67b73472 | |||
| 6b37a9b95c | |||
| 67ac1d9f4b | |||
| 28410eedad | |||
| 0fb182ccb9 | |||
| 7953e36e82 | |||
| 9cea2777d4 | |||
| 46d3591a4f | |||
| 5fc81db0d9 | |||
| fbdca2dcd5 | |||
| afb7825135 |
@@ -1,2 +1,5 @@
|
|||||||
|
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
RUST_LOG=info
|
RUST_LOG=info
|
||||||
RUST_BACKTRACE=1
|
RUST_BACKTRACE=1
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
name: Continuous integration
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
|
||||||
|
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/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'
|
||||||
|
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
override: true
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Build all binaries
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
args: --all
|
||||||
|
|
||||||
|
- name: Run all tests
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --all
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --all -- --check
|
||||||
|
|
||||||
|
- 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:
|
||||||
|
command: clippy
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
name: Mixnet Contract
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
|
||||||
|
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`]'
|
||||||
|
mixnet-contract:
|
||||||
|
# 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' }}
|
||||||
|
needs: matrix_prep
|
||||||
|
strategy:
|
||||||
|
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||||
|
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/mixnet/Cargo.toml --target wasm32-unknown-unknown
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --manifest-path contracts/mixnet/Cargo.toml
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --manifest-path contracts/mixnet/Cargo.toml -- --check
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
|
with:
|
||||||
|
command: clippy
|
||||||
|
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 }}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
name: Wasm Client
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths-ignore:
|
||||||
|
- 'explorer/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
wasm:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
target: wasm32-unknown-unknown
|
||||||
|
override: true
|
||||||
|
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
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
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
|
||||||
|
# - uses: actions-rs/cargo@v1
|
||||||
|
# with:
|
||||||
|
# command: test
|
||||||
|
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --manifest-path clients/webassembly/Cargo.toml -- --check
|
||||||
|
|
||||||
|
# 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
|
||||||
|
# with:
|
||||||
|
# command: clippy
|
||||||
|
# args: --manifest-path clients/webassembly/Cargo.toml --target wasm32-unknown-unknown -- -D warnings
|
||||||
+14
-1
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
/targetString
|
/targetString
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
/*/target
|
/*/target
|
||||||
@@ -8,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
|
||||||
@@ -22,3 +24,14 @@ v6-topology.json
|
|||||||
/explorer/downloads/topology.json
|
/explorer/downloads/topology.json
|
||||||
/explorer/public/downloads/mixmining.json
|
/explorer/public/downloads/mixmining.json
|
||||||
/explorer/public/downloads/topology.json
|
/explorer/public/downloads/topology.json
|
||||||
|
/nym-wallet/dist/*
|
||||||
|
/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
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: nym
|
||||||
|
Upstream-Contact: Nym Technologies SA <contact@nymtech.net>
|
||||||
|
Source: https://github.com/nymtech/nym
|
||||||
|
|
||||||
|
|
||||||
|
Files: *clients/* *common/* *explorer/*
|
||||||
|
Copyright: 2020, Nym Technologies SA <contact@nymtech.net>
|
||||||
|
License: Apache-2.0
|
||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
language: rust
|
|
||||||
rust:
|
|
||||||
- stable
|
|
||||||
- beta
|
|
||||||
- nightly
|
|
||||||
jobs:
|
|
||||||
allow_failures:
|
|
||||||
- rust: nightly
|
|
||||||
fast_finish: true
|
|
||||||
before_script:
|
|
||||||
- rustup component add rustfmt
|
|
||||||
script:
|
|
||||||
- cargo build
|
|
||||||
- cargo test --all
|
|
||||||
- cargo fmt -- --check
|
|
||||||
+267
-13
@@ -1,5 +1,258 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [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)
|
||||||
|
|
||||||
|
**Closed issues:**
|
||||||
|
|
||||||
|
- Prometheus metrics doesn't work [\#606](https://github.com/nymtech/nym/issues/606)
|
||||||
|
- Bonding hostname vs. ip-address does not show up on NYM explorer [\#593](https://github.com/nymtech/nym/issues/593)
|
||||||
|
- Cannot assign requested address [\#584](https://github.com/nymtech/nym/issues/584)
|
||||||
|
- Native client upgrade command is broken [\#582](https://github.com/nymtech/nym/issues/582)
|
||||||
|
- Spread directory requests across good validators [\#580](https://github.com/nymtech/nym/issues/580)
|
||||||
|
- Change network monitor to use currency-based rewareds [\#540](https://github.com/nymtech/nym/issues/540)
|
||||||
|
- Unregistration for protocol ipv6 does not work [\#511](https://github.com/nymtech/nym/issues/511)
|
||||||
|
- Network monitor view on validators [\#373](https://github.com/nymtech/nym/issues/373)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Bugfix/unique node ownership [\#612](https://github.com/nymtech/nym/pull/612) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Decreased log severity for verloc-related functionalities [\#611](https://github.com/nymtech/nym/pull/611) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Disabled metrics reporting to the central server [\#609](https://github.com/nymtech/nym/pull/609) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/network monitor gateway pings [\#608](https://github.com/nymtech/nym/pull/608) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Implemented display traits for identity and encryption keys [\#607](https://github.com/nymtech/nym/pull/607) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/add node description api [\#605](https://github.com/nymtech/nym/pull/605) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/updated network monitor [\#604](https://github.com/nymtech/nym/pull/604) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/ping timings [\#603](https://github.com/nymtech/nym/pull/603) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bump lodash from 4.17.20 to 4.17.21 in /clients/validator [\#602](https://github.com/nymtech/nym/pull/602) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump lodash from 4.17.20 to 4.17.21 in /clients/native/examples/js-examples/websocket [\#601](https://github.com/nymtech/nym/pull/601) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Feature/add rocket [\#600](https://github.com/nymtech/nym/pull/600) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Bump url-parse from 1.4.7 to 1.5.1 in /clients/native/examples/js-examples/websocket [\#599](https://github.com/nymtech/nym/pull/599) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump url-parse from 1.4.7 to 1.5.1 in /clients/webassembly/js-example [\#598](https://github.com/nymtech/nym/pull/598) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Recalculating reward rates on appropriate value changes [\#594](https://github.com/nymtech/nym/pull/594) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Changed default mixnode query page limit [\#592](https://github.com/nymtech/nym/pull/592) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/more exposed client api [\#591](https://github.com/nymtech/nym/pull/591) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Contract adjustment to check for node ownership before allowing bonding [\#590](https://github.com/nymtech/nym/pull/590) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bump ssri from 6.0.1 to 6.0.2 in /clients/webassembly/js-example [\#589](https://github.com/nymtech/nym/pull/589) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump ssri from 6.0.1 to 6.0.2 in /clients/native/examples/js-examples/websocket [\#588](https://github.com/nymtech/nym/pull/588) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Impl Error trait for ValidatorClientError [\#587](https://github.com/nymtech/nym/pull/587) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Checking for tx success when sending coins [\#586](https://github.com/nymtech/nym/pull/586) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Logging adjustment [\#585](https://github.com/nymtech/nym/pull/585) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/multiple validator endpoints [\#583](https://github.com/nymtech/nym/pull/583) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Refreshing nodes gets all available nodes from the contract [\#575](https://github.com/nymtech/nym/pull/575) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/simple payments [\#571](https://github.com/nymtech/nym/pull/571) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Minor cosmetic changes while reading around [\#568](https://github.com/nymtech/nym/pull/568) ([huitseeker](https://github.com/huitseeker))
|
||||||
|
|
||||||
|
## [v0.10.0](https://github.com/nymtech/nym/tree/v0.10.0) (2021-04-15)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/nymtech/nym/compare/validator-client-0.10.0-rc1...v0.10.0)
|
||||||
|
|
||||||
|
This release brings a distributed directory authority powered by [Cosmos SDK](https://cosmos.network) and [CosmWasm](https://cosmwasm.com) smart contracts. It is designed to run [Testnet Finney](https://testnet-finney-explorer.nymtech.net), the new Nym testnet.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
**Closed issues:**
|
||||||
|
|
||||||
|
- When I run this command :'./nym-mixnode run --id zzznym', an error occurs [\#548](https://github.com/nymtech/nym/issues/548)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Displaying address of the client on init [\#573](https://github.com/nymtech/nym/pull/573) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Fixed nightly clippy warnings [\#572](https://github.com/nymtech/nym/pull/572) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Changed default client topology refresh rate from 30s to 5min [\#570](https://github.com/nymtech/nym/pull/570) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Adding the wallet url in startup instructions [\#569](https://github.com/nymtech/nym/pull/569) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Removed unused data from cargo.toml [\#567](https://github.com/nymtech/nym/pull/567) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/cli signing [\#566](https://github.com/nymtech/nym/pull/566) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Updated version number on the validator client [\#565](https://github.com/nymtech/nym/pull/565) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Renamed mixnode registration into bonding [\#564](https://github.com/nymtech/nym/pull/564) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- A pull request for discussion about contract state variables [\#563](https://github.com/nymtech/nym/pull/563) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/mixnet contract ci [\#562](https://github.com/nymtech/nym/pull/562) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/bonding adjustments [\#561](https://github.com/nymtech/nym/pull/561) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/migration additions [\#560](https://github.com/nymtech/nym/pull/560) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Changed default contract execution gas limit to 250\_000 \(from 9\_000\_000\_000\) [\#559](https://github.com/nymtech/nym/pull/559) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Missing quotes in mixnet\_contract\_address config field [\#558](https://github.com/nymtech/nym/pull/558) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Updated default validator url and contract address [\#557](https://github.com/nymtech/nym/pull/557) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bump y18n from 4.0.0 to 4.0.1 in /clients/native/examples/js-examples/websocket [\#556](https://github.com/nymtech/nym/pull/556) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Feature/bonding info on init [\#555](https://github.com/nymtech/nym/pull/555) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/validator client address getter [\#554](https://github.com/nymtech/nym/pull/554) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Added extra step for publishing validator client [\#553](https://github.com/nymtech/nym/pull/553) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/validator client rc3 [\#552](https://github.com/nymtech/nym/pull/552) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/upgrade update [\#551](https://github.com/nymtech/nym/pull/551) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/export coin helper [\#550](https://github.com/nymtech/nym/pull/550) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Chore/dependency updates [\#549](https://github.com/nymtech/nym/pull/549) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/validator query client [\#547](https://github.com/nymtech/nym/pull/547) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/validator client rc2 [\#546](https://github.com/nymtech/nym/pull/546) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/has node query validator client [\#545](https://github.com/nymtech/nym/pull/545) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Added contract query to check if given address owns a mixnode/gateway [\#544](https://github.com/nymtech/nym/pull/544) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
|
||||||
|
## [validator-client-0.10.0-rc1](https://github.com/nymtech/nym/tree/validator-client-0.10.0-rc1) (2021-03-24)
|
||||||
|
|
||||||
|
[Full Changelog](https://github.com/nymtech/nym/compare/v0.9.2...validator-client-0.10.0-rc1)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add option to whitelist IPv4 ranges to allowed.list in sphinx-socks [\#415](https://github.com/nymtech/nym/issues/415)
|
||||||
|
- Mixmining monitoring for gateways [\#384](https://github.com/nymtech/nym/issues/384)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Network requester should periodically remove stale proxies [\#424](https://github.com/nymtech/nym/issues/424)
|
||||||
|
- Network requester now prints correct version with --version [\#478](https://github.com/nymtech/nym/pull/478) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
|
||||||
|
**Closed issues:**
|
||||||
|
|
||||||
|
- Change topology to work with validators. [\#538](https://github.com/nymtech/nym/issues/538)
|
||||||
|
- Unable to rejoin the network after powerdown [\#514](https://github.com/nymtech/nym/issues/514)
|
||||||
|
- nym-socks5-client 0.9.2 issue with outbound\_request\_filter.check [\#498](https://github.com/nymtech/nym/issues/498)
|
||||||
|
- nym-socks5-client high CPU usage on idle [\#491](https://github.com/nymtech/nym/issues/491)
|
||||||
|
- network requester too many Received a 'Send' before 'Connect' - going to buffer the data [\#483](https://github.com/nymtech/nym/issues/483)
|
||||||
|
- Socks5 client loops on malformed - invalidaddress message [\#482](https://github.com/nymtech/nym/issues/482)
|
||||||
|
- Socks5 client hangs [\#479](https://github.com/nymtech/nym/issues/479)
|
||||||
|
- Network Requester -V flag does not print version [\#469](https://github.com/nymtech/nym/issues/469)
|
||||||
|
- Gateway reconnection \(wasm\) [\#458](https://github.com/nymtech/nym/issues/458)
|
||||||
|
- Client warning 'No valid topology' [\#343](https://github.com/nymtech/nym/issues/343)
|
||||||
|
- private key file permission bits too open, readable for others [\#319](https://github.com/nymtech/nym/issues/319)
|
||||||
|
- Fix dependabot security notice [\#267](https://github.com/nymtech/nym/issues/267)
|
||||||
|
- Change how time intervals are serialized in configs [\#141](https://github.com/nymtech/nym/issues/141)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- RC1 published [\#543](https://github.com/nymtech/nym/pull/543) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/prep for publish [\#542](https://github.com/nymtech/nym/pull/542) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/bigger better stronger mnemonics [\#541](https://github.com/nymtech/nym/pull/541) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Removed a package-lock.json which seems to have been accidentally added [\#539](https://github.com/nymtech/nym/pull/539) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/convert to uhal [\#537](https://github.com/nymtech/nym/pull/537) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/topology conversion [\#536](https://github.com/nymtech/nym/pull/536) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/hook up url in validator client [\#535](https://github.com/nymtech/nym/pull/535) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/upgrade cosm client [\#534](https://github.com/nymtech/nym/pull/534) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/mix contract identity key [\#533](https://github.com/nymtech/nym/pull/533) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/validator client rust [\#532](https://github.com/nymtech/nym/pull/532) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/add currency helpers [\#531](https://github.com/nymtech/nym/pull/531) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Exporting Coin struct, needed for wallet [\#530](https://github.com/nymtech/nym/pull/530) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Getting correct user home dir in Python setup script [\#528](https://github.com/nymtech/nym/pull/528) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Temporarily disabling fs access [\#527](https://github.com/nymtech/nym/pull/527) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/validator client gateway bonding [\#526](https://github.com/nymtech/nym/pull/526) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Fixed eslint errors in the validator client [\#525](https://github.com/nymtech/nym/pull/525) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/gateway bonding [\#524](https://github.com/nymtech/nym/pull/524) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Fix the remove mixnode test [\#522](https://github.com/nymtech/nym/pull/522) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Bump elliptic from 6.5.3 to 6.5.4 in /clients/native/examples/js-examples/websocket [\#521](https://github.com/nymtech/nym/pull/521) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Feature/fix go errors in examples [\#516](https://github.com/nymtech/nym/pull/516) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Feature/initial mixnet contract [\#515](https://github.com/nymtech/nym/pull/515) ([futurechimp](https://github.com/futurechimp))
|
||||||
|
- Running CI also on windows and macOS [\#512](https://github.com/nymtech/nym/pull/512) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/socks5 adjustments [\#510](https://github.com/nymtech/nym/pull/510) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Fixed unused import in non-unix systems [\#509](https://github.com/nymtech/nym/pull/509) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Checking if the delay has already expired before attempting to put it… [\#508](https://github.com/nymtech/nym/pull/508) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Not including gateway non-delay when calculating total packet delay [\#507](https://github.com/nymtech/nym/pull/507) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Allowing for a single topology refresh failure [\#505](https://github.com/nymtech/nym/pull/505) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- More restrictive unix key files permissions [\#504](https://github.com/nymtech/nym/pull/504) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- More human-readable errors on mixnode/gateway startup [\#503](https://github.com/nymtech/nym/pull/503) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/ip filtering [\#502](https://github.com/nymtech/nym/pull/502) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/wasm client compilation fixes [\#501](https://github.com/nymtech/nym/pull/501) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Fixed possible crash on invalid topology [\#500](https://github.com/nymtech/nym/pull/500) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/gateway monitoring [\#499](https://github.com/nymtech/nym/pull/499) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/GitHub actions and clippy cleanup [\#493](https://github.com/nymtech/nym/pull/493) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Fix typos [\#492](https://github.com/nymtech/nym/pull/492) ([rex4539](https://github.com/rex4539))
|
||||||
|
- Bump ini from 1.3.5 to 1.3.8 in /clients/native/examples/js-examples/websocket [\#490](https://github.com/nymtech/nym/pull/490) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- Bump ini from 1.3.5 to 1.3.8 in /clients/webassembly/js-example [\#489](https://github.com/nymtech/nym/pull/489) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
|
- display 0 on no validators rather than crash [\#488](https://github.com/nymtech/nym/pull/488) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- NGI0 - Updating licensing aspects according REUSE [\#487](https://github.com/nymtech/nym/pull/487) ([lnceballosz](https://github.com/lnceballosz))
|
||||||
|
- Feature/removed topology [\#481](https://github.com/nymtech/nym/pull/481) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Bugfix/explorer fixes [\#477](https://github.com/nymtech/nym/pull/477) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
- Feature/0.9.2+only monitoring [\#475](https://github.com/nymtech/nym/pull/475) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
|
||||||
## [v0.9.2](https://github.com/nymtech/nym/tree/v0.9.2) (2020-11-26)
|
## [v0.9.2](https://github.com/nymtech/nym/tree/v0.9.2) (2020-11-26)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/nymtech/nym/compare/v0.9.1...v0.9.2)
|
[Full Changelog](https://github.com/nymtech/nym/compare/v0.9.1...v0.9.2)
|
||||||
@@ -12,6 +265,7 @@ This release brings networking improvements, eliminating blocking calls and impr
|
|||||||
|
|
||||||
**Merged pull requests:**
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Release/v0.9.2 [\#474](https://github.com/nymtech/nym/pull/474) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
- Minor mixnet client code simplification and optimization [\#472](https://github.com/nymtech/nym/pull/472) ([jstuczyn](https://github.com/jstuczyn))
|
- Minor mixnet client code simplification and optimization [\#472](https://github.com/nymtech/nym/pull/472) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
|
|
||||||
## [v0.9.1](https://github.com/nymtech/nym/tree/v0.9.1) (2020-11-24)
|
## [v0.9.1](https://github.com/nymtech/nym/tree/v0.9.1) (2020-11-24)
|
||||||
@@ -264,7 +518,6 @@ This release introduces, among other things, the following improvements:
|
|||||||
- could not count to ten properly [\#262](https://github.com/nymtech/nym/pull/262) ([ststefa](https://github.com/ststefa))
|
- could not count to ten properly [\#262](https://github.com/nymtech/nym/pull/262) ([ststefa](https://github.com/ststefa))
|
||||||
- build\(deps\): bump websocket-extensions from 0.1.3 to 0.1.4 in /clients/webassembly/js-example [\#261](https://github.com/nymtech/nym/pull/261) ([dependabot[bot]](https://github.com/apps/dependabot))
|
- build\(deps\): bump websocket-extensions from 0.1.3 to 0.1.4 in /clients/webassembly/js-example [\#261](https://github.com/nymtech/nym/pull/261) ([dependabot[bot]](https://github.com/apps/dependabot))
|
||||||
- add disabling feature 'offline-test' for network-dependent tests [\#260](https://github.com/nymtech/nym/pull/260) ([hyperfekt](https://github.com/hyperfekt))
|
- add disabling feature 'offline-test' for network-dependent tests [\#260](https://github.com/nymtech/nym/pull/260) ([hyperfekt](https://github.com/hyperfekt))
|
||||||
- Filtering compatible node versions [\#259](https://github.com/nymtech/nym/pull/259) ([jstuczyn](https://github.com/jstuczyn))
|
|
||||||
|
|
||||||
## [v0.7.0](https://github.com/nymtech/nym/tree/v0.7.0) (2020-06-08)
|
## [v0.7.0](https://github.com/nymtech/nym/tree/v0.7.0) (2020-06-08)
|
||||||
|
|
||||||
@@ -294,7 +547,7 @@ See the [changelog](https://github.com/nymtech/nym/blob/develop/CHANGELOG.md) fo
|
|||||||
**Closed issues:**
|
**Closed issues:**
|
||||||
|
|
||||||
- Move to userpubkey@gatewaypubkey addresses. [\#235](https://github.com/nymtech/nym/issues/235)
|
- Move to userpubkey@gatewaypubkey addresses. [\#235](https://github.com/nymtech/nym/issues/235)
|
||||||
- Get `start\_local\_network.sh` working with the js example [\#227](https://github.com/nymtech/nym/issues/227)
|
- Get `start_local_network.sh` working with the js example [\#227](https://github.com/nymtech/nym/issues/227)
|
||||||
- Fix indeterminate test failure [\#218](https://github.com/nymtech/nym/issues/218)
|
- Fix indeterminate test failure [\#218](https://github.com/nymtech/nym/issues/218)
|
||||||
- Remove 'fetch' mechanism from desktop client's client in favour of push [\#211](https://github.com/nymtech/nym/issues/211)
|
- Remove 'fetch' mechanism from desktop client's client in favour of push [\#211](https://github.com/nymtech/nym/issues/211)
|
||||||
- Mixnode - load Sphinx keys like Gateway [\#209](https://github.com/nymtech/nym/issues/209)
|
- Mixnode - load Sphinx keys like Gateway [\#209](https://github.com/nymtech/nym/issues/209)
|
||||||
@@ -319,15 +572,16 @@ See the [changelog](https://github.com/nymtech/nym/blob/develop/CHANGELOG.md) fo
|
|||||||
- Bring health-checker into validator mix-mining [\#78](https://github.com/nymtech/nym/issues/78)
|
- Bring health-checker into validator mix-mining [\#78](https://github.com/nymtech/nym/issues/78)
|
||||||
- Solidify TCPSocket on client [\#72](https://github.com/nymtech/nym/issues/72)
|
- Solidify TCPSocket on client [\#72](https://github.com/nymtech/nym/issues/72)
|
||||||
- scripts: run\_local\_network.sh doesn't die nicely [\#45](https://github.com/nymtech/nym/issues/45)
|
- scripts: run\_local\_network.sh doesn't die nicely [\#45](https://github.com/nymtech/nym/issues/45)
|
||||||
- WASM version of the Sphinx packet [\#19](https://github.com/nymtech/nym/issues/19)
|
|
||||||
- Persistent socket connection \(TCP Socket with provider\) [\#18](https://github.com/nymtech/nym/issues/18)
|
|
||||||
- Persistent socket connection \(Websocket with client\) [\#17](https://github.com/nymtech/nym/issues/17)
|
|
||||||
- Persistent socket connection \(TCP Socket with client\) [\#13](https://github.com/nymtech/nym/issues/13)
|
|
||||||
- Persistent socket connection \(Websocket with client\) [\#12](https://github.com/nymtech/nym/issues/12)
|
|
||||||
- Persistently store ledger with registered clients and their auth tokens [\#6](https://github.com/nymtech/nym/issues/6)
|
- Persistently store ledger with registered clients and their auth tokens [\#6](https://github.com/nymtech/nym/issues/6)
|
||||||
|
- Persistent socket connection \(Websocket with client\) [\#17](https://github.com/nymtech/nym/issues/17)
|
||||||
|
- Persistent socket connection \(TCP Socket with provider\) [\#18](https://github.com/nymtech/nym/issues/18)
|
||||||
|
- Persistent socket connection \(Websocket with client\) [\#12](https://github.com/nymtech/nym/issues/12)
|
||||||
|
- Persistent socket connection \(TCP Socket with client\) [\#13](https://github.com/nymtech/nym/issues/13)
|
||||||
|
- WASM version of the Sphinx packet [\#19](https://github.com/nymtech/nym/issues/19)
|
||||||
|
|
||||||
**Merged pull requests:**
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Filtering compatible node versions [\#259](https://github.com/nymtech/nym/pull/259) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
- systemd service unit example [\#257](https://github.com/nymtech/nym/pull/257) ([ststefa](https://github.com/ststefa))
|
- systemd service unit example [\#257](https://github.com/nymtech/nym/pull/257) ([ststefa](https://github.com/ststefa))
|
||||||
- renaming desktop to native client [\#251](https://github.com/nymtech/nym/pull/251) ([futurechimp](https://github.com/futurechimp))
|
- renaming desktop to native client [\#251](https://github.com/nymtech/nym/pull/251) ([futurechimp](https://github.com/futurechimp))
|
||||||
- Adding a pipenv dependencies file to the python client example [\#250](https://github.com/nymtech/nym/pull/250) ([futurechimp](https://github.com/futurechimp))
|
- Adding a pipenv dependencies file to the python client example [\#250](https://github.com/nymtech/nym/pull/250) ([futurechimp](https://github.com/futurechimp))
|
||||||
@@ -466,11 +720,11 @@ This release fixes bugs in v0.5.0. All testnet node operators are advised to up
|
|||||||
- Fix incorrectly used Arcs [\#47](https://github.com/nymtech/nym/issues/47)
|
- Fix incorrectly used Arcs [\#47](https://github.com/nymtech/nym/issues/47)
|
||||||
- nym-mixnode mandatory host option [\#26](https://github.com/nymtech/nym/issues/26)
|
- nym-mixnode mandatory host option [\#26](https://github.com/nymtech/nym/issues/26)
|
||||||
- Create config struct for mixnode \(possibly also for client\) [\#21](https://github.com/nymtech/nym/issues/21)
|
- Create config struct for mixnode \(possibly also for client\) [\#21](https://github.com/nymtech/nym/issues/21)
|
||||||
- Reuse TCP socket connection between client and mixnodes [\#20](https://github.com/nymtech/nym/issues/20)
|
|
||||||
- Once implementation is available, wherever appropriate, replace `futures::lock::Mutex` with `futures::lock::RwLock` [\#9](https://github.com/nymtech/nym/issues/9)
|
|
||||||
- Check if RwLock on MixProcessingData is still needed [\#8](https://github.com/nymtech/nym/issues/8)
|
- Check if RwLock on MixProcessingData is still needed [\#8](https://github.com/nymtech/nym/issues/8)
|
||||||
- Reuse TCP socket connection between mixnodes and providers [\#3](https://github.com/nymtech/nym/issues/3)
|
- Once implementation is available, wherever appropriate, replace `futures::lock::Mutex` with `futures::lock::RwLock` [\#9](https://github.com/nymtech/nym/issues/9)
|
||||||
- Persistent socket connection with other mixes [\#2](https://github.com/nymtech/nym/issues/2)
|
- Persistent socket connection with other mixes [\#2](https://github.com/nymtech/nym/issues/2)
|
||||||
|
- Reuse TCP socket connection between client and mixnodes [\#20](https://github.com/nymtech/nym/issues/20)
|
||||||
|
- Reuse TCP socket connection between mixnodes and providers [\#3](https://github.com/nymtech/nym/issues/3)
|
||||||
|
|
||||||
**Merged pull requests:**
|
**Merged pull requests:**
|
||||||
|
|
||||||
@@ -570,8 +824,8 @@ This release also integrates a health-checker and network topology refresh into
|
|||||||
- Messages returned by fetch are base64 encoded [\#55](https://github.com/nymtech/nym/issues/55)
|
- Messages returned by fetch are base64 encoded [\#55](https://github.com/nymtech/nym/issues/55)
|
||||||
- Check layer 1 connectivity at client start [\#38](https://github.com/nymtech/nym/issues/38)
|
- Check layer 1 connectivity at client start [\#38](https://github.com/nymtech/nym/issues/38)
|
||||||
- Check required sfw-provider args [\#27](https://github.com/nymtech/nym/issues/27)
|
- Check required sfw-provider args [\#27](https://github.com/nymtech/nym/issues/27)
|
||||||
- Make Electron app work with new Rust mixnet client [\#16](https://github.com/nymtech/nym/issues/16)
|
|
||||||
- Take version numbers into account when picking routes [\#14](https://github.com/nymtech/nym/issues/14)
|
- Take version numbers into account when picking routes [\#14](https://github.com/nymtech/nym/issues/14)
|
||||||
|
- Make Electron app work with new Rust mixnet client [\#16](https://github.com/nymtech/nym/issues/16)
|
||||||
|
|
||||||
**Merged pull requests:**
|
**Merged pull requests:**
|
||||||
|
|
||||||
@@ -614,7 +868,7 @@ This release also integrates a health-checker and network topology refresh into
|
|||||||
**Merged pull requests:**
|
**Merged pull requests:**
|
||||||
|
|
||||||
- Feature/client topology filtering [\#54](https://github.com/nymtech/nym/pull/54) ([jstuczyn](https://github.com/jstuczyn))
|
- Feature/client topology filtering [\#54](https://github.com/nymtech/nym/pull/54) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
- print public key for nym client tools [\#53](https://github.com/nymtech/nym/pull/53) ([mileschet](https://github.com/mileschet))
|
- print public key for nym client tools [\#53](https://github.com/nymtech/nym/pull/53) ([ghost](https://github.com/ghost))
|
||||||
- Showing binding warning on binding to localhost, 0.0.0.0 or 127.0.0.1 [\#52](https://github.com/nymtech/nym/pull/52) ([jstuczyn](https://github.com/jstuczyn))
|
- Showing binding warning on binding to localhost, 0.0.0.0 or 127.0.0.1 [\#52](https://github.com/nymtech/nym/pull/52) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
- validator: moving sample config files into sample configs directory [\#51](https://github.com/nymtech/nym/pull/51) ([futurechimp](https://github.com/futurechimp))
|
- validator: moving sample config files into sample configs directory [\#51](https://github.com/nymtech/nym/pull/51) ([futurechimp](https://github.com/futurechimp))
|
||||||
- Feature/validator health checker [\#50](https://github.com/nymtech/nym/pull/50) ([jstuczyn](https://github.com/jstuczyn))
|
- Feature/validator health checker [\#50](https://github.com/nymtech/nym/pull/50) ([jstuczyn](https://github.com/jstuczyn))
|
||||||
@@ -637,7 +891,7 @@ This release also integrates a health-checker and network topology refresh into
|
|||||||
|
|
||||||
## [0.2.0](https://github.com/nymtech/nym/tree/0.2.0) (2020-01-06)
|
## [0.2.0](https://github.com/nymtech/nym/tree/0.2.0) (2020-01-06)
|
||||||
|
|
||||||
[Full Changelog](https://github.com/nymtech/nym/compare/0.1.0...0.2.0)
|
[Full Changelog](https://github.com/nymtech/nym/compare/3c64a2facd753f4f2f431e7f888e54842e2bc64e...0.2.0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Generated
+5421
-999
File diff suppressed because it is too large
Load Diff
+17
-6
@@ -1,6 +1,10 @@
|
|||||||
|
# Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
[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"
|
||||||
@@ -8,19 +12,25 @@ 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/mixnode-common",
|
"common/mixnode-common",
|
||||||
|
"common/network-defaults",
|
||||||
"common/nonexhaustive-delayqueue",
|
"common/nonexhaustive-delayqueue",
|
||||||
|
"common/nymcoconut",
|
||||||
"common/nymsphinx",
|
"common/nymsphinx",
|
||||||
"common/nymsphinx/acknowledgements",
|
"common/nymsphinx/acknowledgements",
|
||||||
"common/nymsphinx/addressing",
|
"common/nymsphinx/addressing",
|
||||||
@@ -32,15 +42,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 = [
|
||||||
@@ -50,7 +61,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"]
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
Creative Commons Legal Code
|
||||||
|
|
||||||
|
CC0 1.0 Universal
|
||||||
|
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
|
||||||
|
|
||||||
|
Statement of Purpose
|
||||||
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
|
||||||
|
|
||||||
|
Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
|
||||||
|
|
||||||
|
For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
|
||||||
|
|
||||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
|
||||||
|
i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
|
||||||
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
|
iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
|
||||||
|
iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
|
||||||
|
v. rights protecting the extraction, dissemination, use and reuse of data in a Work;
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
|
||||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||||
|
3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
|
||||||
|
4. Limitations and Disclaimers.
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
|
||||||
|
b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
|
||||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
|
||||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
|
||||||
|
|
||||||
|
Standard License Header
|
||||||
|
|
||||||
|
There is no standard license header for the license
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) <year> <copyright holders>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
Standard License Header
|
||||||
|
|
||||||
|
There is no standard license header for the license
|
||||||
|
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
## The Nym Privacy Platform
|
<!--
|
||||||
|
Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
This repository contains the Nym mixnet.
|
## The Nym Privacy Platform
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
@@ -9,13 +12,16 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
|||||||
* nym-socks5-client - a Socks5 proxy you can run on your machine, and use with existing applications
|
* nym-socks5-client - a Socks5 proxy you can run on your machine, and use with existing applications
|
||||||
* 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://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||||
|
|
||||||
[](https://travis-ci.com/nymtech/nym)
|
|
||||||
|
|
||||||
### 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
|
||||||
|
|
||||||
@@ -24,3 +30,47 @@ There's a `.env.sample-dev` file provided which you can rename to `.env` if you
|
|||||||
### Developer chat
|
### Developer chat
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
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,20 +1,21 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "client-core"
|
name = "client-core"
|
||||||
version = "0.9.2"
|
version = "0.11.0"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "2.0.2"
|
dirs = "3.0"
|
||||||
futures = "0.3.1"
|
futures = "0.3"
|
||||||
humantime-serde = "1.0.1"
|
humantime-serde = "1.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||||
serde = { version = "1.0.104", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
sled = "0.33"
|
sled = "0.34"
|
||||||
tokio = { version = "0.2", features = ["full"] }
|
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;
|
||||||
@@ -46,7 +35,7 @@ where
|
|||||||
|
|
||||||
/// Internal state, determined by `average_message_sending_delay`,
|
/// Internal state, determined by `average_message_sending_delay`,
|
||||||
/// used to keep track of when a next packet should be sent out.
|
/// used to keep track of when a next packet should be sent out.
|
||||||
next_delay: time::Delay,
|
next_delay: Pin<Box<time::Sleep>>,
|
||||||
|
|
||||||
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||||
/// out to the network without any further delays.
|
/// out to the network without any further delays.
|
||||||
@@ -74,7 +63,7 @@ where
|
|||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
// it is not yet time to return a message
|
// it is not yet time to return a message
|
||||||
if Pin::new(&mut self.next_delay).poll(cx).is_pending() {
|
if self.next_delay.as_mut().poll(cx).is_pending() {
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,7 +76,7 @@ where
|
|||||||
// The next interval value is `next_poisson_delay` after the one that just
|
// The next interval value is `next_poisson_delay` after the one that just
|
||||||
// yielded.
|
// yielded.
|
||||||
let next = now + next_poisson_delay;
|
let next = now + next_poisson_delay;
|
||||||
self.next_delay.reset(next);
|
self.next_delay.as_mut().reset(next);
|
||||||
|
|
||||||
Poll::Ready(Some(()))
|
Poll::Ready(Some(()))
|
||||||
}
|
}
|
||||||
@@ -112,7 +101,7 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
average_ack_delay,
|
average_ack_delay,
|
||||||
average_packet_delay,
|
average_packet_delay,
|
||||||
average_cover_message_sending_delay,
|
average_cover_message_sending_delay,
|
||||||
next_delay: time::delay_for(Default::default()),
|
next_delay: Box::pin(time::sleep(Default::default())),
|
||||||
mix_tx,
|
mix_tx,
|
||||||
our_full_destination,
|
our_full_destination,
|
||||||
rng,
|
rng,
|
||||||
@@ -166,10 +155,10 @@ impl LoopCoverTrafficStream<OsRng> {
|
|||||||
|
|
||||||
async fn run(&mut self) {
|
async fn run(&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
|
||||||
self.next_delay = time::delay_for(sample_poisson_duration(
|
self.next_delay = Box::pin(time::sleep(sample_poisson_duration(
|
||||||
&mut self.rng,
|
&mut self.rng,
|
||||||
self.average_cover_message_sending_delay,
|
self.average_cover_message_sending_delay,
|
||||||
));
|
)));
|
||||||
|
|
||||||
while self.next().await.is_some() {
|
while self.next().await.is_some() {
|
||||||
self.on_new_message().await;
|
self.on_new_message().await;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::ReplySURB;
|
use nymsphinx::anonymous_replies::ReplySurb;
|
||||||
|
|
||||||
pub type InputMessageSender = mpsc::UnboundedSender<InputMessage>;
|
pub type InputMessageSender = mpsc::UnboundedSender<InputMessage>;
|
||||||
pub type InputMessageReceiver = mpsc::UnboundedReceiver<InputMessage>;
|
pub type InputMessageReceiver = mpsc::UnboundedReceiver<InputMessage>;
|
||||||
@@ -13,7 +13,7 @@ pub enum InputMessage {
|
|||||||
with_reply_surb: bool,
|
with_reply_surb: bool,
|
||||||
},
|
},
|
||||||
Reply {
|
Reply {
|
||||||
reply_surb: ReplySURB,
|
reply_surb: ReplySurb,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ impl InputMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_reply(reply_surb: ReplySURB, data: Vec<u8>) -> Self {
|
pub fn new_reply(reply_surb: ReplySurb, data: Vec<u8>) -> Self {
|
||||||
InputMessage::Reply { reply_surb, data }
|
InputMessage::Reply { reply_surb, data }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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};
|
||||||
@@ -61,8 +50,8 @@ impl KeyManager {
|
|||||||
R: RngCore + CryptoRng,
|
R: RngCore + CryptoRng,
|
||||||
{
|
{
|
||||||
KeyManager {
|
KeyManager {
|
||||||
identity_keypair: Arc::new(identity::KeyPair::new_with_rng(rng)),
|
identity_keypair: Arc::new(identity::KeyPair::new(rng)),
|
||||||
encryption_keypair: Arc::new(encryption::KeyPair::new_with_rng(rng)),
|
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
|
||||||
gateway_shared_key: None,
|
gateway_shared_key: None,
|
||||||
ack_key: Arc::new(AckKey::new(rng)),
|
ack_key: Arc::new(AckKey::new(rng)),
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
+2
-13
@@ -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;
|
||||||
|
|||||||
+5
-18
@@ -1,35 +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 super::PendingAcknowledgement;
|
use super::PendingAcknowledgement;
|
||||||
use crate::client::real_messages_control::acknowledgement_control::RetransmissionRequestSender;
|
use crate::client::real_messages_control::acknowledgement_control::RetransmissionRequestSender;
|
||||||
use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||||
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nonexhaustive_delayqueue::NonExhaustiveDelayQueue;
|
use nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey, TimerError};
|
||||||
use nymsphinx::chunking::fragment::FragmentIdentifier;
|
use nymsphinx::chunking::fragment::FragmentIdentifier;
|
||||||
use nymsphinx::Delay as SphinxDelay;
|
use nymsphinx::Delay as SphinxDelay;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::stream::StreamExt;
|
|
||||||
use tokio::time::delay_queue::{self, Expired};
|
|
||||||
use tokio::time::Error as TimerError;
|
|
||||||
|
|
||||||
pub(crate) type ActionSender = UnboundedSender<Action>;
|
pub(crate) type ActionSender = UnboundedSender<Action>;
|
||||||
|
|
||||||
// The actual data being sent off as well as potential key to the delay queue
|
// The actual data being sent off as well as potential key to the delay queue
|
||||||
type PendingAckEntry = (Arc<PendingAcknowledgement>, Option<delay_queue::Key>);
|
type PendingAckEntry = (Arc<PendingAcknowledgement>, Option<QueueKey>);
|
||||||
|
|
||||||
// we can either:
|
// we can either:
|
||||||
// - have a completely new set of packets we just sent and need to create entries for
|
// - have a completely new set of packets we just sent and need to create entries for
|
||||||
|
|||||||
+21
-29
@@ -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;
|
||||||
@@ -22,7 +11,7 @@ use crate::client::{
|
|||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::anonymous_replies::ReplySURB;
|
use nymsphinx::anonymous_replies::ReplySurb;
|
||||||
use nymsphinx::preparer::MessagePreparer;
|
use nymsphinx::preparer::MessagePreparer;
|
||||||
use nymsphinx::{acknowledgements::AckKey, addressing::clients::Recipient};
|
use nymsphinx::{acknowledgements::AckKey, addressing::clients::Recipient};
|
||||||
use rand::{CryptoRng, Rng};
|
use rand::{CryptoRng, Rng};
|
||||||
@@ -49,6 +38,9 @@ impl<R> InputMessageListener<R>
|
|||||||
where
|
where
|
||||||
R: CryptoRng + Rng,
|
R: CryptoRng + Rng,
|
||||||
{
|
{
|
||||||
|
// at this point I'm not entirely sure how to deal with this warning without
|
||||||
|
// some considerable refactoring
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(super) fn new(
|
pub(super) fn new(
|
||||||
ack_key: Arc<AckKey>,
|
ack_key: Arc<AckKey>,
|
||||||
ack_recipient: Recipient,
|
ack_recipient: Recipient,
|
||||||
@@ -72,7 +64,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we require topology for replies to generate surb_acks
|
// we require topology for replies to generate surb_acks
|
||||||
async fn handle_reply(&mut self, reply_surb: ReplySURB, data: Vec<u8>) -> Option<RealMessage> {
|
async fn handle_reply(&mut self, reply_surb: ReplySurb, data: Vec<u8>) -> Option<RealMessage> {
|
||||||
let topology_permit = self.topology_access.get_read_permit().await;
|
let topology_permit = self.topology_access.get_read_permit().await;
|
||||||
let topology = match topology_permit.try_get_valid_topology_ref(&self.ack_recipient, None) {
|
let topology = match topology_permit.try_get_valid_topology_ref(&self.ack_recipient, None) {
|
||||||
Some(topology_ref) => topology_ref,
|
Some(topology_ref) => topology_ref,
|
||||||
@@ -107,7 +99,7 @@ where
|
|||||||
recipient: Recipient,
|
recipient: Recipient,
|
||||||
content: Vec<u8>,
|
content: Vec<u8>,
|
||||||
with_reply_surb: bool,
|
with_reply_surb: bool,
|
||||||
) -> Vec<RealMessage> {
|
) -> Option<Vec<RealMessage>> {
|
||||||
let topology_permit = self.topology_access.get_read_permit().await;
|
let topology_permit = self.topology_access.get_read_permit().await;
|
||||||
let topology = match topology_permit
|
let topology = match topology_permit
|
||||||
.try_get_valid_topology_ref(&self.ack_recipient, Some(&recipient))
|
.try_get_valid_topology_ref(&self.ack_recipient, Some(&recipient))
|
||||||
@@ -115,7 +107,7 @@ where
|
|||||||
Some(topology_ref) => topology_ref,
|
Some(topology_ref) => topology_ref,
|
||||||
None => {
|
None => {
|
||||||
warn!("Could not process the message - the network topology is invalid");
|
warn!("Could not process the message - the network topology is invalid");
|
||||||
return Vec::new();
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,7 +153,7 @@ where
|
|||||||
.unbounded_send(Action::new_insert(pending_acks))
|
.unbounded_send(Action::new_insert(pending_acks))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
real_messages
|
Some(real_messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_input_message(&mut self, msg: InputMessage) {
|
async fn on_input_message(&mut self, msg: InputMessage) {
|
||||||
@@ -174,19 +166,19 @@ where
|
|||||||
self.handle_fresh_message(recipient, data, with_reply_surb)
|
self.handle_fresh_message(recipient, data, with_reply_surb)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
InputMessage::Reply { reply_surb, data } => {
|
InputMessage::Reply { reply_surb, data } => self
|
||||||
if let Some(real_message) = self.handle_reply(reply_surb, data).await {
|
.handle_reply(reply_surb, data)
|
||||||
vec![real_message]
|
.await
|
||||||
} else {
|
.map(|message| vec![message]),
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// tells real message sender (with the poisson timer) to send this to the mix network
|
// there's no point in trying to send nothing
|
||||||
self.real_message_sender
|
if let Some(real_messages) = real_messages {
|
||||||
.unbounded_send(real_messages)
|
// tells real message sender (with the poisson timer) to send this to the mix network
|
||||||
.unwrap();
|
self.real_message_sender
|
||||||
|
.unbounded_send(real_messages)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn run(&mut self) {
|
pub(super) async fn run(&mut self) {
|
||||||
|
|||||||
+3
-29
@@ -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,
|
||||||
@@ -56,7 +44,7 @@ type RetransmissionRequestReceiver = mpsc::UnboundedReceiver<Weak<PendingAcknowl
|
|||||||
pub(super) type SentPacketNotificationSender = mpsc::UnboundedSender<FragmentIdentifier>;
|
pub(super) type SentPacketNotificationSender = mpsc::UnboundedSender<FragmentIdentifier>;
|
||||||
|
|
||||||
/// Channel used for receiving signals about the particular `Fragment` (associated with the `FragmentIdentifier`)
|
/// Channel used for receiving signals about the particular `Fragment` (associated with the `FragmentIdentifier`)
|
||||||
/// that it is about to be sent to tbe mix network and its timeout timer should be started.
|
/// that it is about to be sent to the mix network and its timeout timer should be started.
|
||||||
type SentPacketNotificationReceiver = mpsc::UnboundedReceiver<FragmentIdentifier>;
|
type SentPacketNotificationReceiver = mpsc::UnboundedReceiver<FragmentIdentifier>;
|
||||||
|
|
||||||
/// Structure representing a data `Fragment` that is on-route to the specified `Recipient`
|
/// Structure representing a data `Fragment` that is on-route to the specified `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
|
||||||
|
|||||||
+2
-13
@@ -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;
|
||||||
|
|||||||
+2
-13
@@ -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,14 +50,6 @@ 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 {
|
||||||
@@ -81,19 +61,15 @@ 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,
|
||||||
|
ack_wait_addition,
|
||||||
|
ack_wait_multiplier,
|
||||||
self_recipient,
|
self_recipient,
|
||||||
|
average_message_sending_delay,
|
||||||
average_packet_delay_duration,
|
average_packet_delay_duration,
|
||||||
average_ack_delay_duration,
|
average_ack_delay_duration,
|
||||||
average_message_sending_delay,
|
|
||||||
ack_wait_multiplier,
|
|
||||||
ack_wait_addition,
|
|
||||||
packet_mode,
|
|
||||||
vpn_key_reuse_limit,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,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(
|
||||||
@@ -171,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();
|
||||||
|
|
||||||
@@ -179,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
|
||||||
});
|
});
|
||||||
@@ -198,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;
|
||||||
@@ -73,7 +62,7 @@ where
|
|||||||
|
|
||||||
/// Internal state, determined by `average_message_sending_delay`,
|
/// Internal state, determined by `average_message_sending_delay`,
|
||||||
/// used to keep track of when a next packet should be sent out.
|
/// used to keep track of when a next packet should be sent out.
|
||||||
next_delay: time::Delay,
|
next_delay: Pin<Box<time::Sleep>>,
|
||||||
|
|
||||||
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
/// Channel used for sending prepared sphinx packets to `MixTrafficController` that sends them
|
||||||
/// out to the network without any further delays.
|
/// out to the network without any further delays.
|
||||||
@@ -117,7 +106,7 @@ type BatchRealMessageReceiver = mpsc::UnboundedReceiver<Vec<RealMessage>>;
|
|||||||
|
|
||||||
pub(crate) enum StreamMessage {
|
pub(crate) enum StreamMessage {
|
||||||
Cover,
|
Cover,
|
||||||
Real(RealMessage),
|
Real(Box<RealMessage>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> Stream for OutQueueControl<R>
|
impl<R> Stream for OutQueueControl<R>
|
||||||
@@ -128,7 +117,7 @@ where
|
|||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
// it is not yet time to return a message
|
// it is not yet time to return a message
|
||||||
if Pin::new(&mut self.next_delay).poll(cx).is_pending() {
|
if self.next_delay.as_mut().poll(cx).is_pending() {
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -141,11 +130,11 @@ where
|
|||||||
// The next interval value is `next_poisson_delay` after the one that just
|
// The next interval value is `next_poisson_delay` after the one that just
|
||||||
// yielded.
|
// yielded.
|
||||||
let next = now + next_poisson_delay;
|
let next = now + next_poisson_delay;
|
||||||
self.next_delay.reset(next);
|
self.next_delay.as_mut().reset(next);
|
||||||
|
|
||||||
// check if we have anything immediately available
|
// check if we have anything immediately available
|
||||||
if let Some(real_available) = self.received_buffer.pop_front() {
|
if let Some(real_available) = self.received_buffer.pop_front() {
|
||||||
return Poll::Ready(Some(StreamMessage::Real(real_available)));
|
return Poll::Ready(Some(StreamMessage::Real(Box::new(real_available))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// decide what kind of message to send
|
// decide what kind of message to send
|
||||||
@@ -158,9 +147,9 @@ where
|
|||||||
Poll::Ready(Some(real_messages)) => {
|
Poll::Ready(Some(real_messages)) => {
|
||||||
self.received_buffer = real_messages.into();
|
self.received_buffer = real_messages.into();
|
||||||
// we MUST HAVE received at least ONE message
|
// we MUST HAVE received at least ONE message
|
||||||
Poll::Ready(Some(StreamMessage::Real(
|
Poll::Ready(Some(StreamMessage::Real(Box::new(
|
||||||
self.received_buffer.pop_front().unwrap(),
|
self.received_buffer.pop_front().unwrap(),
|
||||||
)))
|
))))
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise construct a dummy one
|
// otherwise construct a dummy one
|
||||||
@@ -173,6 +162,9 @@ impl<R> OutQueueControl<R>
|
|||||||
where
|
where
|
||||||
R: CryptoRng + Rng + Unpin,
|
R: CryptoRng + Rng + Unpin,
|
||||||
{
|
{
|
||||||
|
// at this point I'm not entirely sure how to deal with this warning without
|
||||||
|
// some considerable refactoring
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
config: Config,
|
config: Config,
|
||||||
ack_key: Arc<AckKey>,
|
ack_key: Arc<AckKey>,
|
||||||
@@ -187,7 +179,7 @@ where
|
|||||||
config,
|
config,
|
||||||
ack_key,
|
ack_key,
|
||||||
sent_notifier,
|
sent_notifier,
|
||||||
next_delay: time::delay_for(Default::default()),
|
next_delay: Box::pin(time::sleep(Default::default())),
|
||||||
mix_tx,
|
mix_tx,
|
||||||
real_receiver,
|
real_receiver,
|
||||||
our_full_destination,
|
our_full_destination,
|
||||||
@@ -257,42 +249,21 @@ 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
|
||||||
self.next_delay = time::delay_for(sample_poisson_duration(
|
self.next_delay = Box::pin(time::sleep(sample_poisson_duration(
|
||||||
&mut self.rng,
|
&mut self.rng,
|
||||||
self.config.average_message_sending_delay,
|
self.config.average_message_sending_delay,
|
||||||
));
|
)));
|
||||||
|
|
||||||
while let Some(next_message) = self.next().await {
|
while let Some(next_message) = self.next().await {
|
||||||
self.on_message(next_message).await;
|
self.on_message(next_message).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
@@ -21,8 +10,8 @@ use futures::lock::Mutex;
|
|||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gateway_client::MixnetMessageReceiver;
|
use gateway_client::MixnetMessageReceiver;
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SURBEncryptionKey};
|
use nymsphinx::anonymous_replies::{encryption_key::EncryptionKeyDigest, SurbEncryptionKey};
|
||||||
use nymsphinx::params::{ReplySURBEncryptionAlgorithm, ReplySURBKeyDigestAlgorithm};
|
use nymsphinx::params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorithm};
|
||||||
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
use nymsphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -165,7 +154,7 @@ impl ReceivedMessagesBuffer {
|
|||||||
|
|
||||||
// while we're at it, also empty the buffer if we happened to receive anything while
|
// while we're at it, also empty the buffer if we happened to receive anything while
|
||||||
// no sender was connected
|
// no sender was connected
|
||||||
let stored_messages = std::mem::replace(&mut guard.messages, Vec::new());
|
let stored_messages = std::mem::take(&mut guard.messages);
|
||||||
if !stored_messages.is_empty() {
|
if !stored_messages.is_empty() {
|
||||||
if let Err(err) = sender.unbounded_send(stored_messages) {
|
if let Err(err) = sender.unbounded_send(stored_messages) {
|
||||||
error!(
|
error!(
|
||||||
@@ -191,12 +180,12 @@ impl ReceivedMessagesBuffer {
|
|||||||
|
|
||||||
fn process_received_reply(
|
fn process_received_reply(
|
||||||
reply_ciphertext: &[u8],
|
reply_ciphertext: &[u8],
|
||||||
reply_key: SURBEncryptionKey,
|
reply_key: SurbEncryptionKey,
|
||||||
) -> Option<ReconstructedMessage> {
|
) -> Option<ReconstructedMessage> {
|
||||||
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,
|
||||||
);
|
);
|
||||||
@@ -221,7 +210,7 @@ impl ReceivedMessagesBuffer {
|
|||||||
let mut completed_messages = Vec::new();
|
let mut completed_messages = Vec::new();
|
||||||
let mut inner_guard = self.inner.lock().await;
|
let mut inner_guard = self.inner.lock().await;
|
||||||
|
|
||||||
let reply_surb_digest_size = ReplySURBKeyDigestAlgorithm::output_size();
|
let reply_surb_digest_size = ReplySurbKeyDigestAlgorithm::output_size();
|
||||||
|
|
||||||
// first check if this is a reply or a chunked message
|
// first check if this is a reply or a chunked message
|
||||||
// TODO: verify with @AP if this way of doing it is safe or whether it could
|
// TODO: verify with @AP if this way of doing it is safe or whether it could
|
||||||
|
|||||||
@@ -1,21 +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 log::*;
|
use log::*;
|
||||||
use nymsphinx::anonymous_replies::{
|
use nymsphinx::anonymous_replies::{
|
||||||
encryption_key::EncryptionKeyDigest, encryption_key::Unsigned, SURBEncryptionKey,
|
encryption_key::EncryptionKeyDigest, encryption_key::Unsigned, SurbEncryptionKey,
|
||||||
SURBEncryptionKeySize,
|
SurbEncryptionKeySize,
|
||||||
};
|
};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -49,24 +38,24 @@ impl ReplyKeyStorage {
|
|||||||
Ok(ReplyKeyStorage { db })
|
Ok(ReplyKeyStorage { db })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_encryption_key(&self, raw_key: sled::IVec) -> SURBEncryptionKey {
|
fn read_encryption_key(&self, raw_key: sled::IVec) -> SurbEncryptionKey {
|
||||||
let key_bytes_ref = raw_key.as_ref();
|
let key_bytes_ref = raw_key.as_ref();
|
||||||
// if this fails it means we have some database corruption and we
|
// if this fails it means we have some database corruption and we
|
||||||
// absolutely can't continue
|
// absolutely can't continue
|
||||||
|
|
||||||
if key_bytes_ref.len() != SURBEncryptionKeySize::to_usize() {
|
if key_bytes_ref.len() != SurbEncryptionKeySize::to_usize() {
|
||||||
error!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
error!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||||
panic!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
panic!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||||
}
|
}
|
||||||
|
|
||||||
// this can only fail if the bytes have invalid length but we already asserted it
|
// this can only fail if the bytes have invalid length but we already asserted it
|
||||||
SURBEncryptionKey::try_from_bytes(key_bytes_ref).unwrap()
|
SurbEncryptionKey::try_from_bytes(key_bytes_ref).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TOOD: perhaps we could also store some part of original message here too?
|
// TOOD: perhaps we could also store some part of original message here too?
|
||||||
pub fn insert_encryption_key(
|
pub fn insert_encryption_key(
|
||||||
&mut self,
|
&mut self,
|
||||||
encryption_key: SURBEncryptionKey,
|
encryption_key: SurbEncryptionKey,
|
||||||
) -> Result<(), ReplyKeyStorageError> {
|
) -> Result<(), ReplyKeyStorageError> {
|
||||||
let digest = encryption_key.compute_digest();
|
let digest = encryption_key.compute_digest();
|
||||||
|
|
||||||
@@ -89,7 +78,7 @@ impl ReplyKeyStorage {
|
|||||||
pub fn get_and_remove_encryption_key(
|
pub fn get_and_remove_encryption_key(
|
||||||
&self,
|
&self,
|
||||||
key_digest: EncryptionKeyDigest,
|
key_digest: EncryptionKeyDigest,
|
||||||
) -> Result<Option<SURBEncryptionKey>, ReplyKeyStorageError> {
|
) -> Result<Option<SurbEncryptionKey>, ReplyKeyStorageError> {
|
||||||
let removal_result = match self.db.remove(&key_digest.to_vec()) {
|
let removal_result = match self.db.remove(&key_digest.to_vec()) {
|
||||||
Err(e) => Err(ReplyKeyStorageError::DbReadError(e)),
|
Err(e) => Err(ReplyKeyStorageError::DbReadError(e)),
|
||||||
Ok(existing_key) => {
|
Ok(existing_key) => {
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -22,7 +13,8 @@ use std::time::Duration;
|
|||||||
use tokio::runtime::Handle;
|
use tokio::runtime::Handle;
|
||||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use topology::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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,51 +121,159 @@ impl TopologyAccessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for TopologyAccessor {
|
||||||
|
fn default() -> Self {
|
||||||
|
TopologyAccessor::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct TopologyRefresherConfig {
|
pub struct TopologyRefresherConfig {
|
||||||
directory_server: String,
|
validator_api_urls: Vec<Url>,
|
||||||
refresh_rate: time::Duration,
|
refresh_rate: time::Duration,
|
||||||
|
client_version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TopologyRefresherConfig {
|
impl TopologyRefresherConfig {
|
||||||
pub fn new(directory_server: String, refresh_rate: time::Duration) -> Self {
|
pub fn new(
|
||||||
|
validator_api_urls: Vec<Url>,
|
||||||
|
refresh_rate: time::Duration,
|
||||||
|
client_version: String,
|
||||||
|
) -> Self {
|
||||||
TopologyRefresherConfig {
|
TopologyRefresherConfig {
|
||||||
directory_server,
|
validator_api_urls,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TopologyRefresher {
|
impl TopologyRefresher {
|
||||||
pub fn new_directory_client(
|
pub fn new(mut cfg: TopologyRefresherConfig, topology_accessor: TopologyAccessor) -> Self {
|
||||||
cfg: TopologyRefresherConfig,
|
cfg.validator_api_urls.shuffle(&mut thread_rng());
|
||||||
topology_accessor: TopologyAccessor,
|
|
||||||
) -> Self {
|
|
||||||
let validator_client_config = validator_client::Config::new(cfg.directory_server);
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
async fn get_current_compatible_topology(&self) -> Option<NymTopology> {
|
||||||
match self.validator_client.get_active_topology().await {
|
// TODO: optimization for the future:
|
||||||
|
// only refresh mixnodes on timer and refresh gateways only when
|
||||||
|
// we have to send to a new, unknown, gateway
|
||||||
|
|
||||||
|
let mixnodes = match self.validator_client.get_cached_active_mixnodes().await {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("failed to get active network topology! - {:?}", err);
|
error!("failed to get network mixnodes - {}", err);
|
||||||
None
|
return None;
|
||||||
}
|
}
|
||||||
Ok(topology) => {
|
Ok(mixes) => mixes,
|
||||||
let nym_topology: NymTopology = topology.into();
|
};
|
||||||
Some(nym_topology.filter_system_version(env!("CARGO_PKG_VERSION")))
|
|
||||||
|
let gateways = match self.validator_client.get_cached_gateways().await {
|
||||||
|
Err(err) => {
|
||||||
|
error!("failed to get network gateways - {}", err);
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
|
Ok(gateways) => gateways,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mixnodes_count = mixnodes.len();
|
||||||
|
let topology =
|
||||||
|
nym_topology_from_bonds(mixnodes, gateways).filter_system_version(&self.client_version);
|
||||||
|
|
||||||
|
if !self.check_layer_distribution(&topology, mixnodes_count) {
|
||||||
|
warn!("The current filtered active topology has extremely skewed layer distribution. It cannot be used.");
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(topology)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +281,20 @@ impl TopologyRefresher {
|
|||||||
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 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
|
||||||
|
warn!("we're going to keep on using the old topology for this iteration");
|
||||||
|
self.was_latest_valid = false;
|
||||||
|
return;
|
||||||
|
} else if new_topology.is_some() {
|
||||||
|
self.was_latest_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
self.topology_accessor
|
self.topology_accessor
|
||||||
.update_global_topology(new_topology)
|
.update_global_topology(new_topology)
|
||||||
.await;
|
.await;
|
||||||
@@ -193,7 +307,7 @@ impl TopologyRefresher {
|
|||||||
pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
|
pub fn start(mut self, handle: &Handle) -> JoinHandle<()> {
|
||||||
handle.spawn(async move {
|
handle.spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
tokio::time::delay_for(self.refresh_rate).await;
|
tokio::time::sleep(self.refresh_rate).await;
|
||||||
self.refresh().await;
|
self.refresh().await;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,33 +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::defaults::*;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use serde::{
|
use serde::{Deserialize, Serialize};
|
||||||
de::{self, IntoDeserializer, Visitor},
|
|
||||||
Deserialize, Deserializer, 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_ENDPOINT: &str = "http://testnet-validator1.nymtech.net:8081";
|
|
||||||
|
|
||||||
// 'DEBUG'
|
// 'DEBUG'
|
||||||
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5;
|
||||||
|
|
||||||
@@ -35,59 +20,12 @@ const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500);
|
|||||||
const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200);
|
const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200);
|
||||||
const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20);
|
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_millis(30_000);
|
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);
|
||||||
|
|
||||||
// custom function is defined to deserialize based on whether field contains a pre 0.9.0
|
|
||||||
// u64 interpreted as milliseconds or proper duration introduced in 0.9.0
|
|
||||||
//
|
|
||||||
// TODO: when we get to refactoring down the line, this code can just be removed
|
|
||||||
// and all Duration fields could just have #[serde(with = "humantime_serde")] instead
|
|
||||||
// reason for that is that we don't expect anyone to be upgrading from pre 0.9.0 when we have,
|
|
||||||
// for argument sake, 0.11.0 out
|
|
||||||
fn deserialize_duration<'de, D>(deserializer: D) -> Result<Duration, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct DurationVisitor;
|
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for DurationVisitor {
|
|
||||||
type Value = Duration;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
formatter.write_str("u64 or a duration")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_i64<E>(self, value: i64) -> Result<Duration, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.visit_u64(value as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_u64<E>(self, value: u64) -> Result<Duration, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
Ok(Duration::from_millis(Deserialize::deserialize(
|
|
||||||
value.into_deserializer(),
|
|
||||||
)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Duration, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
humantime_serde::deserialize(value.into_deserializer())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_any(DurationVisitor)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn missing_string_value() -> String {
|
pub fn missing_string_value() -> String {
|
||||||
MISSING_VALUE.to_string()
|
MISSING_VALUE.to_string()
|
||||||
@@ -165,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,24 +125,26 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.gateway_listener = gateway_listener.into();
|
self.client.gateway_listener = gateway_listener.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_custom_validator<S: Into<String>>(&mut self, validator: S) {
|
#[cfg(not(feature = "coconut"))]
|
||||||
self.client.validator_rest_url = validator.into();
|
pub fn with_eth_private_key<S: Into<String>>(&mut self, eth_private_key: S) {
|
||||||
|
self.client.eth_private_key = eth_private_key.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "coconut"))]
|
||||||
|
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) {
|
||||||
self.debug.average_packet_delay = Duration::from_millis(1);
|
self.debug.average_packet_delay = Duration::from_millis(10);
|
||||||
self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2000000); // basically don't really send cover messages
|
self.debug.loop_cover_traffic_average_delay = Duration::from_millis(2000000); // basically don't really send cover messages
|
||||||
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();
|
||||||
}
|
}
|
||||||
@@ -234,8 +185,8 @@ impl<T: NymConfig> Config<T> {
|
|||||||
self.client.ack_key_file.clone()
|
self.client.ack_key_file.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_validator_rest_endpoint(&self) -> String {
|
pub fn get_validator_api_endpoints(&self) -> Vec<Url> {
|
||||||
self.client.validator_rest_url.clone()
|
self.client.validator_api_urls.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_gateway_id(&self) -> String {
|
pub fn get_gateway_id(&self) -> String {
|
||||||
@@ -246,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 {
|
||||||
@@ -276,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 {
|
||||||
@@ -295,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_else(|| DEFAULT_VPN_KEY_REUSE_LIMIT),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_version(&self) -> &str {
|
pub fn get_version(&self) -> &str {
|
||||||
&self.client.version
|
&self.client.version
|
||||||
}
|
}
|
||||||
@@ -334,15 +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(default = "missing_string_value")]
|
validator_api_urls: Vec<Url>,
|
||||||
validator_rest_url: 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,
|
||||||
@@ -375,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,
|
||||||
@@ -389,8 +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_url: DEFAULT_VALIDATOR_REST_ENDPOINT.to_string(),
|
validator_api_urls: default_api_endpoints(),
|
||||||
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(),
|
||||||
@@ -400,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(),
|
||||||
}
|
}
|
||||||
@@ -408,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 {
|
||||||
@@ -453,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
|
||||||
@@ -477,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 {
|
||||||
@@ -543,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.9.2"
|
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,21 +17,23 @@ 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
|
||||||
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
|
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
|
||||||
log = "0.4" # self explanatory
|
log = "0.4" # self explanatory
|
||||||
pretty_env_logger = "0.3" # for formatting log messages
|
pretty_env_logger = "0.4" # for formatting log messages
|
||||||
rand = {version = "0.7.3", features = ["wasm-bindgen"]} # rng-related traits + some rng implementation to use
|
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
|
||||||
serde = { version = "1.0.104", features = ["derive"] } # for config serialization/deserialization
|
serde = { version = "1.0.104", features = ["derive"] } # for config serialization/deserialization
|
||||||
sled = "0.33" # for storage of replySURB decryption keys
|
sled = "0.34" # for storage of replySURB decryption keys
|
||||||
tokio = { version = "0.2", features = ["full"] } # async runtime
|
tokio = { version = "1.4", features = ["rt-multi-thread", "net", "signal"] } # async runtime
|
||||||
tokio-tungstenite = "0.11.0" # websocket
|
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" }
|
||||||
@@ -41,6 +44,10 @@ topology = { path = "../../common/topology" }
|
|||||||
websocket-requests = { path = "websocket-requests" }
|
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" }
|
||||||
|
network-defaults = { path = "../../common/network-defaults" }
|
||||||
|
|
||||||
|
[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
-18
@@ -9,21 +9,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// request tags
|
// request tags
|
||||||
const SEND_REQUEST_TAG = 0x00
|
const sendRequestTag = 0x00
|
||||||
const REPLY_REQUEST_TAG = 0x01
|
const replyRequestTag = 0x01
|
||||||
const SELF_ADDRESS_REQUEST_TAG = 0x02
|
const selfAddressRequestTag = 0x02
|
||||||
|
|
||||||
// response tags
|
// response tags
|
||||||
const ERROR_RESPONSE_TAG = 0x00
|
const errorResponseTag = 0x00
|
||||||
const RECEIVED_RESPONSE_TAG = 0x01
|
const receivedResponseTag = 0x01
|
||||||
const SELF_ADDRESS_RESPONSE_TAG = 0x02
|
const selfAddressResponseTag = 0x02
|
||||||
|
|
||||||
func makeSelfAddressRequest() []byte {
|
func makeSelfAddressRequest() []byte {
|
||||||
return []byte{SELF_ADDRESS_REQUEST_TAG}
|
return []byte{selfAddressRequestTag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSelfAddressResponse(rawResponse []byte) []byte {
|
func parseSelfAddressResponse(rawResponse []byte) []byte {
|
||||||
if len(rawResponse) != 97 || rawResponse[0] != SELF_ADDRESS_RESPONSE_TAG {
|
if len(rawResponse) != 97 || rawResponse[0] != selfAddressResponseTag {
|
||||||
panic("Received invalid response")
|
panic("Received invalid response")
|
||||||
}
|
}
|
||||||
return rawResponse[1:]
|
return rawResponse[1:]
|
||||||
@@ -38,7 +38,7 @@ func makeSendRequest(recipient []byte, message []byte, withReplySurb bool) []byt
|
|||||||
surbByte = 1
|
surbByte = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
out := []byte{SEND_REQUEST_TAG, surbByte}
|
out := []byte{sendRequestTag, surbByte}
|
||||||
out = append(out, recipient...)
|
out = append(out, recipient...)
|
||||||
out = append(out, messageLen...)
|
out = append(out, messageLen...)
|
||||||
out = append(out, message...)
|
out = append(out, message...)
|
||||||
@@ -53,7 +53,7 @@ func makeReplyRequest(message []byte, replySURB []byte) []byte {
|
|||||||
surbLen := make([]byte, 8)
|
surbLen := make([]byte, 8)
|
||||||
binary.BigEndian.PutUint64(surbLen, uint64(len(replySURB)))
|
binary.BigEndian.PutUint64(surbLen, uint64(len(replySURB)))
|
||||||
|
|
||||||
out := []byte{REPLY_REQUEST_TAG}
|
out := []byte{replyRequestTag}
|
||||||
out = append(out, surbLen...)
|
out = append(out, surbLen...)
|
||||||
out = append(out, replySURB...)
|
out = append(out, replySURB...)
|
||||||
out = append(out, messageLen...)
|
out = append(out, messageLen...)
|
||||||
@@ -63,7 +63,7 @@ func makeReplyRequest(message []byte, replySURB []byte) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseReceived(rawResponse []byte) ([]byte, []byte) {
|
func parseReceived(rawResponse []byte) ([]byte, []byte) {
|
||||||
if rawResponse[0] != RECEIVED_RESPONSE_TAG {
|
if rawResponse[0] != receivedResponseTag {
|
||||||
panic("Received invalid response!")
|
panic("Received invalid response!")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ func parseReceived(rawResponse []byte) ([]byte, []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendWithoutReply() {
|
func sendBinaryWithoutReply() {
|
||||||
uri := "ws://localhost:1977"
|
uri := "ws://localhost:1977"
|
||||||
|
|
||||||
conn, _, err := websocket.DefaultDialer.Dial(uri, nil)
|
conn, _, err := websocket.DefaultDialer.Dial(uri, nil)
|
||||||
@@ -122,12 +122,12 @@ func sendWithoutReply() {
|
|||||||
}
|
}
|
||||||
selfAddress := parseSelfAddressResponse(receivedResponse)
|
selfAddress := parseSelfAddressResponse(receivedResponse)
|
||||||
|
|
||||||
read_data, err := ioutil.ReadFile("dummy_file")
|
readData, err := ioutil.ReadFile("dummy_file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendRequest := makeSendRequest(selfAddress, read_data, false)
|
sendRequest := makeSendRequest(selfAddress, readData, false)
|
||||||
fmt.Printf("sending content of 'dummy file' over the mix network...\n")
|
fmt.Printf("sending content of 'dummy file' over the mix network...\n")
|
||||||
if err = conn.WriteMessage(websocket.BinaryMessage, sendRequest); err != nil {
|
if err = conn.WriteMessage(websocket.BinaryMessage, sendRequest); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -144,10 +144,10 @@ func sendWithoutReply() {
|
|||||||
panic("did not expect a replySURB!")
|
panic("did not expect a replySURB!")
|
||||||
}
|
}
|
||||||
fmt.Printf("writing the file back to the disk!\n")
|
fmt.Printf("writing the file back to the disk!\n")
|
||||||
ioutil.WriteFile("received_file_noreply", fileData, 0644)
|
ioutil.WriteFile("received_file_no_reply", fileData, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendWithReply() {
|
func sendBinaryWithReply() {
|
||||||
uri := "ws://localhost:1977"
|
uri := "ws://localhost:1977"
|
||||||
|
|
||||||
conn, _, err := websocket.DefaultDialer.Dial(uri, nil)
|
conn, _, err := websocket.DefaultDialer.Dial(uri, nil)
|
||||||
@@ -212,6 +212,6 @@ func sendWithReply() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// sendWithoutReply()
|
// sendBinaryWithoutReply()
|
||||||
sendWithReply()
|
sendBinaryWithReply()
|
||||||
}
|
}
|
||||||
@@ -4,5 +4,5 @@ go 1.14
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/btcsuite/btcutil v1.0.2 // indirect
|
github.com/btcsuite/btcutil v1.0.2 // indirect
|
||||||
github.com/gorilla/websocket v1.4.2 // indirect
|
github.com/gorilla/websocket v1.4.2
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis efficitur neque. Quisque aliquet vulputate ante, eget vehicula odio feugiat ac. Nulla ut mattis magna. Aenean tincidunt quis nulla eget eleifend. Cras in pretium sem. Nunc lorem metus, blandit sit amet egestas ut, feugiat quis tellus. Aenean tristique, enim a tincidunt condimentum, eros est blandit nunc, id viverra metus erat at nulla. Vivamus at tellus sodales, feugiat odio vel, laoreet neque. Vivamus posuere nulla ac sodales bibendum.
|
||||||
|
|
||||||
|
Vestibulum pulvinar nisi non ultricies egestas. Integer finibus ultrices justo vitae suscipit. Etiam interdum eu justo vel interdum. Morbi sagittis ac nisl quis consequat. Mauris dapibus ut risus ac facilisis. Pellentesque non tortor feugiat, consectetur arcu vel, ullamcorper sapien. Proin sodales purus non orci bibendum, sit amet ultrices justo ullamcorper. Nullam ac risus ac justo ultricies efficitur auctor nec arcu. Etiam sed finibus felis. Suspendisse potenti. Phasellus malesuada velit ac ullamcorper egestas. Sed elementum diam ut est gravida ultricies.
|
||||||
|
|
||||||
|
Pellentesque sed metus massa. Cras imperdiet lacus sit amet dolor aliquam, luctus posuere justo hendrerit. Morbi augue ex, gravida a metus sed, scelerisque euismod lacus. Nam consequat sapien ac pellentesque sagittis. Morbi a ultrices massa, vel aliquet ex. Maecenas ac sem diam. Nunc sed erat et ipsum volutpat auctor. Etiam elit felis, commodo vitae ipsum ac, fermentum lobortis arcu. Aliquam eu tempus enim. Curabitur vulputate imperdiet aliquam. Morbi iaculis rhoncus risus at malesuada. Donec accumsan feugiat ligula ut facilisis. Nunc porttitor sit amet est eget malesuada. Sed sed consectetur augue, non dapibus orci. Mauris aliquam pellentesque quam, sit amet pellentesque velit cursus vitae. Morbi sit amet molestie risus.
|
||||||
|
|
||||||
|
Nam gravida non ligula a egestas. Fusce sodales, purus id rhoncus mattis, purus est vehicula urna, vel finibus augue velit et est. Donec dictum erat eleifend lobortis iaculis. Praesent id venenatis ante. Donec feugiat, ipsum eget porttitor pulvinar, nisl odio posuere lorem, ut placerat elit nulla a ligula. Suspendisse nec nibh tincidunt, sollicitudin mi a, volutpat ligula. In maximus quam lacus, eget semper dolor sagittis sit amet.
|
||||||
|
|
||||||
|
In vitae hendrerit est, quis facilisis dui. In eu ante enim. Nullam hendrerit odio sit amet odio tincidunt eleifend. Aliquam erat volutpat. Curabitur commodo, purus pharetra lobortis rhoncus, tortor massa imperdiet nisl, vel dignissim tortor sem at orci. Aliquam maximus lobortis lacus, eu porttitor purus dapibus ut. Praesent at dapibus felis, efficitur blandit tortor. In hac habitasse platea dictumst. Aenean ultrices, nisl a pretium sagittis, tellus sapien mollis erat, eu consectetur erat mauris sed libero. Duis feugiat dapibus mi, vel ornare velit vehicula mattis. Ut suscipit pharetra leo et sollicitudin.
|
||||||
+7
-7
@@ -26,7 +26,7 @@ func getSelfAddress(conn *websocket.Conn) string {
|
|||||||
return responseJSON["address"].(string)
|
return responseJSON["address"].(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendWithoutReply() {
|
func sendTextWithoutReply() {
|
||||||
message := "Hello Nym!"
|
message := "Hello Nym!"
|
||||||
|
|
||||||
uri := "ws://localhost:1977"
|
uri := "ws://localhost:1977"
|
||||||
@@ -62,7 +62,7 @@ func sendWithoutReply() {
|
|||||||
fmt.Printf("received %v from the mix network!\n", string(receivedMessage))
|
fmt.Printf("received %v from the mix network!\n", string(receivedMessage))
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendWithReply() {
|
func sendTextWithReply() {
|
||||||
message := "Hello Nym!"
|
message := "Hello Nym!"
|
||||||
|
|
||||||
uri := "ws://localhost:1977"
|
uri := "ws://localhost:1977"
|
||||||
@@ -97,13 +97,13 @@ func sendWithReply() {
|
|||||||
}
|
}
|
||||||
fmt.Printf("received %v from the mix network!\n", string(receivedMessage))
|
fmt.Printf("received %v from the mix network!\n", string(receivedMessage))
|
||||||
|
|
||||||
receivedMessageJson := make(map[string]interface{})
|
receivedMessageJSON := make(map[string]interface{})
|
||||||
if err := json.Unmarshal(receivedMessage, &receivedMessageJson); err != nil {
|
if err := json.Unmarshal(receivedMessage, &receivedMessageJSON); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// use the received surb to send an anonymous reply!
|
// use the received surb to send an anonymous reply!
|
||||||
replySurb := receivedMessageJson["replySurb"]
|
replySurb := receivedMessageJSON["replySurb"]
|
||||||
replyMessage := "hello from reply SURB!"
|
replyMessage := "hello from reply SURB!"
|
||||||
|
|
||||||
reply, err := json.Marshal(map[string]interface{}{
|
reply, err := json.Marshal(map[string]interface{}{
|
||||||
@@ -129,6 +129,6 @@ func sendWithReply() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// sendWithoutReply()
|
// sendTextWithoutReply()
|
||||||
sendWithReply()
|
sendTextWithReply()
|
||||||
}
|
}
|
||||||
+7909
-1177
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||||
|
|||||||
+34
-23
@@ -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,13 +1,15 @@
|
|||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message, WebSocketStream};
|
use tokio_tungstenite::{
|
||||||
|
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
|
||||||
|
};
|
||||||
use websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
use websocket_requests::{requests::ClientRequest, responses::ServerResponse};
|
||||||
|
|
||||||
// just helpers functions that work in this very particular context because we are sending to ourselves
|
// just helpers functions that work in this very particular context because we are sending to ourselves
|
||||||
// and hence will always get a response back (i.e. the message we sent)
|
// and hence will always get a response back (i.e. the message we sent)
|
||||||
async fn send_message_and_get_response(
|
async fn send_message_and_get_response(
|
||||||
ws_stream: &mut WebSocketStream<TcpStream>,
|
ws_stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||||
req: Vec<u8>,
|
req: Vec<u8>,
|
||||||
) -> ServerResponse {
|
) -> ServerResponse {
|
||||||
ws_stream.send(Message::Binary(req)).await.unwrap();
|
ws_stream.send(Message::Binary(req)).await.unwrap();
|
||||||
@@ -18,7 +20,7 @@ async fn send_message_and_get_response(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_self_address(ws_stream: &mut WebSocketStream<TcpStream>) -> Recipient {
|
async fn get_self_address(ws_stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>) -> Recipient {
|
||||||
let self_address_request = ClientRequest::SelfAddress.serialize();
|
let self_address_request = ClientRequest::SelfAddress.serialize();
|
||||||
let response = send_message_and_get_response(ws_stream, self_address_request).await;
|
let response = send_message_and_get_response(ws_stream, self_address_request).await;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_tungstenite::{connect_async, tungstenite::protocol::Message, WebSocketStream};
|
use tokio_tungstenite::{
|
||||||
|
connect_async, tungstenite::protocol::Message, MaybeTlsStream, WebSocketStream,
|
||||||
|
};
|
||||||
|
|
||||||
// PREFACE: in practice I don't see why you would ever want to use text api while in Rust, but example
|
// PREFACE: in practice I don't see why you would ever want to use text api while in Rust, but example
|
||||||
// is here for the completion sake
|
// is here for the completion sake
|
||||||
@@ -9,7 +11,7 @@ use tokio_tungstenite::{connect_async, tungstenite::protocol::Message, WebSocket
|
|||||||
// just helpers functions that work in this very particular context because we are sending to ourselves
|
// just helpers functions that work in this very particular context because we are sending to ourselves
|
||||||
// and hence will always get a response back (i.e. the message we sent)
|
// and hence will always get a response back (i.e. the message we sent)
|
||||||
async fn send_message_and_get_json_response(
|
async fn send_message_and_get_json_response(
|
||||||
ws_stream: &mut WebSocketStream<TcpStream>,
|
ws_stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>,
|
||||||
text_req: String,
|
text_req: String,
|
||||||
) -> serde_json::Value {
|
) -> serde_json::Value {
|
||||||
ws_stream.send(Message::Text(text_req)).await.unwrap();
|
ws_stream.send(Message::Text(text_req)).await.unwrap();
|
||||||
@@ -20,7 +22,7 @@ async fn send_message_and_get_json_response(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_self_address(ws_stream: &mut WebSocketStream<TcpStream>) -> String {
|
async fn get_self_address(ws_stream: &mut WebSocketStream<MaybeTlsStream<TcpStream>>) -> String {
|
||||||
let self_address_request = json!({ "type": "selfAddress" }).to_string();
|
let self_address_request = json!({ "type": "selfAddress" }).to_string();
|
||||||
let response = send_message_and_get_json_response(ws_stream, self_address_request).await;
|
let response = send_message_and_get_json_response(ws_stream, self_address_request).await;
|
||||||
|
|
||||||
|
|||||||
@@ -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,13 +19,12 @@ 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_url = '{{ client.validator_rest_url }}'
|
validator_api_urls = [
|
||||||
|
{{#each client.validator_api_urls }}
|
||||||
# Special mode of the system such that all messages are sent as soon as they are received
|
'{{this}}',
|
||||||
# and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
{{/each}}
|
||||||
# '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 }}'
|
||||||
@@ -54,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,19 +1,6 @@
|
|||||||
// 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::websocket;
|
|
||||||
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
|
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
|
||||||
use client_core::client::inbound_messages::{
|
use client_core::client::inbound_messages::{
|
||||||
InputMessage, InputMessageReceiver, InputMessageSender,
|
InputMessage, InputMessageReceiver, InputMessageSender,
|
||||||
@@ -35,6 +22,7 @@ use client_core::client::topology_control::{
|
|||||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use crypto::asymmetric::identity;
|
use crypto::asymmetric::identity;
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
|
use gateway_client::bandwidth::BandwidthController;
|
||||||
use gateway_client::{
|
use gateway_client::{
|
||||||
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
|
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
|
||||||
MixnetMessageSender,
|
MixnetMessageSender,
|
||||||
@@ -42,11 +30,13 @@ 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::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 crate::client::config::{Config, SocketType};
|
||||||
|
use crate::websocket;
|
||||||
|
|
||||||
pub(crate) mod config;
|
pub(crate) mod config;
|
||||||
|
|
||||||
pub struct NymClient {
|
pub struct NymClient {
|
||||||
@@ -106,21 +96,20 @@ impl NymClient {
|
|||||||
info!("Starting loop cover traffic stream...");
|
info!("Starting loop cover traffic stream...");
|
||||||
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
||||||
// set in the constructor which HAS TO be called within context of a tokio runtime
|
// set in the constructor which HAS TO be called within context of a tokio runtime
|
||||||
self.runtime
|
let _guard = self.runtime.enter();
|
||||||
.enter(|| {
|
|
||||||
LoopCoverTrafficStream::new(
|
LoopCoverTrafficStream::new(
|
||||||
self.key_manager.ack_key(),
|
self.key_manager.ack_key(),
|
||||||
self.config.get_base().get_average_ack_delay(),
|
self.config.get_base().get_average_ack_delay(),
|
||||||
self.config.get_base().get_average_packet_delay(),
|
self.config.get_base().get_average_packet_delay(),
|
||||||
self.config
|
self.config
|
||||||
.get_base()
|
.get_base()
|
||||||
.get_loop_cover_traffic_average_delay(),
|
.get_loop_cover_traffic_average_delay(),
|
||||||
mix_tx,
|
mix_tx,
|
||||||
self.as_mix_recipient(),
|
self.as_mix_recipient(),
|
||||||
topology_accessor,
|
topology_accessor,
|
||||||
)
|
)
|
||||||
})
|
.start(self.runtime.handle());
|
||||||
.start(self.runtime.handle());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_real_traffic_controller(
|
fn start_real_traffic_controller(
|
||||||
@@ -131,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(),
|
||||||
@@ -145,26 +128,23 @@ 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...");
|
||||||
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
||||||
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
|
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
|
||||||
// When refactoring this restriction should definitely be removed.
|
// When refactoring this restriction should definitely be removed.
|
||||||
let real_messages_controller = self.runtime.enter(|| {
|
let _guard = self.runtime.enter();
|
||||||
RealMessagesController::new(
|
|
||||||
controller_config,
|
RealMessagesController::new(
|
||||||
ack_receiver,
|
controller_config,
|
||||||
input_receiver,
|
ack_receiver,
|
||||||
mix_sender,
|
input_receiver,
|
||||||
topology_accessor,
|
mix_sender,
|
||||||
reply_key_storage,
|
topology_accessor,
|
||||||
)
|
reply_key_storage,
|
||||||
});
|
)
|
||||||
real_messages_controller
|
.start(self.runtime.handle());
|
||||||
.start(self.runtime.handle(), self.config.get_base().get_vpn_mode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer controlling all messages fetched from provider
|
// buffer controlling all messages fetched from provider
|
||||||
@@ -202,41 +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_endpoint(),
|
self.config.get_base().get_validator_api_endpoints(),
|
||||||
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_directory_client(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_endpoint()
|
|
||||||
);
|
|
||||||
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
|
||||||
@@ -297,7 +289,7 @@ impl NymClient {
|
|||||||
/// EXPERIMENTAL DIRECT RUST API
|
/// EXPERIMENTAL DIRECT RUST API
|
||||||
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
|
/// It's untested and there are absolutely no guarantees about it (but seems to have worked
|
||||||
/// well enough in local tests)
|
/// well enough in local tests)
|
||||||
pub fn send_reply(&mut self, reply_surb: ReplySURB, message: Vec<u8>) {
|
pub fn send_reply(&mut self, reply_surb: ReplySurb, message: Vec<u8>) {
|
||||||
let input_msg = InputMessage::new_reply(reply_surb, message);
|
let input_msg = InputMessage::new_reply(reply_surb, message);
|
||||||
|
|
||||||
self.input_tx
|
self.input_tx
|
||||||
@@ -389,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,34 +1,39 @@
|
|||||||
// 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::commands::override_config;
|
|
||||||
use clap::{App, Arg, ArgMatches};
|
use clap::{App, Arg, ArgMatches};
|
||||||
use client_core::client::key_manager::KeyManager;
|
use client_core::client::key_manager::KeyManager;
|
||||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
use coconut_interface::{hash_to_scalar, Credential, Parameters};
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use crypto::asymmetric::identity;
|
#[cfg(feature = "coconut")]
|
||||||
|
use credentials::coconut::bandwidth::{
|
||||||
|
obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES,
|
||||||
|
};
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
use credentials::obtain_aggregate_verification_key;
|
||||||
|
use crypto::asymmetric::{encryption, identity};
|
||||||
use gateway_client::GatewayClient;
|
use gateway_client::GatewayClient;
|
||||||
use gateway_requests::registration::handshake::SharedKeys;
|
use gateway_requests::registration::handshake::SharedKeys;
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
use network_defaults::BANDWIDTH_VALUE;
|
||||||
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
|
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::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use topology::{gateway, NymTopology};
|
use topology::{filter::VersionFilterable, gateway};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::client::config::Config;
|
||||||
|
use crate::commands::override_config;
|
||||||
|
|
||||||
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")
|
||||||
@@ -41,10 +46,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.help("Id of the gateway we are going to connect to.")
|
.help("Id of the gateway we are going to connect to.")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("validator")
|
.arg(Arg::with_name("validators")
|
||||||
.long("validator")
|
.long("validators")
|
||||||
.help("Address of the validator server the client is getting topology from")
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("disable-socket")
|
.arg(Arg::with_name("disable-socket")
|
||||||
.long("disable-socket")
|
.long("disable-socket")
|
||||||
@@ -56,31 +61,64 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// this behaviour should definitely be changed, we shouldn't
|
||||||
|
// need to get bandwidth credential for registration
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
async fn _prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) -> Credential {
|
||||||
|
let verification_key = obtain_aggregate_verification_key(validators)
|
||||||
|
.await
|
||||||
|
.expect("could not obtain aggregate verification key of validators");
|
||||||
|
|
||||||
|
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||||
|
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
|
||||||
|
serial_number: params.random_scalar(),
|
||||||
|
binding_number: params.random_scalar(),
|
||||||
|
voucher_value: hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()),
|
||||||
|
voucher_info: hash_to_scalar(String::from("BandwidthVoucher").as_bytes()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let bandwidth_credential =
|
||||||
|
obtain_signature(¶ms, &bandwidth_credential_attributes, validators)
|
||||||
|
.await
|
||||||
|
.expect("could not obtain bandwidth credential");
|
||||||
|
|
||||||
|
prepare_for_spending(
|
||||||
|
raw_identity,
|
||||||
|
&bandwidth_credential,
|
||||||
|
&bandwidth_credential_attributes,
|
||||||
|
&verification_key,
|
||||||
|
)
|
||||||
|
.expect("could not prepare out bandwidth credential for spending")
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
@@ -90,44 +128,87 @@ 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(validator_server: &str, chosen_gateway_id: Option<&str>) -> gateway::Node {
|
async fn gateway_details(
|
||||||
let validator_client_config = validator_client::Config::new(validator_server.to_string());
|
validator_servers: Vec<Url>,
|
||||||
let validator_client = validator_client::Client::new(validator_client_config);
|
chosen_gateway_id: Option<&str>,
|
||||||
let topology = validator_client.get_active_topology().await.unwrap();
|
) -> gateway::Node {
|
||||||
let nym_topology: NymTopology = topology.into();
|
let validator_api = validator_servers
|
||||||
let version_filtered_topology = nym_topology.filter_system_version(env!("CARGO_PKG_VERSION"));
|
.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_cached_gateways().await.unwrap();
|
||||||
|
let valid_gateways = gateways
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
|
.collect::<Vec<gateway::Node>>();
|
||||||
|
|
||||||
|
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||||
|
|
||||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||||
// be working correctly)
|
// be working correctly)
|
||||||
|
|
||||||
if let Some(gateway_id) = chosen_gateway_id {
|
if let Some(gateway_id) = chosen_gateway_id {
|
||||||
version_filtered_topology
|
filtered_gateways
|
||||||
.gateways()
|
|
||||||
.iter()
|
.iter()
|
||||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||||
.clone()
|
.clone()
|
||||||
} else {
|
} else {
|
||||||
version_filtered_topology
|
filtered_gateways
|
||||||
.gateways()
|
|
||||||
.choose(&mut rand::thread_rng())
|
.choose(&mut rand::thread_rng())
|
||||||
.expect("there are no gateways on the network!")
|
.expect("there are no gateways on the network!")
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn show_address(config: &Config) {
|
||||||
|
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||||
|
let identity_keypair: identity::KeyPair =
|
||||||
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
|
pathfinder.private_identity_key().to_owned(),
|
||||||
|
pathfinder.public_identity_key().to_owned(),
|
||||||
|
))
|
||||||
|
.expect("Failed to read stored identity key files");
|
||||||
|
identity_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||||
|
let sphinx_keypair: encryption::KeyPair =
|
||||||
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
|
pathfinder.private_encryption_key().to_owned(),
|
||||||
|
pathfinder.public_encryption_key().to_owned(),
|
||||||
|
))
|
||||||
|
.expect("Failed to read stored sphinx key files");
|
||||||
|
sphinx_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||||
|
let identity_keypair = load_identity_keys(&pathfinder);
|
||||||
|
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||||
|
|
||||||
|
let client_recipient = Recipient::new(
|
||||||
|
*identity_keypair.public_key(),
|
||||||
|
*sphinx_keypair.public_key(),
|
||||||
|
// TODO: below only works under assumption that gateway address == gateway id
|
||||||
|
// (which currently is true)
|
||||||
|
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("\nThe address of this client is: {}", client_recipient);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn execute(matches: &ArgMatches) {
|
pub fn execute(matches: &ArgMatches) {
|
||||||
println!("Initialising client...");
|
println!("Initialising client...");
|
||||||
|
|
||||||
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 {
|
||||||
@@ -155,7 +236,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_endpoint(),
|
config.get_base().get_validator_api_endpoints(),
|
||||||
chosen_gateway_id,
|
chosen_gateway_id,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@@ -164,11 +245,11 @@ 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?
|
||||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
@@ -188,5 +269,7 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
.expect("Failed to save the config file");
|
.expect("Failed to save the config file");
|
||||||
println!("Saved configuration file to {:?}", config_save_location);
|
println!("Saved configuration file to {:?}", config_save_location);
|
||||||
println!("Using gateway: {}", config.get_base().get_gateway_id(),);
|
println!("Using gateway: {}", config.get_base().get_gateway_id(),);
|
||||||
println!("Client configuration completed.\n\n\n")
|
println!("Client configuration completed.\n\n\n");
|
||||||
|
|
||||||
|
show_address(&config);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,30 @@
|
|||||||
// 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<Url> {
|
||||||
|
raw.split(',')
|
||||||
|
.map(|raw_validator| {
|
||||||
|
raw_validator
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.expect("one of the provided validator api urls is invalid")
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||||
if let Some(validator) = matches.value_of("validator") {
|
if let Some(raw_validators) = matches.value_of("validators") {
|
||||||
config.get_base_mut().set_custom_validator(validator);
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_validator_apis(parse_validators(raw_validators));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(gateway_id) = matches.value_of("gateway") {
|
if let Some(gateway_id) = matches.value_of("gateway") {
|
||||||
@@ -32,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
|
||||||
@@ -44,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")
|
||||||
@@ -30,10 +19,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.required(true)
|
.required(true)
|
||||||
)
|
)
|
||||||
// the rest of arguments are optional, they are used to override settings in config file
|
// the rest of arguments are optional, they are used to override settings in config file
|
||||||
.arg(Arg::with_name("validator")
|
.arg(Arg::with_name("validators")
|
||||||
.long("validator")
|
.long("validators")
|
||||||
.help("Address of the validator server the client is getting topology from")
|
.help("Comma separated list rest rest endpoints of the validators")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("gateway")
|
.arg(Arg::with_name("gateway")
|
||||||
.long("gateway")
|
.long("gateway")
|
||||||
@@ -44,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
|
||||||
@@ -85,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_ENDPOINT;
|
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,199 +36,136 @@ fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_090_upgrade(from: &str, mut config: Config) -> Config {
|
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||||
// this is not extracted to separate function as you only have to manually pass version
|
eprintln!(
|
||||||
// if upgrading from pre090 version
|
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
|
||||||
let from = match from.strip_prefix("v") {
|
config_version, package_version
|
||||||
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_endpoint() != 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_ENDPOINT
|
|
||||||
);
|
);
|
||||||
|
process::exit(1)
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validator(DEFAULT_VALIDATOR_REST_ENDPOINT);
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patch_09x_upgrade(mut config: Config, _matches: &ArgMatches) -> Config {
|
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||||
// this call must succeed as it was already called before
|
|
||||||
let from_version = Version::parse(config.get_base().get_version()).unwrap();
|
|
||||||
let to_version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
|
||||||
|
|
||||||
print_start_upgrade(&from_version, &to_version);
|
|
||||||
|
|
||||||
// 0.9.1 upgrade:
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
|
||||||
|
|
||||||
config.save_to_file(None).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
|
||||||
print_failed_upgrade(&from_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
print_successful_upgrade(from_version, to_version);
|
|
||||||
|
|
||||||
config
|
|
||||||
}
|
|
||||||
|
|
||||||
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),
|
|
||||||
)
|
|
||||||
// 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(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, current_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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_upgrade(mut config: Config, matches: &ArgMatches) {
|
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||||
let current = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
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 {
|
||||||
|
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
||||||
|
eprintln!("failed to parse client version! - {:?}", err);
|
||||||
|
process::exit(1)
|
||||||
|
});
|
||||||
|
|
||||||
|
if version.is_prerelease() || !version.build.is_empty() {
|
||||||
|
eprintln!(
|
||||||
|
"Trying to upgrade from a non-released version {}. This is not supported!",
|
||||||
|
version
|
||||||
|
);
|
||||||
|
process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
version
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_package_version() -> Version {
|
||||||
|
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||||
|
|
||||||
|
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
||||||
|
// however, we are not using them ourselves at the moment and hence it should be fine.
|
||||||
|
// if we change our mind, we could easily tweak this code
|
||||||
|
if version.is_prerelease() || !version.build.is_empty() {
|
||||||
|
eprintln!(
|
||||||
|
"Trying to upgrade to a non-released version {}. This is not supported!",
|
||||||
|
version
|
||||||
|
);
|
||||||
|
process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
version
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minor_0_12_upgrade(
|
||||||
|
mut config: Config,
|
||||||
|
_matches: &ArgMatches,
|
||||||
|
config_version: &Version,
|
||||||
|
package_version: &Version,
|
||||||
|
) -> Config {
|
||||||
|
let to_version = if package_version.major == 0 && package_version.minor == 12 {
|
||||||
|
package_version.clone()
|
||||||
|
} else {
|
||||||
|
Version::new(0, 12, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_start_upgrade(&config_version, &to_version);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Setting validator API endpoints to {:?}",
|
||||||
|
default_api_endpoints()
|
||||||
|
);
|
||||||
|
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_validator_apis(default_api_endpoints());
|
||||||
|
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_version(to_version.to_string().as_ref());
|
||||||
|
|
||||||
|
config.save_to_file(None).unwrap_or_else(|err| {
|
||||||
|
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||||
|
print_failed_upgrade(&config_version, &to_version);
|
||||||
|
process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
print_successful_upgrade(config_version, to_version);
|
||||||
|
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version) {
|
||||||
loop {
|
loop {
|
||||||
let config_version =
|
let config_version = parse_config_version(&config);
|
||||||
Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to parse client version! - {:?}", err);
|
|
||||||
process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
if config_version == current {
|
if config_version == package_version {
|
||||||
println!("You're using the most recent version!");
|
println!("You're using the most recent version!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
config = match config_version.major {
|
config = match config_version.major {
|
||||||
0 => match config_version.minor {
|
0 => match config_version.minor {
|
||||||
9 => patch_09x_upgrade(config, &matches),
|
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||||
_ => unsupported_upgrade(current, config_version),
|
11 => minor_0_12_upgrade(config, matches, &config_version, &package_version),
|
||||||
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
},
|
},
|
||||||
_ => unsupported_upgrade(current, config_version),
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(matches: &ArgMatches) {
|
pub fn execute(matches: &ArgMatches) {
|
||||||
let current = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
let package_version = parse_package_version();
|
||||||
|
|
||||||
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
|
||||||
// however, we are not using them ourselves at the moment and hence it should be fine.
|
|
||||||
// if we change our mind, we could easily tweak this code
|
|
||||||
if current.is_prerelease() || !current.build.is_empty() {
|
|
||||||
eprintln!(
|
|
||||||
"Trying to upgrade to a non-released version {}. This is not supported!",
|
|
||||||
current
|
|
||||||
);
|
|
||||||
process::exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let config_version =
|
|
||||||
Version::parse(existing_config.get_base().get_version()).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to parse client version! - {:?}", err);
|
|
||||||
process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
if config_version.is_prerelease() || !config_version.build.is_empty() {
|
|
||||||
eprintln!(
|
|
||||||
"Trying to upgrade from non-released version {}. This is not supported!",
|
|
||||||
config_version
|
|
||||||
);
|
|
||||||
process::exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
if config_version == current {
|
do_upgrade(existing_config, matches, package_version)
|
||||||
println!("You're using the most recent version!");
|
|
||||||
} else {
|
|
||||||
do_upgrade(existing_config, matches)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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},
|
||||||
@@ -22,7 +11,7 @@ use futures::channel::mpsc;
|
|||||||
use futures::{SinkExt, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::ReplySURB;
|
use nymsphinx::anonymous_replies::ReplySurb;
|
||||||
use nymsphinx::receiver::ReconstructedMessage;
|
use nymsphinx::receiver::ReconstructedMessage;
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use tokio_tungstenite::{
|
use tokio_tungstenite::{
|
||||||
@@ -100,9 +89,9 @@ impl Handler {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_reply(&mut self, reply_surb: ReplySURB, message: Vec<u8>) -> Option<ServerResponse> {
|
fn handle_reply(&mut self, reply_surb: ReplySurb, message: Vec<u8>) -> Option<ServerResponse> {
|
||||||
if message.len() > ReplySURB::max_msg_len(Default::default()) {
|
if message.len() > ReplySurb::max_msg_len(Default::default()) {
|
||||||
return Some(ServerResponse::new_error(format!("too long message to put inside a reply SURB. Received: {} bytes and maximum is {} bytes", message.len(), ReplySURB::max_msg_len(Default::default()))));
|
return Some(ServerResponse::new_error(format!("too long message to put inside a reply SURB. Received: {} bytes and maximum is {} bytes", message.len(), ReplySurb::max_msg_len(Default::default()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_msg = InputMessage::new_reply(reply_surb, message);
|
let input_msg = InputMessage::new_reply(reply_surb, message);
|
||||||
|
|||||||
@@ -1,23 +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 super::handler::Handler;
|
use super::handler::Handler;
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::{
|
use std::{net::SocketAddr, process, sync::Arc};
|
||||||
net::{Shutdown, SocketAddr},
|
use tokio::io::AsyncWriteExt;
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
use tokio::runtime;
|
use tokio::runtime;
|
||||||
use tokio::{sync::Notify, task::JoinHandle};
|
use tokio::{sync::Notify, task::JoinHandle};
|
||||||
|
|
||||||
@@ -47,9 +34,13 @@ impl Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn run(&mut self, handler: Handler) {
|
pub(crate) async fn run(&mut self, handler: Handler) {
|
||||||
let mut tcp_listener = tokio::net::TcpListener::bind(self.address)
|
let tcp_listener = match tokio::net::TcpListener::bind(self.address).await {
|
||||||
.await
|
Ok(listener) => listener,
|
||||||
.expect("Failed to start websocket listener");
|
Err(err) => {
|
||||||
|
error!("Failed to bind to {} - {}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?", self.address, err);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let notify = Arc::new(Notify::new());
|
let notify = Arc::new(Notify::new());
|
||||||
|
|
||||||
@@ -61,7 +52,7 @@ impl Listener {
|
|||||||
}
|
}
|
||||||
new_conn = tcp_listener.accept() => {
|
new_conn = tcp_listener.accept() => {
|
||||||
match new_conn {
|
match new_conn {
|
||||||
Ok((socket, remote_addr)) => {
|
Ok((mut socket, remote_addr)) => {
|
||||||
debug!("Received connection from {:?}", remote_addr);
|
debug!("Received connection from {:?}", remote_addr);
|
||||||
if self.state.is_connected() {
|
if self.state.is_connected() {
|
||||||
warn!("tried to duplicate!");
|
warn!("tried to duplicate!");
|
||||||
@@ -70,7 +61,7 @@ impl Listener {
|
|||||||
// while we only ever want to accept a single connection, we don't want
|
// while we only ever want to accept a single connection, we don't want
|
||||||
// to leave clients hanging (and also allow for reconnection if it somehow
|
// to leave clients hanging (and also allow for reconnection if it somehow
|
||||||
// was dropped)
|
// was dropped)
|
||||||
match socket.shutdown(Shutdown::Both) {
|
match socket.shutdown().await {
|
||||||
Ok(_) => trace!(
|
Ok(_) => trace!(
|
||||||
"closed the connection between attempting websocket handshake"
|
"closed the connection between attempting websocket handshake"
|
||||||
),
|
),
|
||||||
@@ -84,7 +75,7 @@ impl Listener {
|
|||||||
let fresh_handler = handler.clone();
|
let fresh_handler = handler.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
fresh_handler.handle_connection(socket).await;
|
fresh_handler.handle_connection(socket).await;
|
||||||
notify_clone.notify();
|
notify_clone.notify_one();
|
||||||
});
|
});
|
||||||
self.state = State::Connected;
|
self.state = State::Connected;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,8 @@
|
|||||||
// 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 listener;
|
|
||||||
|
|
||||||
pub(crate) use handler::Handler;
|
pub(crate) use handler::Handler;
|
||||||
pub(crate) use listener::Listener;
|
pub(crate) use listener::Listener;
|
||||||
|
|
||||||
|
pub(crate) mod handler;
|
||||||
|
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;
|
||||||
@@ -55,7 +44,7 @@ pub enum ErrorKind {
|
|||||||
/// The received request is malformed.
|
/// The received request is malformed.
|
||||||
MalformedRequest = 0x04,
|
MalformedRequest = 0x04,
|
||||||
|
|
||||||
// that's an arbitrary division but lets keep 1-127 (hex 0x01 - 0x7F) values request-specific
|
// that's an arbitrary division but let's keep 1-127 (hex 0x01 - 0x7F) values request-specific
|
||||||
// and 128-254 (hex 0x80 - 0xFE) for responses
|
// and 128-254 (hex 0x80 - 0xFE) for responses
|
||||||
/// The received response contained no data.
|
/// The received response contained no data.
|
||||||
EmptyResponse = 0x80,
|
EmptyResponse = 0x80,
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -18,7 +7,7 @@
|
|||||||
use crate::error::{self, ErrorKind};
|
use crate::error::{self, ErrorKind};
|
||||||
use crate::text::ClientRequestText;
|
use crate::text::ClientRequestText;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::ReplySURB;
|
use nymsphinx::anonymous_replies::ReplySurb;
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
|
|
||||||
@@ -42,7 +31,7 @@ pub enum ClientRequest {
|
|||||||
},
|
},
|
||||||
Reply {
|
Reply {
|
||||||
message: Vec<u8>,
|
message: Vec<u8>,
|
||||||
reply_surb: ReplySURB,
|
reply_surb: ReplySurb,
|
||||||
},
|
},
|
||||||
SelfAddress,
|
SelfAddress,
|
||||||
}
|
}
|
||||||
@@ -119,7 +108,7 @@ impl ClientRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// REPLY_REQUEST_TAG || surb_len || surb || message_len || message
|
// REPLY_REQUEST_TAG || surb_len || surb || message_len || message
|
||||||
fn serialize_reply(message: Vec<u8>, reply_surb: ReplySURB) -> Vec<u8> {
|
fn serialize_reply(message: Vec<u8>, reply_surb: ReplySurb) -> Vec<u8> {
|
||||||
let reply_surb_bytes = reply_surb.to_bytes();
|
let reply_surb_bytes = reply_surb.to_bytes();
|
||||||
let surb_len_bytes = (reply_surb_bytes.len() as u64).to_be_bytes();
|
let surb_len_bytes = (reply_surb_bytes.len() as u64).to_be_bytes();
|
||||||
let message_len_bytes = (message.len() as u64).to_be_bytes();
|
let message_len_bytes = (message.len() as u64).to_be_bytes();
|
||||||
@@ -164,7 +153,7 @@ impl ClientRequest {
|
|||||||
let surb_bound = 1 + size_of::<u64>() + reply_surb_len as usize;
|
let surb_bound = 1 + size_of::<u64>() + reply_surb_len as usize;
|
||||||
|
|
||||||
let reply_surb_bytes = &b[1 + size_of::<u64>()..surb_bound];
|
let reply_surb_bytes = &b[1 + size_of::<u64>()..surb_bound];
|
||||||
let reply_surb = match ReplySURB::from_bytes(reply_surb_bytes) {
|
let reply_surb = match ReplySurb::from_bytes(reply_surb_bytes) {
|
||||||
Ok(reply_surb) => reply_surb,
|
Ok(reply_surb) => reply_surb,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(error::Error::new(
|
return Err(error::Error::new(
|
||||||
@@ -206,11 +195,11 @@ impl ClientRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SELF_ADDRESS_REQUEST_TAG
|
// SELF_ADDRESS_REQUEST_TAG
|
||||||
fn deserialize_self_address(b: &[u8]) -> Result<Self, error::Error> {
|
fn deserialize_self_address(b: &[u8]) -> Self {
|
||||||
// this MUST match because it was called by 'deserialize'
|
// this MUST match because it was called by 'deserialize'
|
||||||
debug_assert_eq!(b[0], SELF_ADDRESS_REQUEST_TAG);
|
debug_assert_eq!(b[0], SELF_ADDRESS_REQUEST_TAG);
|
||||||
|
|
||||||
Ok(ClientRequest::SelfAddress)
|
ClientRequest::SelfAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize(self) -> Vec<u8> {
|
pub fn serialize(self) -> Vec<u8> {
|
||||||
@@ -255,7 +244,7 @@ impl ClientRequest {
|
|||||||
match request_tag {
|
match request_tag {
|
||||||
SEND_REQUEST_TAG => Self::deserialize_send(b),
|
SEND_REQUEST_TAG => Self::deserialize_send(b),
|
||||||
REPLY_REQUEST_TAG => Self::deserialize_reply(b),
|
REPLY_REQUEST_TAG => Self::deserialize_reply(b),
|
||||||
SELF_ADDRESS_REQUEST_TAG => Self::deserialize_self_address(b),
|
SELF_ADDRESS_REQUEST_TAG => Ok(Self::deserialize_self_address(b)),
|
||||||
n => Err(error::Error::new(
|
n => Err(error::Error::new(
|
||||||
ErrorKind::UnknownRequest,
|
ErrorKind::UnknownRequest,
|
||||||
format!("type {}", n),
|
format!("type {}", n),
|
||||||
@@ -333,7 +322,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn reply_request_serialization_works() {
|
fn reply_request_serialization_works() {
|
||||||
let reply_surb_string = "CjfVbHbfAjbC3W1BvNHGXmM8KNAnDNYGaHMLqVDxRYeo352csAihstup9bvqXam4dTWgfHak6KYwL9STaxWJ47E8XFZbSEvs7hEsfCkxr6K9WJuSBPK84GDDEvad8ZAuMCoaXsAd5S2Lj9a5eYyzG4SL1jHzhSMni55LyJwumxo1ZTGZNXggxw1RREosvyzNrW9Rsi3owyPqLCwXpiei2tHZty8w8midVvg8vDa7ZEJD842CLv8D4ohynSG7gDpqTrhkRaqYAuz7dzqNbMXLJRM7v823Jn16fA1L7YQxmcaUdUigyRSgTdb4i9ebiLGSyJ1iDe6Acz613PQZh6Ua3bZ2zVKq3dSycpDm9ngarRK4zJrAaUxRkdih8YzW3BY4nL9eqkfKA4N1TWCLaRU7zpSaf8yMEwrAZReU3d5zLV8c5KBfa2w8R5anhQeBojduZEGEad8kkHuKU52Zg93FeWHvH1qgZaEJMHH4nN7gKXz9mvWDhYwyF4vt3Uy2NhCHC3N5pL1gMme27YcoPcTEia1fxKZtnt6rtEozzTrAgCJGswigkFbkafiV5QaJwLKTUxtzhkZ57eEuLPte9UvJHzhhXUQ2CV7R2BUkJjYZy3Zsx6YYvdYWiAFFkWUwNEGA4QpShUHciBfsQVHQ7pN41YcyYUhbywQDFnTVgEmdUZ1XCBi3gyK5U3tDQmFzP1u9m3mWrUA8qB9mRDE7ptNDm5c3c1458L6uXLUth7sdMaa1Was5LCmCdmNDtvNpCDAEt1in6q6mrZFR85aCSU9b1baNGwZoCqPpPvydkVe63gXWoi8ebvdyxARrqACFrSB3ZdY3uJBw8CTMNkKK6MvcefMkSVVsbLd36TQAtYSCqrpiMc5dQuKcEu5QfciwvWYXYx8WFNAgKwP2mv49KCTvfozNDUCbjzDwSx92Zv5zjG8HbFpB13bY9UZGeyTPvv7gGxCzjGjJGbW6FRAheRQaaje5fUgCNM95Tv7wBmAMRHHFgWafeK1sdFH7dtCX9u898HucGTaboSKLsVh8J78gbbkHErwjMh7y9YRkceq5TTYS5da4kHnyNKYWSbxgZrmFg44XGKoeYcqoHB3XTZrdsf7F5fFeNwnihkmADvhAcaxXUmVqq4rQFZH84a1iC3WBWXYcqiZH2L7ujGWV7mMDT4HBEerDYjc8rNY4xGTPfivCrBCJW1i14aqW8xRdsdgTM88eTksvC3WPJLJ7iMzfKXeL7fMW1Ek6QGyQtLBW98vEESpdcDg6DeZ5rMz6VqjTGGqcCaFGfHoqtfxMDaBAEsyQ8h7XDX6dg1wq9wH6j4Tw7Tj1MEv1b8uj5NJkozZdzVdYA2QyE2Dp8vuurQG6uVdTDNww2d88RBQ8sVgjxN8gR45y4woJLhFAaNTAtrY6wDTxyXST13ni6oyqdYxjFVk9Am4v3DzH7Y2K8iRVSHfTk4FRbPULyaeK6wt2anvMJH1XdvVRgc14h67MnBxMgMD1UFk8AErN7CDj26fppe3c5G6KozJe4cSqQUGbBjVzBnrHCruqrfZBn5hNZHTV37bQiomqhRQXohxhuKEnNrGbAe1xNvJr9X";
|
let reply_surb_string = "CjfVbHbfAjbC3W1BvNHGXmM8KNAnDNYGaHMLqVDxRYeo352csAihstup9bvqXam4dTWgfHak6KYwL9STaxWJ47E8XFZbSEvs7hEsfCkxr6K9WJuSBPK84GDDEvad8ZAuMCoaXsAd5S2Lj9a5eYyzG4SL1jHzhSMni55LyJwumxo1ZTGZNXggxw1RREosvyzNrW9Rsi3owyPqLCwXpiei2tHZty8w8midVvg8vDa7ZEJD842CLv8D4ohynSG7gDpqTrhkRaqYAuz7dzqNbMXLJRM7v823Jn16fA1L7YQxmcaUdUigyRSgTdb4i9ebiLGSyJ1iDe6Acz613PQZh6Ua3bZ2zVKq3dSycpDm9ngarRK4zJrAaUxRkdih8YzW3BY4nL9eqkfKA4N1TWCLaRU7zpSaf8yMEwrAZReU3d5zLV8c5KBfa2w8R5anhQeBojduZEGEad8kkHuKU52Zg93FeWHvH1qgZaEJMHH4nN7gKXz9mvWDhYwyF4vt3Uy2NhCHC3N5pL1gMme27YcoPcTEia1fxKZtnt6rtEozzTrAgCJGswigkFbkafiV5QaJwLKTUxtzhkZ57eEuLPte9UvJHzhhXUQ2CV7R2BUkJjYZy3Zsx6YYvdYWiAFFkWUwNEGA4QpShUHciBfsQVHQ7pN41YcyYUhbywQDFnTVgEmdUZ1XCBi3gyK5U3tDQmFzP1u9m3mWrUA8qB9mRDE7ptNDm5c3c1458L6uXLUth7sdMaa1Was5LCmCdmNDtvNpCDAEt1in6q6mrZFR85aCSU9b1baNGwZoCqPpPvydkVe63gXWoi8ebvdyxARrqACFrSB3ZdY3uJBw8CTMNkKK6MvcefMkSVVsbLd36TQAtYSCqrpiMc5dQuKcEu5QfciwvWYXYx8WFNAgKwP2mv49KCTvfozNDUCbjzDwSx92Zv5zjG8HbFpB13bY9UZGeyTPvv7gGxCzjGjJGbW6FRAheRQaaje5fUgCNM95Tv7wBmAMRHHFgWafeK1sdFH7dtCX9u898HucGTaboSKLsVh8J78gbbkHErwjMh7y9YRkceq5TTYS5da4kHnyNKYWSbxgZrmFg44XGKoeYcqoHB3XTZrdsf7F5fFeNwnihkmADvhAcaxXUmVqq4rQFZH84a1iC3WBWXYcqiZH2L7ujGWV7mMDT4HBEerDYjc8rNY4xGTPfivCrBCJW1i14aqW8xRdsdgTM88eTksvC3WPJLJ7iMzfKXeL7fMW1Ek6QGyQtLBW98vEESpdcDg6DeZ5rMz6VqjTGGqcCaFGfHoqtfxMDaBAEsyQ8h7XDX6dg1wq9wH6j4Tw7Tj1MEv1b8uj5NJkozZdzVdYA2QyE2Dp8vuurQG6uVdTDNww2d88RBQ8sVgjxN8gR45y4woJLhFAaNTAtrY6wDTxyXST13ni6oyqdYxjFVk9Am4v3DzH7Y2K8iRVSHfTk4FRbPULyaeK6wt2anvMJH1XdvVRgc14h67MnBxMgMD1UFk8AErN7CDj26fppe3c5G6KozJe4cSqQUGbBjVzBnrHCruqrfZBn5hNZHTV37bQiomqhRQXohxhuKEnNrGbAe1xNvJr9X";
|
||||||
let reply_surb = ReplySURB::from_base58_string(reply_surb_string).unwrap();
|
let reply_surb = ReplySurb::from_base58_string(reply_surb_string).unwrap();
|
||||||
let reply_request = ClientRequest::Reply {
|
let reply_request = ClientRequest::Reply {
|
||||||
message: b"foomp".to_vec(),
|
message: b"foomp".to_vec(),
|
||||||
reply_surb,
|
reply_surb,
|
||||||
|
|||||||
@@ -1,24 +1,15 @@
|
|||||||
// 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
|
||||||
|
|
||||||
|
#![allow(unknown_lints)] // due to using `clippy::branches_sharing_code` which does not exist on `stable` just yet
|
||||||
|
|
||||||
use crate::error::{self, ErrorKind};
|
use crate::error::{self, ErrorKind};
|
||||||
use crate::text::ServerResponseText;
|
use crate::text::ServerResponseText;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::ReplySURB;
|
use nymsphinx::anonymous_replies::ReplySurb;
|
||||||
use nymsphinx::receiver::ReconstructedMessage;
|
use nymsphinx::receiver::ReconstructedMessage;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
@@ -96,6 +87,8 @@ impl ServerResponse {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// this is a false positive as even though the code is the same, it refers to different things
|
||||||
|
#[allow(clippy::branches_sharing_code)]
|
||||||
if with_reply_surb {
|
if with_reply_surb {
|
||||||
let reply_surb_len =
|
let reply_surb_len =
|
||||||
u64::from_be_bytes(b[2..2 + size_of::<u64>()].as_ref().try_into().unwrap());
|
u64::from_be_bytes(b[2..2 + size_of::<u64>()].as_ref().try_into().unwrap());
|
||||||
@@ -111,7 +104,7 @@ impl ServerResponse {
|
|||||||
let surb_bound = 2 + size_of::<u64>() + reply_surb_len as usize;
|
let surb_bound = 2 + size_of::<u64>() + reply_surb_len as usize;
|
||||||
|
|
||||||
let reply_surb_bytes = &b[2 + size_of::<u64>()..surb_bound];
|
let reply_surb_bytes = &b[2 + size_of::<u64>()..surb_bound];
|
||||||
let reply_surb = match ReplySURB::from_bytes(reply_surb_bytes) {
|
let reply_surb = match ReplySurb::from_bytes(reply_surb_bytes) {
|
||||||
Ok(reply_surb) => reply_surb,
|
Ok(reply_surb) => reply_surb,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(error::Error::new(
|
return Err(error::Error::new(
|
||||||
@@ -339,7 +332,7 @@ mod tests {
|
|||||||
|
|
||||||
let received_with_surb = ServerResponse::Received(ReconstructedMessage {
|
let received_with_surb = ServerResponse::Received(ReconstructedMessage {
|
||||||
message: b"foomp".to_vec(),
|
message: b"foomp".to_vec(),
|
||||||
reply_surb: Some(ReplySURB::from_base58_string(reply_surb_string).unwrap()),
|
reply_surb: Some(ReplySurb::from_base58_string(reply_surb_string).unwrap()),
|
||||||
});
|
});
|
||||||
let bytes = received_with_surb.serialize();
|
let bytes = received_with_surb.serialize();
|
||||||
let recovered = ServerResponse::deserialize(&bytes).unwrap();
|
let recovered = ServerResponse::deserialize(&bytes).unwrap();
|
||||||
|
|||||||
@@ -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.
|
|
||||||
|
|
||||||
use crate::error::ErrorKind;
|
use crate::error::ErrorKind;
|
||||||
use crate::requests::ClientRequest;
|
use crate::requests::ClientRequest;
|
||||||
use crate::responses::ServerResponse;
|
use crate::responses::ServerResponse;
|
||||||
use nymsphinx::addressing::clients::Recipient;
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
use nymsphinx::anonymous_replies::ReplySURB;
|
use nymsphinx::anonymous_replies::ReplySurb;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
@@ -75,7 +64,7 @@ impl TryInto<ClientRequest> for ClientRequestText {
|
|||||||
reply_surb,
|
reply_surb,
|
||||||
} => {
|
} => {
|
||||||
let message_bytes = message.into_bytes();
|
let message_bytes = message.into_bytes();
|
||||||
let reply_surb = ReplySURB::from_base58_string(reply_surb).map_err(|err| {
|
let reply_surb = ReplySurb::from_base58_string(reply_surb).map_err(|err| {
|
||||||
Self::Error::new(ErrorKind::MalformedRequest, err.to_string())
|
Self::Error::new(ErrorKind::MalformedRequest, err.to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -115,15 +104,15 @@ impl TryFrom<String> for ServerResponseText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<String> for ServerResponseText {
|
impl From<ServerResponseText> for String {
|
||||||
fn into(self) -> String {
|
fn from(res: ServerResponseText) -> Self {
|
||||||
// per serde_json docs:
|
// per serde_json docs:
|
||||||
/*
|
/*
|
||||||
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
|
/// Serialization can fail if `T`'s implementation of `Serialize` decides to
|
||||||
/// fail, or if `T` contains a map with non-string keys.
|
/// fail, or if `T` contains a map with non-string keys.
|
||||||
*/
|
*/
|
||||||
// this is not the case here.
|
// this is not the case here.
|
||||||
serde_json::to_string(&self).unwrap()
|
serde_json::to_string(&res).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "0.9.2"
|
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"
|
||||||
@@ -14,23 +15,31 @@ dirs = "3.0" # for determining default store directories in config
|
|||||||
dotenv = "0.15.0"
|
dotenv = "0.15.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pin-project = "0.4"
|
pin-project = "1.0"
|
||||||
pretty_env_logger = "0.3"
|
pretty_env_logger = "0.4"
|
||||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
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.4.1"
|
snafu = "0.6"
|
||||||
tokio = { version = "0.2", features = ["rt-threaded"] }
|
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" }
|
||||||
gateway-requests = { path = "../../gateway/gateway-requests" }
|
gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||||
nymsphinx = { path = "../../common/nymsphinx" }
|
nymsphinx = { path = "../../common/nymsphinx" }
|
||||||
ordered-buffer = {path = "../../common/socks5/ordered-buffer"}
|
ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
|
||||||
socks5-requests = { path = "../../common/socks5/requests" }
|
socks5-requests = { path = "../../common/socks5/requests" }
|
||||||
topology = { path = "../../common/topology" }
|
topology = { path = "../../common/topology" }
|
||||||
|
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" }
|
||||||
|
network-defaults = { path = "../../common/network-defaults" }
|
||||||
|
|
||||||
|
[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,13 +19,12 @@ 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_url = '{{ client.validator_rest_url }}'
|
validator_api_urls = [
|
||||||
|
{{#each client.validator_api_urls }}
|
||||||
# Special mode of the system such that all messages are sent as soon as they are received
|
'{{this}}',
|
||||||
# and no cover traffic is generated. If set all message delays are set to 0 and overwriting
|
{{/each}}
|
||||||
# '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 }}'
|
||||||
@@ -54,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,22 +1,6 @@
|
|||||||
// 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::socks::{
|
|
||||||
authentication::{AuthenticationMethods, Authenticator, User},
|
|
||||||
server::SphinxSocksServer,
|
|
||||||
};
|
|
||||||
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
|
use client_core::client::cover_traffic_stream::LoopCoverTrafficStream;
|
||||||
use client_core::client::inbound_messages::{
|
use client_core::client::inbound_messages::{
|
||||||
InputMessage, InputMessageReceiver, InputMessageSender,
|
InputMessage, InputMessageReceiver, InputMessageSender,
|
||||||
@@ -36,6 +20,7 @@ use client_core::client::topology_control::{
|
|||||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
use crypto::asymmetric::identity;
|
use crypto::asymmetric::identity;
|
||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
|
use gateway_client::bandwidth::BandwidthController;
|
||||||
use gateway_client::{
|
use gateway_client::{
|
||||||
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
|
AcknowledgementReceiver, AcknowledgementSender, GatewayClient, MixnetMessageReceiver,
|
||||||
MixnetMessageSender,
|
MixnetMessageSender,
|
||||||
@@ -43,9 +28,14 @@ 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 crate::client::config::Config;
|
||||||
|
use crate::socks::{
|
||||||
|
authentication::{AuthenticationMethods, Authenticator, User},
|
||||||
|
server::SphinxSocksServer,
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) mod config;
|
pub(crate) mod config;
|
||||||
|
|
||||||
pub struct NymClient {
|
pub struct NymClient {
|
||||||
@@ -94,21 +84,20 @@ impl NymClient {
|
|||||||
info!("Starting loop cover traffic stream...");
|
info!("Starting loop cover traffic stream...");
|
||||||
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
||||||
// set in the constructor which HAS TO be called within context of a tokio runtime
|
// set in the constructor which HAS TO be called within context of a tokio runtime
|
||||||
self.runtime
|
let _guard = self.runtime.enter();
|
||||||
.enter(|| {
|
|
||||||
LoopCoverTrafficStream::new(
|
LoopCoverTrafficStream::new(
|
||||||
self.key_manager.ack_key(),
|
self.key_manager.ack_key(),
|
||||||
self.config.get_base().get_average_ack_delay(),
|
self.config.get_base().get_average_ack_delay(),
|
||||||
self.config.get_base().get_average_packet_delay(),
|
self.config.get_base().get_average_packet_delay(),
|
||||||
self.config
|
self.config
|
||||||
.get_base()
|
.get_base()
|
||||||
.get_loop_cover_traffic_average_delay(),
|
.get_loop_cover_traffic_average_delay(),
|
||||||
mix_tx,
|
mix_tx,
|
||||||
self.as_mix_recipient(),
|
self.as_mix_recipient(),
|
||||||
topology_accessor,
|
topology_accessor,
|
||||||
)
|
)
|
||||||
})
|
.start(self.runtime.handle());
|
||||||
.start(self.runtime.handle());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_real_traffic_controller(
|
fn start_real_traffic_controller(
|
||||||
@@ -119,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(),
|
||||||
@@ -133,26 +116,23 @@ 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...");
|
||||||
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
// we need to explicitly enter runtime due to "next_delay: time::delay_for(Default::default())"
|
||||||
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
|
// set in the constructor [of OutQueueControl] which HAS TO be called within context of a tokio runtime
|
||||||
// When refactoring this restriction should definitely be removed.
|
// When refactoring this restriction should definitely be removed.
|
||||||
let real_messages_controller = self.runtime.enter(|| {
|
let _guard = self.runtime.enter();
|
||||||
RealMessagesController::new(
|
|
||||||
controller_config,
|
RealMessagesController::new(
|
||||||
ack_receiver,
|
controller_config,
|
||||||
input_receiver,
|
ack_receiver,
|
||||||
mix_sender,
|
input_receiver,
|
||||||
topology_accessor,
|
mix_sender,
|
||||||
reply_key_storage,
|
topology_accessor,
|
||||||
)
|
reply_key_storage,
|
||||||
});
|
)
|
||||||
real_messages_controller
|
.start(self.runtime.handle());
|
||||||
.start(self.runtime.handle(), self.config.get_base().get_vpn_mode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffer controlling all messages fetched from provider
|
// buffer controlling all messages fetched from provider
|
||||||
@@ -190,41 +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_endpoint(),
|
self.config.get_base().get_validator_api_endpoints(),
|
||||||
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_directory_client(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_endpoint()
|
|
||||||
);
|
|
||||||
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
|
||||||
@@ -261,8 +253,7 @@ impl NymClient {
|
|||||||
msg_input: InputMessageSender,
|
msg_input: InputMessageSender,
|
||||||
) {
|
) {
|
||||||
info!("Starting socks5 listener...");
|
info!("Starting socks5 listener...");
|
||||||
let mut auth_methods: Vec<u8> = Vec::new();
|
let auth_methods = vec![AuthenticationMethods::NoAuth as u8];
|
||||||
auth_methods.push(AuthenticationMethods::NoAuth as u8);
|
|
||||||
let allowed_users: Vec<User> = Vec::new();
|
let allowed_users: Vec<User> = Vec::new();
|
||||||
|
|
||||||
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
let authenticator = Authenticator::new(auth_methods, allowed_users);
|
||||||
@@ -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,33 +1,37 @@
|
|||||||
// 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::commands::override_config;
|
|
||||||
use clap::{App, Arg, ArgMatches};
|
use clap::{App, Arg, ArgMatches};
|
||||||
use client_core::client::key_manager::KeyManager;
|
use client_core::client::key_manager::KeyManager;
|
||||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
use coconut_interface::{hash_to_scalar, Credential, Parameters};
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use crypto::asymmetric::identity;
|
#[cfg(feature = "coconut")]
|
||||||
|
use credentials::coconut::bandwidth::{
|
||||||
|
obtain_signature, prepare_for_spending, BandwidthVoucherAttributes, TOTAL_ATTRIBUTES,
|
||||||
|
};
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
use credentials::obtain_aggregate_verification_key;
|
||||||
|
use crypto::asymmetric::{encryption, identity};
|
||||||
use gateway_client::GatewayClient;
|
use gateway_client::GatewayClient;
|
||||||
use gateway_requests::registration::handshake::SharedKeys;
|
use gateway_requests::registration::handshake::SharedKeys;
|
||||||
use rand::{prelude::SliceRandom, rngs::OsRng};
|
#[cfg(feature = "coconut")]
|
||||||
|
use network_defaults::BANDWIDTH_VALUE;
|
||||||
|
use nymsphinx::addressing::clients::Recipient;
|
||||||
|
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||||
|
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use topology::{gateway, NymTopology};
|
use topology::{filter::VersionFilterable, gateway};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use crate::client::config::Config;
|
||||||
|
use crate::commands::override_config;
|
||||||
|
|
||||||
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")
|
||||||
@@ -46,10 +50,10 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.help("Id of the gateway we are going to connect to.")
|
.help("Id of the gateway we are going to connect to.")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("validator")
|
.arg(Arg::with_name("validators")
|
||||||
.long("validator")
|
.long("validators")
|
||||||
.help("Address of the validator server the client is getting topology from")
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("port")
|
.arg(Arg::with_name("port")
|
||||||
.short("p")
|
.short("p")
|
||||||
@@ -57,31 +61,64 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.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
|
||||||
|
}
|
||||||
|
|
||||||
|
// this behaviour should definitely be changed, we shouldn't
|
||||||
|
// need to get bandwidth credential for registration
|
||||||
|
#[cfg(feature = "coconut")]
|
||||||
|
async fn _prepare_temporary_credential(validators: &[Url], raw_identity: &[u8]) -> Credential {
|
||||||
|
let verification_key = obtain_aggregate_verification_key(validators)
|
||||||
|
.await
|
||||||
|
.expect("could not obtain aggregate verification key of validators");
|
||||||
|
|
||||||
|
let params = Parameters::new(TOTAL_ATTRIBUTES).unwrap();
|
||||||
|
let bandwidth_credential_attributes = BandwidthVoucherAttributes {
|
||||||
|
serial_number: params.random_scalar(),
|
||||||
|
binding_number: params.random_scalar(),
|
||||||
|
voucher_value: hash_to_scalar(BANDWIDTH_VALUE.to_be_bytes()),
|
||||||
|
voucher_info: hash_to_scalar("BandwidthVoucher"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let bandwidth_credential =
|
||||||
|
obtain_signature(¶ms, &bandwidth_credential_attributes, validators)
|
||||||
|
.await
|
||||||
|
.expect("could not obtain bandwidth credential");
|
||||||
|
|
||||||
|
prepare_for_spending(
|
||||||
|
raw_identity,
|
||||||
|
&bandwidth_credential,
|
||||||
|
&bandwidth_credential_attributes,
|
||||||
|
&verification_key,
|
||||||
|
)
|
||||||
|
.expect("could not prepare out bandwidth credential for spending")
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
@@ -91,45 +128,88 @@ 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(validator_server: &str, chosen_gateway_id: Option<&str>) -> gateway::Node {
|
async fn gateway_details(
|
||||||
let validator_client_config = validator_client::Config::new(validator_server.to_string());
|
validator_servers: Vec<Url>,
|
||||||
let validator_client = validator_client::Client::new(validator_client_config);
|
chosen_gateway_id: Option<&str>,
|
||||||
let topology = validator_client.get_active_topology().await.unwrap();
|
) -> gateway::Node {
|
||||||
let nym_topology: NymTopology = topology.into();
|
let validator_api = validator_servers
|
||||||
let version_filtered_topology = nym_topology.filter_system_version(env!("CARGO_PKG_VERSION"));
|
.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_cached_gateways().await.unwrap();
|
||||||
|
let valid_gateways = gateways
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|gateway| gateway.try_into().ok())
|
||||||
|
.collect::<Vec<gateway::Node>>();
|
||||||
|
|
||||||
|
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||||
|
|
||||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||||
// be working correctly)
|
// be working correctly)
|
||||||
|
|
||||||
if let Some(gateway_id) = chosen_gateway_id {
|
if let Some(gateway_id) = chosen_gateway_id {
|
||||||
version_filtered_topology
|
filtered_gateways
|
||||||
.gateways()
|
|
||||||
.iter()
|
.iter()
|
||||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||||
.clone()
|
.clone()
|
||||||
} else {
|
} else {
|
||||||
version_filtered_topology
|
filtered_gateways
|
||||||
.gateways()
|
|
||||||
.choose(&mut rand::thread_rng())
|
.choose(&mut rand::thread_rng())
|
||||||
.expect("there are no gateways on the network!")
|
.expect("there are no gateways on the network!")
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn show_address(config: &Config) {
|
||||||
|
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||||
|
let identity_keypair: identity::KeyPair =
|
||||||
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
|
pathfinder.private_identity_key().to_owned(),
|
||||||
|
pathfinder.public_identity_key().to_owned(),
|
||||||
|
))
|
||||||
|
.expect("Failed to read stored identity key files");
|
||||||
|
identity_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||||
|
let sphinx_keypair: encryption::KeyPair =
|
||||||
|
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||||
|
pathfinder.private_encryption_key().to_owned(),
|
||||||
|
pathfinder.public_encryption_key().to_owned(),
|
||||||
|
))
|
||||||
|
.expect("Failed to read stored sphinx key files");
|
||||||
|
sphinx_keypair
|
||||||
|
}
|
||||||
|
|
||||||
|
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||||
|
let identity_keypair = load_identity_keys(&pathfinder);
|
||||||
|
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||||
|
|
||||||
|
let client_recipient = Recipient::new(
|
||||||
|
*identity_keypair.public_key(),
|
||||||
|
*sphinx_keypair.public_key(),
|
||||||
|
// TODO: below only works under assumption that gateway address == gateway id
|
||||||
|
// (which currently is true)
|
||||||
|
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("\nThe address of this client is: {}", client_recipient);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn execute(matches: &ArgMatches) {
|
pub fn execute(matches: &ArgMatches) {
|
||||||
println!("Initialising client...");
|
println!("Initialising client...");
|
||||||
|
|
||||||
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 {
|
||||||
@@ -157,7 +237,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_endpoint(),
|
config.get_base().get_validator_api_endpoints(),
|
||||||
chosen_gateway_id,
|
chosen_gateway_id,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@@ -166,11 +246,11 @@ 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?
|
||||||
let mut rt = tokio::runtime::Runtime::new().unwrap();
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
let (shared_keys, gateway_listener) = rt.block_on(registration_fut);
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
@@ -190,5 +270,7 @@ pub fn execute(matches: &ArgMatches) {
|
|||||||
.expect("Failed to save the config file");
|
.expect("Failed to save the config file");
|
||||||
println!("Saved configuration file to {:?}", config_save_location);
|
println!("Saved configuration file to {:?}", config_save_location);
|
||||||
println!("Using gateway: {}", config.get_base().get_gateway_id(),);
|
println!("Using gateway: {}", config.get_base().get_gateway_id(),);
|
||||||
println!("Client configuration completed.\n\n\n")
|
println!("Client configuration completed.\n\n\n");
|
||||||
|
|
||||||
|
show_address(&config);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,36 @@
|
|||||||
// 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<Url> {
|
||||||
|
raw.split(',')
|
||||||
|
.map(|raw_validator| {
|
||||||
|
raw_validator
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.expect("one of the provided validator api urls is invalid")
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches) -> Config {
|
||||||
if let Some(validator) = matches.value_of("validator") {
|
if let Some(raw_validators) = matches.value_of("validators") {
|
||||||
config.get_base_mut().set_custom_validator(validator);
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_validator_apis(parse_validators(raw_validators));
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -40,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")
|
||||||
@@ -40,33 +29,34 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
.help("Address of the socks5 provider to send messages to.")
|
.help("Address of the socks5 provider to send messages to.")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name("validator")
|
.arg(Arg::with_name("validators")
|
||||||
.long("validator")
|
.long("validators")
|
||||||
.help("Address of the validator server the client is getting topology from")
|
.help("Comma separated list of rest endpoints of the validators")
|
||||||
.takes_value(true),
|
.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
|
||||||
@@ -91,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_ENDPOINT;
|
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,199 +36,136 @@ fn print_successful_upgrade<D1: Display, D2: Display>(from: D1, to: D2) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pre_090_upgrade(from: &str, mut config: Config) -> Config {
|
fn outdated_upgrade(config_version: &Version, package_version: &Version) -> ! {
|
||||||
// this is not extracted to separate function as you only have to manually pass version
|
eprintln!(
|
||||||
// if upgrading from pre090 version
|
"Cannot perform upgrade from {} to {}. Your version is too old to perform the upgrade.!",
|
||||||
let from = match from.strip_prefix("v") {
|
config_version, package_version
|
||||||
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_endpoint() != 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_ENDPOINT
|
|
||||||
);
|
);
|
||||||
|
process::exit(1)
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validator(DEFAULT_VALIDATOR_REST_ENDPOINT);
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn patch_09x_upgrade(mut config: Config, _matches: &ArgMatches) -> Config {
|
fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> ! {
|
||||||
// this call must succeed as it was already called before
|
|
||||||
let from_version = Version::parse(config.get_base().get_version()).unwrap();
|
|
||||||
let to_version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
|
||||||
|
|
||||||
print_start_upgrade(&from_version, &to_version);
|
|
||||||
|
|
||||||
// 0.9.1 upgrade:
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
|
||||||
|
|
||||||
config.save_to_file(None).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to overwrite config file! - {:?}", err);
|
|
||||||
print_failed_upgrade(&from_version, &to_version);
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
print_successful_upgrade(from_version, to_version);
|
|
||||||
|
|
||||||
config
|
|
||||||
}
|
|
||||||
|
|
||||||
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-socks5-client we want to upgrade")
|
|
||||||
.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(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, current_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)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_upgrade(mut config: Config, matches: &ArgMatches) {
|
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
||||||
let current = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
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 {
|
||||||
|
let version = Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
||||||
|
eprintln!("failed to parse client version! - {:?}", err);
|
||||||
|
process::exit(1)
|
||||||
|
});
|
||||||
|
|
||||||
|
if version.is_prerelease() || !version.build.is_empty() {
|
||||||
|
eprintln!(
|
||||||
|
"Trying to upgrade from a non-released version {}. This is not supported!",
|
||||||
|
version
|
||||||
|
);
|
||||||
|
process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
version
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_package_version() -> Version {
|
||||||
|
let version = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
||||||
|
|
||||||
|
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
||||||
|
// however, we are not using them ourselves at the moment and hence it should be fine.
|
||||||
|
// if we change our mind, we could easily tweak this code
|
||||||
|
if version.is_prerelease() || !version.build.is_empty() {
|
||||||
|
eprintln!(
|
||||||
|
"Trying to upgrade to a non-released version {}. This is not supported!",
|
||||||
|
version
|
||||||
|
);
|
||||||
|
process::exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
version
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minor_0_12_upgrade(
|
||||||
|
mut config: Config,
|
||||||
|
_matches: &ArgMatches,
|
||||||
|
config_version: &Version,
|
||||||
|
package_version: &Version,
|
||||||
|
) -> Config {
|
||||||
|
let to_version = if package_version.major == 0 && package_version.minor == 12 {
|
||||||
|
package_version.clone()
|
||||||
|
} else {
|
||||||
|
Version::new(0, 12, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
print_start_upgrade(&config_version, &to_version);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Setting validator API endpoints to {:?}",
|
||||||
|
default_api_endpoints()
|
||||||
|
);
|
||||||
|
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_validator_apis(default_api_endpoints());
|
||||||
|
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_version(to_version.to_string().as_ref());
|
||||||
|
|
||||||
|
config.save_to_file(None).unwrap_or_else(|err| {
|
||||||
|
eprintln!("failed to overwrite config file! - {:?}", err);
|
||||||
|
print_failed_upgrade(&config_version, &to_version);
|
||||||
|
process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
print_successful_upgrade(config_version, to_version);
|
||||||
|
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_upgrade(mut config: Config, matches: &ArgMatches, package_version: Version) {
|
||||||
loop {
|
loop {
|
||||||
let config_version =
|
let config_version = parse_config_version(&config);
|
||||||
Version::parse(config.get_base().get_version()).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to parse client version! - {:?}", err);
|
|
||||||
process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
if config_version == current {
|
if config_version == package_version {
|
||||||
println!("You're using the most recent version!");
|
println!("You're using the most recent version!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
config = match config_version.major {
|
config = match config_version.major {
|
||||||
0 => match config_version.minor {
|
0 => match config_version.minor {
|
||||||
9 => patch_09x_upgrade(config, &matches),
|
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
||||||
_ => unsupported_upgrade(current, config_version),
|
11 => minor_0_12_upgrade(config, matches, &config_version, &package_version),
|
||||||
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
},
|
},
|
||||||
_ => unsupported_upgrade(current, config_version),
|
_ => unsupported_upgrade(&config_version, &package_version),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(matches: &ArgMatches) {
|
pub fn execute(matches: &ArgMatches) {
|
||||||
let current = Version::parse(env!("CARGO_PKG_VERSION")).unwrap();
|
let package_version = parse_package_version();
|
||||||
|
|
||||||
// technically this is not a correct way of checking it as a released version might contain valid build identifiers
|
|
||||||
// however, we are not using them ourselves at the moment and hence it should be fine.
|
|
||||||
// if we change our mind, we could easily tweak this code
|
|
||||||
if current.is_prerelease() || !current.build.is_empty() {
|
|
||||||
eprintln!(
|
|
||||||
"Trying to upgrade to a non-released version {}. This is not supported!",
|
|
||||||
current
|
|
||||||
);
|
|
||||||
process::exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let config_version =
|
|
||||||
Version::parse(existing_config.get_base().get_version()).unwrap_or_else(|err| {
|
|
||||||
eprintln!("failed to parse client version! - {:?}", err);
|
|
||||||
process::exit(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
if config_version.is_prerelease() || !config_version.build.is_empty() {
|
|
||||||
eprintln!(
|
|
||||||
"Trying to upgrade from non-released version {}. This is not supported!",
|
|
||||||
config_version
|
|
||||||
);
|
|
||||||
process::exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
if config_version == current {
|
do_upgrade(existing_config, matches, package_version)
|
||||||
println!("You're using the most recent version!");
|
|
||||||
} else {
|
|
||||||
do_upgrade(existing_config, matches)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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};
|
||||||
|
|
||||||
|
|||||||
@@ -51,9 +51,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn constructor_works() {
|
fn constructor_works() {
|
||||||
let mut auth_methods: Vec<u8> = Vec::new();
|
let auth_methods = vec![
|
||||||
auth_methods.push(AuthenticationMethods::NoAuth as u8);
|
AuthenticationMethods::NoAuth as u8,
|
||||||
auth_methods.push(AuthenticationMethods::UserPass as u8);
|
AuthenticationMethods::UserPass as u8,
|
||||||
|
];
|
||||||
|
|
||||||
let admin = User {
|
let admin = User {
|
||||||
username: "foo".to_string(),
|
username: "foo".to_string(),
|
||||||
@@ -98,8 +99,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn allowed_user_passes_authentication_check() {
|
fn allowed_user_passes_authentication_check() {
|
||||||
let mut auth_methods: Vec<u8> = Vec::new();
|
let auth_methods = vec![AuthenticationMethods::UserPass as u8];
|
||||||
auth_methods.push(AuthenticationMethods::UserPass as u8);
|
|
||||||
|
|
||||||
let admin = User {
|
let admin = User {
|
||||||
username: "foo".to_string(),
|
username: "foo".to_string(),
|
||||||
@@ -115,8 +115,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn disallowed_user_fails_authentication_check() {
|
fn disallowed_user_fails_authentication_check() {
|
||||||
let mut auth_methods: Vec<u8> = Vec::new();
|
let auth_methods = vec![AuthenticationMethods::UserPass as u8];
|
||||||
auth_methods.push(AuthenticationMethods::UserPass as u8);
|
|
||||||
|
|
||||||
let bad_user = User {
|
let bad_user = User {
|
||||||
username: "ashy".to_string(),
|
username: "ashy".to_string(),
|
||||||
|
|||||||
@@ -17,9 +17,10 @@ use proxy_helpers::connection_controller::{
|
|||||||
use proxy_helpers::proxy_runner::ProxyRunner;
|
use proxy_helpers::proxy_runner::ProxyRunner;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
use socks5_requests::{ConnectionId, RemoteAddress, Request};
|
use socks5_requests::{ConnectionId, RemoteAddress, Request};
|
||||||
use std::net::{Shutdown, SocketAddr};
|
use std::io;
|
||||||
|
use std::net::SocketAddr;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use tokio::prelude::*;
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
|
||||||
use tokio::{self, net::TcpStream};
|
use tokio::{self, net::TcpStream};
|
||||||
|
|
||||||
#[pin_project(project = StateProject)]
|
#[pin_project(project = StateProject)]
|
||||||
@@ -61,12 +62,12 @@ impl StreamState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shutdown(&self, how: Shutdown) -> io::Result<()> {
|
async fn shutdown(&mut self) -> io::Result<()> {
|
||||||
// shutdown should only be called if proxy is not being run. If it is, there's some bug
|
// shutdown should only be called if proxy is not being run. If it is, there's some bug
|
||||||
// somewhere
|
// somewhere
|
||||||
match self {
|
match self {
|
||||||
StreamState::RunningProxy => panic!("Tried to shutdown stream while proxy is running"),
|
StreamState::RunningProxy => panic!("Tried to shutdown stream while proxy is running"),
|
||||||
StreamState::Available(ref stream) => TcpStream::shutdown(stream, how),
|
StreamState::Available(ref mut stream) => TcpStream::shutdown(stream).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,8 +77,8 @@ impl AsyncRead for StreamState {
|
|||||||
fn poll_read(
|
fn poll_read(
|
||||||
self: Pin<&mut Self>,
|
self: Pin<&mut Self>,
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
buf: &mut [u8],
|
buf: &mut ReadBuf<'_>,
|
||||||
) -> Poll<io::Result<usize>> {
|
) -> Poll<io::Result<()>> {
|
||||||
match self.project() {
|
match self.project() {
|
||||||
StateProject::RunningProxy => Poll::Ready(Err(io::Error::new(
|
StateProject::RunningProxy => Poll::Ready(Err(io::Error::new(
|
||||||
io::ErrorKind::NotFound,
|
io::ErrorKind::NotFound,
|
||||||
@@ -138,15 +139,18 @@ pub(crate) struct SocksClient {
|
|||||||
connection_id: ConnectionId,
|
connection_id: ConnectionId,
|
||||||
service_provider: Recipient,
|
service_provider: Recipient,
|
||||||
self_address: Recipient,
|
self_address: Recipient,
|
||||||
|
started_proxy: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for SocksClient {
|
impl Drop for SocksClient {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// TODO: decrease to debug/trace
|
|
||||||
debug!("Connection {} is getting closed", self.connection_id);
|
debug!("Connection {} is getting closed", self.connection_id);
|
||||||
self.controller_sender
|
// if we never managed to start a proxy, the entry will not exist in the controller
|
||||||
.unbounded_send(ControllerCommand::Remove(self.connection_id))
|
if self.started_proxy {
|
||||||
.unwrap();
|
self.controller_sender
|
||||||
|
.unbounded_send(ControllerCommand::Remove(self.connection_id))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +175,7 @@ impl SocksClient {
|
|||||||
input_sender,
|
input_sender,
|
||||||
service_provider,
|
service_provider,
|
||||||
self_address,
|
self_address,
|
||||||
|
started_proxy: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,9 +191,9 @@ impl SocksClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Shutdown the TcpStream to the client and end the session
|
/// Shutdown the TcpStream to the client and end the session
|
||||||
pub fn shutdown(&mut self) -> Result<(), SocksProxyError> {
|
pub async fn shutdown(&mut self) -> Result<(), SocksProxyError> {
|
||||||
info!("client is shutting down its TCP stream");
|
info!("client is shutting down its TCP stream");
|
||||||
self.stream.shutdown(Shutdown::Both)?;
|
self.stream.shutdown().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,28 +211,21 @@ impl SocksClient {
|
|||||||
// Handle SOCKS4 requests
|
// Handle SOCKS4 requests
|
||||||
if header[0] != SOCKS_VERSION {
|
if header[0] != SOCKS_VERSION {
|
||||||
warn!("Init: Unsupported version: SOCKS{}", self.socks_version);
|
warn!("Init: Unsupported version: SOCKS{}", self.socks_version);
|
||||||
self.shutdown()?;
|
self.shutdown().await
|
||||||
}
|
}
|
||||||
// Valid SOCKS5
|
// Valid SOCKS5
|
||||||
else {
|
else {
|
||||||
// Authenticate w/ client
|
// Authenticate w/ client
|
||||||
self.authenticate().await?;
|
self.authenticate().await?;
|
||||||
// Handle requests
|
// Handle requests
|
||||||
self.handle_request().await?;
|
self.handle_request().await
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_connect_to_mixnet(&mut self, remote_address: RemoteAddress) {
|
async fn send_connect_to_mixnet(&mut self, remote_address: RemoteAddress) {
|
||||||
let req = Request::new_connect(
|
let req = Request::new_connect(self.connection_id, remote_address, self.self_address);
|
||||||
self.connection_id,
|
|
||||||
remote_address.clone(),
|
|
||||||
self.self_address.clone(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let input_message =
|
let input_message = InputMessage::new_fresh(self.service_provider, req.into_bytes(), false);
|
||||||
InputMessage::new_fresh(self.service_provider.clone(), req.into_bytes(), false);
|
|
||||||
self.input_sender.unbounded_send(input_message).unwrap();
|
self.input_sender.unbounded_send(input_message).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,16 +270,17 @@ impl SocksClient {
|
|||||||
// setup for receiving from the mixnet
|
// setup for receiving from the mixnet
|
||||||
let (mix_sender, mix_receiver) = mpsc::unbounded();
|
let (mix_sender, mix_receiver) = mpsc::unbounded();
|
||||||
|
|
||||||
self.controller_sender
|
|
||||||
.unbounded_send(ControllerCommand::Insert(self.connection_id, mix_sender))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
match request.command {
|
match request.command {
|
||||||
// Use the Proxy to connect to the specified addr/port
|
// Use the Proxy to connect to the specified addr/port
|
||||||
SocksCommand::Connect => {
|
SocksCommand::Connect => {
|
||||||
trace!("Connecting to: {:?}", remote_address.clone());
|
trace!("Connecting to: {:?}", remote_address.clone());
|
||||||
self.acknowledge_socks5().await;
|
self.acknowledge_socks5().await;
|
||||||
|
|
||||||
|
self.started_proxy = true;
|
||||||
|
self.controller_sender
|
||||||
|
.unbounded_send(ControllerCommand::Insert(self.connection_id, mix_sender))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Starting proxy for {} (id: {})",
|
"Starting proxy for {} (id: {})",
|
||||||
remote_address.clone(),
|
remote_address.clone(),
|
||||||
@@ -326,7 +325,7 @@ impl SocksClient {
|
|||||||
/// username and password from the stream, then check with the Authenticator
|
/// username and password from the stream, then check with the Authenticator
|
||||||
/// to see if the resulting user is allowed.
|
/// to see if the resulting user is allowed.
|
||||||
///
|
///
|
||||||
/// A lot of this could probably be put into the the `SocksRequest::from_stream()`
|
/// A lot of this could probably be put into the `SocksRequest::from_stream()`
|
||||||
/// constructor, and/or cleaned up with tokio::codec. It's mostly just
|
/// constructor, and/or cleaned up with tokio::codec. It's mostly just
|
||||||
/// read-a-byte-or-two. The bytes being extracted look like this:
|
/// read-a-byte-or-two. The bytes being extracted look like this:
|
||||||
///
|
///
|
||||||
@@ -392,7 +391,7 @@ impl SocksClient {
|
|||||||
self.stream.write_all(&response).await?;
|
self.stream.write_all(&response).await?;
|
||||||
|
|
||||||
// Shutdown
|
// Shutdown
|
||||||
self.shutdown()?;
|
self.shutdown().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -406,7 +405,7 @@ impl SocksClient {
|
|||||||
warn!("Client has no suitable authentication methods!");
|
warn!("Client has no suitable authentication methods!");
|
||||||
response[1] = AuthenticationMethods::NoMethods as u8;
|
response[1] = AuthenticationMethods::NoMethods as u8;
|
||||||
self.stream.write_all(&response).await?;
|
self.stream.write_all(&response).await?;
|
||||||
self.shutdown()?;
|
self.shutdown().await?;
|
||||||
Err(ResponseCode::Failure.into())
|
Err(ResponseCode::Failure.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ impl MixnetResponseListener {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
MixnetResponseListener {
|
MixnetResponseListener {
|
||||||
controller_sender,
|
|
||||||
buffer_requester,
|
buffer_requester,
|
||||||
mix_response_receiver,
|
mix_response_receiver,
|
||||||
|
controller_sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ use super::types::{AddrType, ResponseCode, SocksProxyError};
|
|||||||
use super::{utils as socks_utils, SOCKS_VERSION};
|
use super::{utils as socks_utils, SOCKS_VERSION};
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use tokio::prelude::*;
|
use tokio::io::{AsyncRead, AsyncReadExt};
|
||||||
|
|
||||||
/// A Socks5 request hitting the proxy.
|
/// A Socks5 request hitting the proxy.
|
||||||
pub(crate) struct SocksRequest {
|
pub(crate) struct SocksRequest {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
pub command: SocksCommand,
|
pub command: SocksCommand,
|
||||||
pub addr_type: AddrType,
|
pub addr_type: AddrType,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ impl SphinxSocksServer {
|
|||||||
input_sender: InputMessageSender,
|
input_sender: InputMessageSender,
|
||||||
buffer_requester: ReceivedBufferRequestSender,
|
buffer_requester: ReceivedBufferRequestSender,
|
||||||
) -> Result<(), SocksProxyError> {
|
) -> Result<(), SocksProxyError> {
|
||||||
let mut listener = TcpListener::bind(self.listening_address).await.unwrap();
|
let listener = TcpListener::bind(self.listening_address).await.unwrap();
|
||||||
info!("Serving Connections...");
|
info!("Serving Connections...");
|
||||||
|
|
||||||
// controller for managing all active connections
|
// controller for managing all active connections
|
||||||
@@ -100,7 +100,7 @@ impl SphinxSocksServer {
|
|||||||
if client.error(response).await.is_err() {
|
if client.error(response).await.is_err() {
|
||||||
warn!("Failed to send error code");
|
warn!("Failed to send error code");
|
||||||
};
|
};
|
||||||
if client.shutdown().is_err() {
|
if client.shutdown().await.is_err() {
|
||||||
warn!("Failed to shutdown TcpStream");
|
warn!("Failed to shutdown TcpStream");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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]
|
||||||
Generated
+14875
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||||
|
},
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user