Compare commits

..

102 Commits

Author SHA1 Message Date
mfahampshire 499b1c7400 license 2025-01-08 16:20:54 +01:00
mfahampshire 5b536eeaf6 proper disconnect signal management 2025-01-08 16:20:46 +01:00
mfahampshire 45617cd218 proper disconnect signals 2025-01-08 16:20:29 +01:00
mfahampshire 3f90de1790 update lock 2025-01-08 16:20:14 +01:00
mfahampshire e638f87729 first pass done 2025-01-08 16:20:03 +01:00
mfahampshire d86286ef54 trying to make run_with_shutdown killable 2025-01-07 14:42:51 +01:00
mfahampshire b73d66e073 rearrange code, comment for rewrite of run() 2025-01-06 19:42:25 +01:00
mfahampshire 378ed88714 comments 2025-01-06 19:41:41 +01:00
mfahampshire 3e1ea8e855 remove comments 2025-01-06 19:41:01 +01:00
mfahampshire 50191cf80b re-add commented out code fr sharing 2025-01-06 13:06:37 +01:00
mfahampshire 54d7b37f10 debugging failing lock quiring 2025-01-03 18:28:28 +01:00
mfahampshire 8dda5fba5f comment 2025-01-03 13:35:40 +01:00
mfahampshire 93f063bb01 added test start fn to client_pool: uses specified gw for all clients 2025-01-03 13:35:40 +01:00
mfahampshire 376eca688a cancel token fixes ongoing 2025-01-03 13:35:40 +01:00
mfahampshire 54cec265e6 add dir creation + time dir to results 2025-01-03 13:35:40 +01:00
mfahampshire 20697fd5fc remove runs 2025-01-03 13:35:40 +01:00
mfahampshire a87753f1ee remove scratch 2025-01-03 13:35:40 +01:00
mfahampshire 5e9d25364f cancel token 2025-01-03 13:35:40 +01:00
mfahampshire 49e1134722 cargo + todo list 2025-01-03 13:35:40 +01:00
mfahampshire ffcc4e8fa5 first pass tester 2025-01-03 13:35:40 +01:00
mfahampshire 0337c04844 fixed test: needed proxiedMessage format 2025-01-03 13:35:40 +01:00
mfahampshire ec77f1e7b4 minor log tweak 2025-01-03 13:35:40 +01:00
mfahampshire 1cd42bde0b working on script fr testing all 2025-01-03 13:35:40 +01:00
mfahampshire 6606fc8cc4 work on test 2025-01-03 13:35:40 +01:00
mfahampshire eef3405777 logging tweak 2025-01-03 13:35:40 +01:00
mfahampshire 2d7957a83b remove active conn 2025-01-03 13:35:40 +01:00
mfahampshire 60e8f8254e fix test 2025-01-03 13:35:39 +01:00
mfahampshire 7066c115e5 deps 2025-01-03 13:35:39 +01:00
mfahampshire fb63555ab0 add metric getter + debug print 2025-01-03 13:35:39 +01:00
mfahampshire 814aeb5e7c clap standalone echo_server 2025-01-03 13:35:39 +01:00
mfahampshire 45bef0da68 temp commit 2025-01-03 13:35:39 +01:00
mfahampshire 060f785ff0 temp commit 2025-01-03 13:35:39 +01:00
mfahampshire a9ef20914e temp commit 2025-01-03 13:35:39 +01:00
mfahampshire 9761644d08 tweaks to lib 2025-01-03 13:35:39 +01:00
mfahampshire b6b8ec41eb first pass all fns 2025-01-03 13:35:39 +01:00
mfahampshire d7d2aaff68 comment 2025-01-03 13:35:39 +01:00
mfahampshire e2114dd9e5 add disconnect 2025-01-03 13:35:39 +01:00
mfahampshire d247c88a74 cargo fix 2025-01-03 13:35:39 +01:00
mfahampshire 2fc359f58f first pass echo server lib 2025-01-03 13:35:39 +01:00
mfahampshire 0f35f5c909 add configurable gw to server 2025-01-03 13:35:39 +01:00
mfahampshire 3fdaa7bac3 future is now 2025-01-03 13:35:39 +01:00
mfahampshire 16c3e5ff9a updated comment in example 2025-01-03 13:35:39 +01:00
mfahampshire 4f5d86a50c tweaked text grammar 2025-01-03 13:35:39 +01:00
mfahampshire 9d8f14ddec fix test 2025-01-03 13:35:39 +01:00
mfahampshire 72482180b9 version bump 2025-01-03 13:35:39 +01:00
mfahampshire d99cb96994 version bump 2025-01-03 13:35:39 +01:00
mfahampshire 99d2a807dd fix clippy again 2025-01-03 13:35:39 +01:00
mfahampshire 9400140f69 fix clippy again 2025-01-03 13:35:39 +01:00
mfahampshire f78bb83eab fix clippy 2025-01-03 13:35:39 +01:00
mfahampshire 349e95aa07 remove clone 2025-01-03 13:35:39 +01:00
mfahampshire 5cc5484297 clone impl 2025-01-03 13:35:39 +01:00
mfahampshire 8864921260 update command help 2025-01-03 13:35:39 +01:00
mfahampshire 7608ca768f comment on ffi 2025-01-03 13:35:39 +01:00
mfahampshire 7fa1cdba93 remove comments for future ffi push + lower default pool size from 4 to 2 2025-01-03 13:35:39 +01:00
mfahampshire d59f05f9d4 client pool docs 2025-01-03 13:35:39 +01:00
mfahampshire f819b33628 update example files tcpproxy 2025-01-03 13:35:39 +01:00
mfahampshire 7d2b1ca9a8 added disconnect thread 2025-01-03 13:35:39 +01:00
mfahampshire 08f5749887 add clone 2025-01-03 13:35:39 +01:00
mfahampshire 3573d1e6a6 comments 2025-01-03 13:35:39 +01:00
mfahampshire 1015251bd9 comments 2025-01-03 13:35:39 +01:00
mfahampshire 0492d84ea8 add cancel token disconnect fn 2025-01-03 13:35:39 +01:00
mfahampshire 70c1e4fd85 update mod file 2025-01-03 13:35:39 +01:00
mfahampshire 5047ed2722 added disconnect to client pool 2025-01-03 13:35:39 +01:00
mfahampshire 8630cefddb client pool example done 2025-01-03 13:35:39 +01:00
mfahampshire 68a1d43cbf comments 2025-01-03 13:35:39 +01:00
mfahampshire fedaf00375 clippy 2025-01-03 13:35:39 +01:00
mfahampshire 7660f007c8 client pool example 2025-01-03 13:35:39 +01:00
mfahampshire 747675f52f client_pool.rs mod 2025-01-03 13:35:39 +01:00
mfahampshire c7b3bd1608 minor comments 2025-01-03 13:35:39 +01:00
mfahampshire 6fc231821b some inline comments 2025-01-03 13:35:39 +01:00
mfahampshire fa6efbaa2a comments to examples 2025-01-03 13:35:39 +01:00
mfahampshire e9ade22b10 slightly dropped default decay time 2025-01-03 13:35:39 +01:00
mfahampshire 731f69acc3 add duplicate packets received to troubleshooting 2025-01-03 13:35:39 +01:00
mfahampshire a0e55f49d4 temp commit 2025-01-03 13:29:55 +01:00
mfahampshire 7563cccf49 bump default decay time (again) 2025-01-03 13:29:55 +01:00
mfahampshire 95274e3883 bump default decay time 2025-01-03 13:29:55 +01:00
mfahampshire c8ca174b87 updated code commnet 2025-01-03 13:29:55 +01:00
mfahampshire 4eccc59f6f bump default decay time 2025-01-03 13:29:55 +01:00
mfahampshire 56becc3a34 minor tweaks 2025-01-03 13:29:55 +01:00
mfahampshire 13a6f0b5ef logging change 2025-01-03 13:29:55 +01:00
mfahampshire 4f1bac204c cancel token 2025-01-03 13:29:55 +01:00
mfahampshire f87f57bddd first pass spin out client_pool 2025-01-03 13:29:55 +01:00
mfahampshire c49f7f91ed first version working 2025-01-03 13:29:55 +01:00
mfahampshire 8c8e085796 added notes for next features 2025-01-03 13:29:55 +01:00
mfahampshire 4bb05f3698 err handling conpool start 2025-01-03 13:29:55 +01:00
mfahampshire 8fcea5f350 removed a bunch of commenting from example 2025-01-03 13:29:55 +01:00
mfahampshire 42739597ed removed a bunch of commenting from example 2025-01-03 13:29:55 +01:00
mfahampshire 699aa6116a comments 2025-01-03 13:29:55 +01:00
mfahampshire 4519bd6571 remove comments and reduce logging verbosity 2025-01-03 13:29:55 +01:00
mfahampshire 5083b420ec remove double accounting for moment 2025-01-03 13:29:55 +01:00
mfahampshire 6f4421dc4a trying to get disconnect to remove from pool 2025-01-03 13:29:55 +01:00
mfahampshire 415c30fcc9 first pass disconnect 2025-01-03 13:29:55 +01:00
mfahampshire 8e8eceb894 fix flipped lowerthan waiting for pool 2025-01-03 13:29:55 +01:00
mfahampshire 546482916d first pass connpool 2025-01-03 13:29:55 +01:00
mfahampshire 530d744d6d make default decay const 2025-01-03 13:29:55 +01:00
mfahampshire 2e8e9a4c0a tweak existing conn tracker logic 2025-01-03 13:29:55 +01:00
mfahampshire 109de83128 tweak 2025-01-03 13:29:55 +01:00
mfahampshire 0c36e64526 tweak 2025-01-03 13:29:55 +01:00
mfahampshire d423cde71c changed logging 2025-01-03 13:29:55 +01:00
mfahampshire 1130d0fe3e name change + specific inc and dec logging 2025-01-03 13:29:55 +01:00
mfahampshire f53d2aa4cd small tweak to tcp tracker 2025-01-03 13:29:55 +01:00
mfahampshire c406814886 tcp conn tracker 2025-01-03 13:29:55 +01:00
1317 changed files with 42520 additions and 113533 deletions
-1
View File
@@ -1,2 +1 @@
nym-validator-rewarder/.sqlx/** diff=nodiff nym-validator-rewarder/.sqlx/** diff=nodiff
nym-node-status-api/nym-node-status-api/.sqlx/** diff=nodiff
+266 -150
View File
@@ -9,7 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.1", "@actions/core": "^1.10.1",
"@actions/github": "^6.0.0", "@actions/github": "^5.1.1",
"@octokit/auth-action": "^4.0.1", "@octokit/auth-action": "^4.0.1",
"@octokit/rest": "^20.0.2", "@octokit/rest": "^20.0.2",
"hasha": "^5.2.0", "hasha": "^5.2.0",
@@ -29,34 +29,22 @@
} }
}, },
"node_modules/@actions/github": { "node_modules/@actions/github": {
"version": "6.0.0", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.0.tgz", "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz",
"integrity": "sha512-alScpSVnYmjNEXboZjarjukQEzgCRmjMv6Xj47fsdnqGS73bjJNDpiiXmp8jr0UZLdUB6d9jW63IcmddUP+l0g==", "integrity": "sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==",
"license": "MIT",
"dependencies": { "dependencies": {
"@actions/http-client": "^2.2.0", "@actions/http-client": "^2.0.1",
"@octokit/core": "^5.0.1", "@octokit/core": "^3.6.0",
"@octokit/plugin-paginate-rest": "^9.0.0", "@octokit/plugin-paginate-rest": "^2.17.0",
"@octokit/plugin-rest-endpoint-methods": "^10.0.0" "@octokit/plugin-rest-endpoint-methods": "^5.13.0"
} }
}, },
"node_modules/@actions/http-client": { "node_modules/@actions/http-client": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.25.4"
}
},
"node_modules/@fastify/busboy": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "integrity": "sha512-qhrkRMB40bbbLo7gF+0vu+X+UawOvQQqNAA/5Unx774RS8poaOhThDOG6BGmxvAnxhQnDp2BG/ZUm65xZILTpw==",
"license": "MIT", "dependencies": {
"engines": { "tunnel": "^0.0.6"
"node": ">=14"
} }
}, },
"node_modules/@octokit/auth-action": { "node_modules/@octokit/auth-action": {
@@ -71,6 +59,14 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/@octokit/auth-action/node_modules/@octokit/auth-token": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/auth-action/node_modules/@octokit/openapi-types": { "node_modules/@octokit/auth-action/node_modules/@octokit/openapi-types": {
"version": "20.0.0", "version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
@@ -85,152 +81,115 @@
} }
}, },
"node_modules/@octokit/auth-token": { "node_modules/@octokit/auth-token": {
"version": "4.0.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"license": "MIT", "dependencies": {
"engines": { "@octokit/types": "^6.0.3"
"node": ">= 18"
} }
}, },
"node_modules/@octokit/core": { "node_modules/@octokit/core": {
"version": "5.2.0", "version": "3.6.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
"integrity": "sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==", "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/auth-token": "^4.0.0", "@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^7.1.0", "@octokit/graphql": "^4.5.8",
"@octokit/request": "^8.3.1", "@octokit/request": "^5.6.3",
"@octokit/request-error": "^5.1.0", "@octokit/request-error": "^2.0.5",
"@octokit/types": "^13.0.0", "@octokit/types": "^6.0.3",
"before-after-hook": "^2.2.0", "before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0" "universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
} }
}, },
"node_modules/@octokit/endpoint": { "node_modules/@octokit/endpoint": {
"version": "9.0.6", "version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^13.1.0", "@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0" "universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
} }
}, },
"node_modules/@octokit/graphql": { "node_modules/@octokit/graphql": {
"version": "7.1.0", "version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==", "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/request": "^8.3.0", "@octokit/request": "^5.6.0",
"@octokit/types": "^13.0.0", "@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0" "universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
} }
}, },
"node_modules/@octokit/openapi-types": { "node_modules/@octokit/openapi-types": {
"version": "23.0.1", "version": "12.11.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz",
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==", "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
"license": "MIT"
}, },
"node_modules/@octokit/plugin-paginate-rest": { "node_modules/@octokit/plugin-paginate-rest": {
"version": "9.2.2", "version": "2.21.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
"integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==", "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^12.6.0" "@octokit/types": "^6.40.0"
},
"engines": {
"node": ">= 18"
}, },
"peerDependencies": { "peerDependencies": {
"@octokit/core": "5" "@octokit/core": ">=2"
}
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^20.0.0"
} }
}, },
"node_modules/@octokit/plugin-rest-endpoint-methods": { "node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "10.4.1", "version": "5.16.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
"integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==", "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^12.6.0" "@octokit/types": "^6.39.0",
}, "deprecation": "^2.3.1"
"engines": {
"node": ">= 18"
}, },
"peerDependencies": { "peerDependencies": {
"@octokit/core": "5" "@octokit/core": ">=3"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
"license": "MIT"
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^20.0.0"
} }
}, },
"node_modules/@octokit/request": { "node_modules/@octokit/request": {
"version": "8.4.1", "version": "5.6.3",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
"integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==", "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/endpoint": "^9.0.6", "@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^5.1.1", "@octokit/request-error": "^2.1.0",
"@octokit/types": "^13.1.0", "@octokit/types": "^6.16.1",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0" "universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
} }
}, },
"node_modules/@octokit/request-error": { "node_modules/@octokit/request-error": {
"version": "5.1.1", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz", "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==", "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/types": "^13.1.0", "@octokit/types": "^6.0.3",
"deprecation": "^2.0.0", "deprecation": "^2.0.0",
"once": "^1.4.0" "once": "^1.4.0"
}
},
"node_modules/@octokit/request/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": {
"whatwg-url": "^5.0.0"
}, },
"engines": { "engines": {
"node": ">= 18" "node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
} }
}, },
"node_modules/@octokit/rest": { "node_modules/@octokit/rest": {
@@ -247,6 +206,89 @@
"node": ">= 18" "node": ">= 18"
} }
}, },
"node_modules/@octokit/rest/node_modules/@octokit/auth-token": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/core": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.0.tgz",
"integrity": "sha512-YbAtMWIrbZ9FCXbLwT9wWB8TyLjq9mxpKdgB3dUNxQcIVTf9hJ70gRPwAcqGZdY6WdJPZ0I7jLaaNDCiloGN2A==",
"dependencies": {
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.0.0",
"@octokit/request": "^8.0.2",
"@octokit/request-error": "^5.0.0",
"@octokit/types": "^11.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/endpoint": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.0.tgz",
"integrity": "sha512-szrQhiqJ88gghWY2Htt8MqUDO6++E/EIXqJ2ZEp5ma3uGS46o7LZAzSLt49myB7rT+Hfw5Y6gO3LmOxGzHijAQ==",
"dependencies": {
"@octokit/types": "^11.0.0",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/graphql": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.1.tgz",
"integrity": "sha512-T5S3oZ1JOE58gom6MIcrgwZXzTaxRnxBso58xhozxHpOqSTgDS6YNeEUvZ/kRvXgPrRz/KHnZhtb7jUMRi9E6w==",
"dependencies": {
"@octokit/request": "^8.0.1",
"@octokit/types": "^11.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/openapi-types": {
"version": "18.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.0.0.tgz",
"integrity": "sha512-V8GImKs3TeQRxRtXFpG2wl19V7444NIOTDF24AWuIbmNaNYOQMWRbjcGDXV5B+0n887fgDcuMNOmlul+k+oJtw=="
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest": {
"version": "9.2.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.1.tgz",
"integrity": "sha512-wfGhE/TAkXZRLjksFXuDZdmGnJQHvtU/joFQdweXUgzo1XwvBCD4o4+75NtFfjfLK5IwLf9vHTfSiU3sLRYpRw==",
"dependencies": {
"@octokit/types": "^12.6.0"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": "5"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"dependencies": {
"@octokit/openapi-types": "^20.0.0"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-request-log": { "node_modules/@octokit/rest/node_modules/@octokit/plugin-request-log": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.0.tgz",
@@ -258,13 +300,75 @@
"@octokit/core": ">=5" "@octokit/core": ">=5"
} }
}, },
"node_modules/@octokit/types": { "node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "13.8.0", "version": "10.4.1",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz", "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz",
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==", "integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@octokit/openapi-types": "^23.0.1" "@octokit/types": "^12.6.0"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": "5"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"dependencies": {
"@octokit/openapi-types": "^20.0.0"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/request": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.1.tgz",
"integrity": "sha512-8N+tdUz4aCqQmXl8FpHYfKG9GelDFd7XGVzyN8rc6WxVlYcfpHECnuRkgquzz+WzvHTK62co5di8gSXnzASZPQ==",
"dependencies": {
"@octokit/endpoint": "^9.0.0",
"@octokit/request-error": "^5.0.0",
"@octokit/types": "^11.1.0",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/request-error": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.0.tgz",
"integrity": "sha512-1ue0DH0Lif5iEqT52+Rf/hf0RmGO9NWFjrzmrkArpG9trFfDM/efx00BJHdLGuro4BR/gECxCU2Twf5OKrRFsQ==",
"dependencies": {
"@octokit/types": "^11.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/types": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-11.1.0.tgz",
"integrity": "sha512-Fz0+7GyLm/bHt8fwEqgvRBWwIV1S6wRRyq+V6exRKLVWaKGsuy6H9QFYeBVDV7rK6fO3XwHgQOPxv+cLj2zpXQ==",
"dependencies": {
"@octokit/openapi-types": "^18.0.0"
}
},
"node_modules/@octokit/types": {
"version": "6.41.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
"integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
"dependencies": {
"@octokit/openapi-types": "^12.11.0"
} }
}, },
"node_modules/@vercel/ncc": { "node_modules/@vercel/ncc": {
@@ -292,8 +396,7 @@
"node_modules/deprecation": { "node_modules/deprecation": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
"license": "ISC"
}, },
"node_modules/fetch-blob": { "node_modules/fetch-blob": {
"version": "3.2.0", "version": "3.2.0",
@@ -343,6 +446,14 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-stream": { "node_modules/is-stream": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@@ -393,11 +504,15 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"license": "ISC",
"dependencies": { "dependencies": {
"wrappy": "1" "wrappy": "1"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/tunnel": { "node_modules/tunnel": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
@@ -414,18 +529,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/undici": {
"version": "5.28.5",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz",
"integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==",
"license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/universal-user-agent": { "node_modules/universal-user-agent": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
@@ -447,11 +550,24 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/wrappy": { "node_modules/wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
"license": "ISC"
} }
} }
} }
@@ -11,7 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@actions/core": "^1.10.1", "@actions/core": "^1.10.1",
"@actions/github": "^6.0.0", "@actions/github": "^5.1.1",
"@octokit/auth-action": "^4.0.1", "@octokit/auth-action": "^4.0.1",
"@octokit/rest": "^20.0.2", "@octokit/rest": "^20.0.2",
"hasha": "^5.2.0", "hasha": "^5.2.0",
@@ -26,7 +26,6 @@ jobs:
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUSTUP_PERMIT_COPY_RENAME: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -80,6 +79,7 @@ jobs:
target/release/nym-socks5-client target/release/nym-socks5-client
target/release/nym-api target/release/nym-api
target/release/nym-network-requester target/release/nym-network-requester
target/release/nym-data-observatory
target/release/nym-cli target/release/nym-cli
target/release/nymvisor target/release/nymvisor
target/release/nym-node target/release/nym-node
@@ -97,9 +97,11 @@ jobs:
cp target/release/nym-socks5-client $OUTPUT_DIR cp target/release/nym-socks5-client $OUTPUT_DIR
cp target/release/nym-api $OUTPUT_DIR cp target/release/nym-api $OUTPUT_DIR
cp target/release/nym-network-requester $OUTPUT_DIR cp target/release/nym-network-requester $OUTPUT_DIR
cp target/release/nym-data-observatory $OUTPUT_DIR
cp target/release/nymvisor $OUTPUT_DIR cp target/release/nymvisor $OUTPUT_DIR
cp target/release/nym-node $OUTPUT_DIR cp target/release/nym-node $OUTPUT_DIR
cp target/release/nym-cli $OUTPUT_DIR cp target/release/nym-cli $OUTPUT_DIR
cp target/release/explorer-api $OUTPUT_DIR
if [ ${{ github.event_name == 'workflow_dispatch' && inputs.enable_deb == true }} = true ]; then if [ ${{ github.event_name == 'workflow_dispatch' && inputs.enable_deb == true }} = true ]; then
cp target/debian/*.deb $OUTPUT_DIR cp target/debian/*.deb $OUTPUT_DIR
fi fi
@@ -12,7 +12,6 @@ jobs:
runs-on: arc-ubuntu-22.04 runs-on: arc-ubuntu-22.04
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUSTUP_PERMIT_COPY_RENAME: 1
steps: steps:
- name: Check out repository code - name: Check out repository code
uses: actions/checkout@v4 uses: actions/checkout@v4
+8 -31
View File
@@ -8,18 +8,16 @@ on:
- 'explorer-api/**' - 'explorer-api/**'
- 'gateway/**' - 'gateway/**'
- 'integrations/**' - 'integrations/**'
- 'nym-api/**' - 'mixnode/**'
- 'nym-credential-proxy/**'
- 'nym-network-monitor/**'
- 'nym-node/**'
- 'nym-node-status-api/**'
- 'nym-outfox/**'
- 'nym-validator-rewarder/**'
- 'nyx-chain-watcher/**'
- 'sdk/ffi/**'
- 'sdk/rust/**' - 'sdk/rust/**'
- 'sdk/lib/**'
- 'service-providers/**' - 'service-providers/**'
- 'nym-browser-extension/storage/**' - 'nym-network-monitor/**'
- 'nym-api/**'
- 'nym-node/**'
- 'nym-outfox/**'
- 'nym-data-observatory/**'
- 'nym-validator-rewarder/**'
- 'tools/**' - 'tools/**'
- 'wasm/**' - 'wasm/**'
- 'Cargo.toml' - 'Cargo.toml'
@@ -27,12 +25,6 @@ on:
- '.github/workflows/ci-build.yml' - '.github/workflows/ci-build.yml'
workflow_dispatch: workflow_dispatch:
concurrency:
# only 1 concurrent `ci-build` allowed per branch
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#example-using-concurrency-and-the-default-behavior
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs: jobs:
build: build:
strategy: strategy:
@@ -43,7 +35,6 @@ jobs:
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
IPINFO_API_TOKEN: ${{ secrets.IPINFO_API_TOKEN }} IPINFO_API_TOKEN: ${{ secrets.IPINFO_API_TOKEN }}
RUSTUP_PERMIT_COPY_RENAME: 1
steps: steps:
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev libudev-dev squashfs-tools protobuf-compiler
@@ -61,20 +52,6 @@ jobs:
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
# To avoid running out of disk space, skip generating debug symbols
- name: Set debug to false (unix)
if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'mac')
run: |
sed -i.bak 's/\[profile.dev\]/\[profile.dev\]\ndebug = false/' Cargo.toml
git diff
- name: Set debug to false (win)
if: contains(matrix.os, 'windows')
shell: pwsh
run: |
(Get-Content Cargo.toml) -replace '\[profile.dev\]', "`$&`ndebug = false" | Set-Content Cargo.toml
git diff
- name: Check formatting - name: Check formatting
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@@ -1,57 +0,0 @@
name: ci-check-ns-api-version
on:
pull_request:
paths:
- "nym-node-status-api/**"
env:
WORKING_DIRECTORY: "nym-node-status-api/nym-node-status-api"
jobs:
check-if-tag-exists:
runs-on: arc-ubuntu-22.04-dind
steps:
- name: Checkout repo
uses: actions/checkout@v4
- name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1
id: get_version
with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
- name: Check if git tag exists
run: |
TAG=${{ env.WORKING_DIRECTORY }}-${{ steps.get_version.outputs.result }}
if [[ -z "$TAG" ]]; then
echo "Tag is empty"
exit 1
fi
git ls-remote --tags origin | awk '{print $2}'
if git ls-remote --tags origin | awk '{print $2}' | grep -q "refs/tags/$TAG$" ; then
echo "Tag '$TAG' ALREADY EXISTS on the remote"
exit 1
else
echo "Tag '$TAG' does not exist on the remote"
fi
- name: Check if harbor tag exists
run: |
TAG=${{ steps.get_version.outputs.result }}
registry=https://harbor.nymte.ch
repo_name=nym/node-status-api
if [[ -z $TAG ]]; then
echo "Tag is empty"
exit 1
fi
curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq
exists=$(curl -su ${{ secrets.HARBOR_ROBOT_USERNAME }}:${{ secrets.HARBOR_ROBOT_SECRET }} "$registry/v2/$repo_name/tags/list" | jq --arg tag $TAG '.tags | contains([$tag])' )
if [[ $exists = "true" ]]; then
echo "Version '$TAG' defined in Cargo.toml ALREADY EXISTS as tag in harbor repo"
exit 1
elif [[ $exists = "false" ]]; then
echo "Version '$TAG' doesn't exist on the remote"
else
echo "Unknown output '$exists'"
exit 1
fi
@@ -0,0 +1,6 @@
[
{
"rust":"stable",
"runOnEvent":"always"
}
]
@@ -31,6 +31,7 @@ jobs:
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.77
target: wasm32-unknown-unknown target: wasm32-unknown-unknown
override: true override: true
@@ -39,9 +40,6 @@ jobs:
with: with:
version: '114' version: '114'
- name: Install cosmwasm-check
run: cargo install cosmwasm-check
- name: Build release contracts - name: Build release contracts
run: make contracts run: make contracts
@@ -52,6 +50,7 @@ jobs:
run: | run: |
cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_bandwidth.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/nym_coconut_dkg.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/cw3_flex_multisig.wasm $OUTPUT_DIR
cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR cp contracts/target/wasm32-unknown-unknown/release/cw4_group.wasm $OUTPUT_DIR
+17 -15
View File
@@ -9,17 +9,31 @@ on:
paths: paths:
- 'contracts/**' - 'contracts/**'
- 'common/**' - 'common/**'
- 'Cargo.lock'
- 'Cargo.toml'
- '.github/workflows/ci-contracts.yml' - '.github/workflows/ci-contracts.yml'
jobs: jobs:
matrix_prep:
runs-on: ubuntu-20.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
# creates the matrix strategy from ci-contracts-matrix-includes.json
- uses: actions/checkout@v4
- id: set-matrix
uses: JoshuaTheMiller/conditional-build-matrix@main
with:
inputFile: '.github/workflows/ci-contracts-matrix-includes.json'
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
build: build:
# since it's going to be compiled into wasm, there's absolutely # since it's going to be compiled into wasm, there's absolutely
# no point in running CI on different OS-es # no point in running CI on different OS-es
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
needs: matrix_prep
strategy:
fail-fast: false
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -27,19 +41,11 @@ jobs:
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
profile: minimal profile: minimal
toolchain: stable toolchain: ${{ matrix.rust }}
target: wasm32-unknown-unknown target: wasm32-unknown-unknown
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Install cosmwasm-check
run: cargo install cosmwasm-check
- name: Install wasm-opt
uses: ./.github/actions/install-wasm-opt
with:
version: '114'
- name: Build contracts - name: Build contracts
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
env: env:
@@ -65,7 +71,3 @@ jobs:
with: with:
command: clippy command: clippy
args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings args: --lib --manifest-path contracts/Cargo.toml --workspace --all-targets -- -D warnings
- name: Check chain compatibility against release build
# this will build contracts in release mode, run wasm-opt and finally cosmwasm-check
run: make contracts
-2
View File
@@ -11,8 +11,6 @@ on:
jobs: jobs:
build: build:
runs-on: arc-ubuntu-20.04 runs-on: arc-ubuntu-20.04
env:
RUSTUP_PERMIT_COPY_RENAME: 1
defaults: defaults:
run: run:
working-directory: documentation/docs working-directory: documentation/docs
+1 -3
View File
@@ -16,8 +16,6 @@ on:
jobs: jobs:
build: build:
runs-on: arc-ubuntu-20.04 runs-on: arc-ubuntu-20.04
env:
RUSTUP_PERMIT_COPY_RENAME: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
@@ -44,7 +42,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: "1.23.7" go-version: '1.20'
- name: Install - name: Install
run: yarn run: yarn
-7
View File
@@ -14,7 +14,6 @@ jobs:
runs-on: arc-ubuntu-20.04 runs-on: arc-ubuntu-20.04
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUSTUP_PERMIT_COPY_RENAME: 1
steps: steps:
- name: Install Dependencies (Linux) - name: Install Dependencies (Linux)
run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools run: sudo apt-get update && sudo apt-get -y install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
@@ -31,12 +30,6 @@ jobs:
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy
- name: Set debug to false
working-directory: nym-wallet
run: |
sed -i.bak '1s/^/\[profile.dev\]\ndebug = false\n\n/' Cargo.toml
git diff
- name: Build all binaries - name: Build all binaries
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
+52 -52
View File
@@ -10,66 +10,66 @@ jobs:
build: build:
runs-on: custom-linux runs-on: custom-linux
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install rsync - name: Install rsync
run: sudo apt-get install rsync run: sudo apt-get install rsync
continue-on-error: true continue-on-error: true
- uses: rlespinasse/github-slug-action@v3.x - uses: rlespinasse/github-slug-action@v3.x
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 18
- name: Setup yarn - name: Setup yarn
run: npm install -g yarn run: npm install -g yarn
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: stable
- name: Install wasm-pack - name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build dependencies - name: Build dependencies
run: yarn && yarn build run: yarn && yarn build
- name: Build storybook - name: Build storybook
run: yarn storybook:build run: yarn storybook:build
working-directory: ./nym-wallet working-directory: ./nym-wallet
- name: Deploy branch to CI www (storybook) - name: Deploy branch to CI www (storybook)
continue-on-error: true continue-on-error: true
uses: easingthemes/ssh-deploy@main uses: easingthemes/ssh-deploy@main
env: env:
SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }} SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete" ARGS: "-rltgoDzvO --delete"
SOURCE: "nym-wallet/storybook-static/" SOURCE: "nym-wallet/storybook-static/"
REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }} REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }}
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }} REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }} TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/wallet-${{ env.GITHUB_REF_SLUG }}
EXCLUDE: "/dist/, /node_modules/" EXCLUDE: "/dist/, /node_modules/"
- name: Matrix - Node Install - name: Matrix - Node Install
run: npm install run: npm install
working-directory: .github/workflows/support-files working-directory: .github/workflows/support-files
- name: Matrix - Send Notification - name: Matrix - Send Notification
env: env:
NYM_NOTIFICATION_KIND: nym-wallet NYM_NOTIFICATION_KIND: nym-wallet
NYM_PROJECT_NAME: "nym-wallet" NYM_PROJECT_NAME: "nym-wallet"
NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}" NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}"
NYM_CI_WWW_LOCATION: "wallet-${{ env.GITHUB_REF_SLUG }}" NYM_CI_WWW_LOCATION: "wallet-${{ env.GITHUB_REF_SLUG }}"
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}" GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
GIT_BRANCH: "${GITHUB_REF##*/}" GIT_BRANCH: "${GITHUB_REF##*/}"
IS_SUCCESS: "${{ job.status == 'success' }}" IS_SUCCESS: "${{ job.status == 'success' }}"
MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}" MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}"
MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}" MATRIX_ROOM: "${{ secrets.MATRIX_ROOM }}"
MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}" MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}"
MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}" MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}"
MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}" MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}"
uses: docker://keybaseio/client:stable-node uses: docker://keybaseio/client:stable-node
with: with:
args: .github/workflows/support-files/notifications/entry_point.sh args: .github/workflows/support-files/notifications/entry_point.sh
+1 -8
View File
@@ -1,7 +1,6 @@
name: ci-sdk-wasm name: ci-sdk-wasm
on: on:
workflow_dispatch:
pull_request: pull_request:
paths: paths:
- 'wasm/**' - 'wasm/**'
@@ -14,7 +13,6 @@ jobs:
runs-on: arc-ubuntu-20.04 runs-on: arc-ubuntu-20.04
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
RUSTUP_PERMIT_COPY_RENAME: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -33,7 +31,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: "1.23.7" go-version: '1.20'
- name: Install wasm-pack - name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
@@ -46,11 +44,6 @@ jobs:
- name: Install wasm-bindgen-cli - name: Install wasm-bindgen-cli
run: cargo install wasm-bindgen-cli run: cargo install wasm-bindgen-cli
- name: Set debug to false
run: |
sed -i.bak 's/\[profile.dev\]/\[profile.dev\]\ndebug = false/' Cargo.toml
git diff
- name: "Build" - name: "Build"
run: make sdk-wasm-build run: make sdk-wasm-build
+3 -2
View File
@@ -2,18 +2,19 @@ name: publish-nym-contracts
on: on:
workflow_dispatch: workflow_dispatch:
release: release:
types: [ created ] types: [created]
jobs: jobs:
build: build:
if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }} if: ${{ (startsWith(github.ref, 'refs/tags/nym-contracts-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-latest runs-on: [self-hosted, custom-ubuntu-20.04]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: 1.77
target: wasm32-unknown-unknown target: wasm32-unknown-unknown
override: true override: true
@@ -14,7 +14,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
platform: [macos-15] platform: [macos-12-large]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
outputs: outputs:
@@ -30,7 +30,7 @@ jobs:
- name: Node - name: Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 21 node-version: 18
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
@@ -36,7 +36,7 @@ jobs:
- name: Node - name: Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 21 node-version: 18
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
@@ -49,7 +49,7 @@ jobs:
- name: Node - name: Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 21 node-version: 18
- name: Install Rust stable - name: Install Rust stable
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
@@ -49,7 +49,7 @@ jobs:
"build-tools;$SDK_BUILDTOOLS_VERSION" "build-tools;$SDK_BUILDTOOLS_VERSION"
- name: Install Rust toolchain - name: Install Rust toolchain
uses: dtolnay/rust-toolchain@1.100.0 uses: dtolnay/rust-toolchain@1.90.0
- name: Install rust android targets - name: Install rust android targets
run: | run: |
+6 -1
View File
@@ -31,7 +31,12 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: "1.23.7" go-version: "1.20"
- name: Install TinyGo
uses: acifani/setup-tinygo@v2
with:
tinygo-version: "0.27.0"
- name: Install dependencies - name: Install dependencies
run: yarn run: yarn
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1 uses: mikefarah/yq@v4.44.6
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-credential-proxy/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1 uses: mikefarah/yq@v4.44.6
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1 uses: mikefarah/yq@v4.44.6
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-network-monitor/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/nym-network-monitor/Cargo.toml
@@ -31,7 +31,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1 uses: mikefarah/yq@v4.44.6
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1 uses: mikefarah/yq@v4.44.6
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1 uses: mikefarah/yq@v4.44.6
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1 uses: mikefarah/yq@v4.44.6
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
@@ -26,7 +26,7 @@ jobs:
git config --global user.name "Lawrence Stalder" git config --global user.name "Lawrence Stalder"
- name: Get version from cargo.toml - name: Get version from cargo.toml
uses: mikefarah/yq@v4.45.1 uses: mikefarah/yq@v4.44.6
id: get_version id: get_version
with: with:
cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml cmd: yq -oy '.package.version' ${{ env.WORKING_DIRECTORY }}/Cargo.toml
+6 -493
View File
@@ -4,499 +4,12 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased] ## [Unreleased]
## [2025.6-chuckles] (2025-03-31)
- Remove Google public DNS ([#5660])
- Revert using AsyncWrite sink in IPR ([#5656])
- Add fd callback for initial authentication ([#5654])
- Add concurrency limit to CI ([#5651])
- Remove UNIQUE constraint on node pubkey ([#5649])
- Add RUSTUP_PERMIT_COPY_RENAME in two workflows that we forgot about ([#5646])
- Upgrade sha2 to workspace version for validator-client ([#5644])
- Add max_retransmissions flag on each message ([#5642])
- build(deps): bump zip from 2.2.2 to 2.4.1 ([#5639])
- build(deps): bump dtolnay/rust-toolchain from 1.90.0 to 1.100.0 ([#5638])
- / regenerated yarn.lock ([#5636])
- Rework IPR codec to extract out timer and implement AsyncWrite ([#5632])
- build(deps): bump tempfile from 3.18.0 to 3.19.0 ([#5631])
- build(deps): bump zeroize from 1.6.0 to 1.8.1 ([#5630])
- build(deps): bump once_cell from 1.20.3 to 1.21.1 ([#5629])
- build(deps): bump uuid from 1.15.1 to 1.16.0 ([#5628])
- build(deps): bump celes from 2.5.0 to 2.6.0 ([#5627])
- build(deps): bump http from 1.2.0 to 1.3.1 ([#5626])
- build(deps): bump humantime from 2.1.0 to 2.2.0 ([#5625])
- build(deps): bump the patch-updates group with 8 updates ([#5624])
- build(deps): bump @babel/runtime from 7.16.3 to 7.26.10 in /testnet-faucet ([#5621])
- Feature/paginated ticketbooks challenge ([#5619])
- build(deps-dev): bump webpack from 5.77.0 to 5.98.0 in /wasm/client/internal-dev ([#5615])
- build(deps-dev): bump ws from 8.13.0 to 8.18.1 in /wasm/client/internal-dev ([#5614])
- build(deps): bump golang.org/x/net from 0.23.0 to 0.36.0 in /wasm/mix-fetch/go-mix-conn ([#5613])
- build(deps): bump braces from 3.0.2 to 3.0.3 in /sdk/typescript/packages/mix-fetch-node ([#5612])
- Wireguard exit policies (and tests) ([#5557])
- Explorer V2 ([#5548])
- Clean stale partially received buffers ([#5536])
- Corrected typos ([#5497])
- build(deps): bump @octokit/plugin-paginate-rest and @actions/github in /.github/actions/nym-hash-releases/src ([#5488])
- feature: upgrade cosmwasm to 2.2 ([#5479])
- build(deps): bump store2 from 2.14.3 to 2.14.4 ([#5391])
- build(deps): bump nanoid from 3.3.7 to 3.3.8 in /documentation/docs ([#5335])
- build(deps): bump next from 13.5.7 to 14.2.15 in /documentation/docs ([#5281])
- Bump http-proxy-middleware from 2.0.6 to 2.0.7 ([#5019])
[#5660]: https://github.com/nymtech/nym/pull/5660
[#5656]: https://github.com/nymtech/nym/pull/5656
[#5654]: https://github.com/nymtech/nym/pull/5654
[#5651]: https://github.com/nymtech/nym/pull/5651
[#5649]: https://github.com/nymtech/nym/pull/5649
[#5646]: https://github.com/nymtech/nym/pull/5646
[#5644]: https://github.com/nymtech/nym/pull/5644
[#5642]: https://github.com/nymtech/nym/pull/5642
[#5639]: https://github.com/nymtech/nym/pull/5639
[#5638]: https://github.com/nymtech/nym/pull/5638
[#5636]: https://github.com/nymtech/nym/pull/5636
[#5632]: https://github.com/nymtech/nym/pull/5632
[#5631]: https://github.com/nymtech/nym/pull/5631
[#5630]: https://github.com/nymtech/nym/pull/5630
[#5629]: https://github.com/nymtech/nym/pull/5629
[#5628]: https://github.com/nymtech/nym/pull/5628
[#5627]: https://github.com/nymtech/nym/pull/5627
[#5626]: https://github.com/nymtech/nym/pull/5626
[#5625]: https://github.com/nymtech/nym/pull/5625
[#5624]: https://github.com/nymtech/nym/pull/5624
[#5621]: https://github.com/nymtech/nym/pull/5621
[#5619]: https://github.com/nymtech/nym/pull/5619
[#5615]: https://github.com/nymtech/nym/pull/5615
[#5614]: https://github.com/nymtech/nym/pull/5614
[#5613]: https://github.com/nymtech/nym/pull/5613
[#5612]: https://github.com/nymtech/nym/pull/5612
[#5557]: https://github.com/nymtech/nym/pull/5557
[#5548]: https://github.com/nymtech/nym/pull/5548
[#5536]: https://github.com/nymtech/nym/pull/5536
[#5497]: https://github.com/nymtech/nym/pull/5497
[#5488]: https://github.com/nymtech/nym/pull/5488
[#5479]: https://github.com/nymtech/nym/pull/5479
[#5391]: https://github.com/nymtech/nym/pull/5391
[#5335]: https://github.com/nymtech/nym/pull/5335
[#5281]: https://github.com/nymtech/nym/pull/5281
[#5019]: https://github.com/nymtech/nym/pull/5019
## [2025.5-chokito] (2025-03-18)
- build(deps): bump braces from 3.0.2 to 3.0.3 in /sdk/typescript/packages/nodejs-client ([#5611])
- build(deps-dev): bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /wasm/client/internal-dev ([#5610])
- Export lane queue lengths in sdk ([#5609])
- Chore/more payment watcher debug endpoints ([#5608])
- build(deps): bump @babel/helpers from 7.24.4 to 7.26.10 ([#5606])
- Chore/update bls12 381 fork ([#5605])
- chore: change auth v2 timestamp skew and allow values from the future ([#5604])
- Chore/payment watcher debug endpoints ([#5601])
- Allow resetting all SURB sender tags ([#5600])
- introduce internal tool for checking signer status ([#5598])
- build(deps-dev): bump webpack from 5.77.0 to 5.98.0 in /wasm/mix-fetch/internal-dev ([#5597])
- build(deps): bump body-parser and express in /wasm/mix-fetch/internal-dev ([#5596])
- build(deps): bump serve-static and express in /wasm/mix-fetch/internal-dev ([#5594])
- build(deps-dev): bump ws from 8.13.0 to 8.18.1 in /wasm/mix-fetch/internal-dev ([#5593])
- build(deps): bump cookie and express in /wasm/client/internal-dev ([#5592])
- build(deps): bump cookie and express in /wasm/mix-fetch/internal-dev ([#5591])
- build(deps): bump braces from 3.0.2 to 3.0.3 in /wasm/zknym-lib/internal-dev ([#5590])
- build(deps): bump webpack-dev-middleware from 5.3.3 to 5.3.4 in /wasm/zknym-lib/internal-dev ([#5589])
- build(deps): bump tempfile from 3.17.1 to 3.18.0 ([#5588])
- build(deps): bump tokio from 1.43.0 to 1.44.0 ([#5587])
- build(deps): bump the patch-updates group with 8 updates ([#5585])
- build(deps): bump ring from 0.17.9 to 0.17.13 ([#5583])
- delete double memo field in send modal ([#5578])
- Server Side internal DoT/DoH opt out ([#5577])
- Rust SDK SURB example: change hardcoded file to tempdir ([#5576])
- Add /v3/nym-nodes ([#5569])
- chore: start sending v2 sphinx packets ([#5554])
- build(deps): bump the patch-updates group across 1 directory with 14 updates ([#5549])
- build(deps): bump uuid from 1.13.2 to 1.15.1 ([#5542])
- build(deps): bump rs_merkle from 1.4.2 to 1.5.0 ([#5541])
- feature: v2 authentication request ([#5537])
- Set RUSTUP_PERMIT_COPY_RENAME ([#5533])
- feature: disallow routing mix packets to nodes not present in the topology ([#5526])
- Make "Memo" visible per default on send NYM ([#5524])
- feat: make sure any terminated task kills the watcher and write run info to db ([#5517])
- Another total_stake SQL fix ([#5516])
- Fix total_stake on SQL update ([#5514])
- build(deps): bump flate2 from 1.0.35 to 1.1.0 ([#5510])
- build(deps): bump itertools from 0.13.0 to 0.14.0 ([#5509])
- build(deps): bump the patch-updates group with 2 updates ([#5505])
- Treat gateways as Nym Nodes ([#5504])
- Update version in Cargo.toml ([#5503])
- feat: use ct_eq for checking bearer token ([#5501])
- Add extra args for the probe ([#5499])
- Fix stats bug & remove HM caching ([#5495])
- fix: Cargo.lock for contracts ([#5489])
- Display error messages if IPv4 or IPv6 address not found on nymtun0 ([#5465])
[#5611]: https://github.com/nymtech/nym/pull/5611
[#5610]: https://github.com/nymtech/nym/pull/5610
[#5609]: https://github.com/nymtech/nym/pull/5609
[#5608]: https://github.com/nymtech/nym/pull/5608
[#5606]: https://github.com/nymtech/nym/pull/5606
[#5605]: https://github.com/nymtech/nym/pull/5605
[#5604]: https://github.com/nymtech/nym/pull/5604
[#5601]: https://github.com/nymtech/nym/pull/5601
[#5600]: https://github.com/nymtech/nym/pull/5600
[#5598]: https://github.com/nymtech/nym/pull/5598
[#5597]: https://github.com/nymtech/nym/pull/5597
[#5596]: https://github.com/nymtech/nym/pull/5596
[#5594]: https://github.com/nymtech/nym/pull/5594
[#5593]: https://github.com/nymtech/nym/pull/5593
[#5592]: https://github.com/nymtech/nym/pull/5592
[#5591]: https://github.com/nymtech/nym/pull/5591
[#5590]: https://github.com/nymtech/nym/pull/5590
[#5589]: https://github.com/nymtech/nym/pull/5589
[#5588]: https://github.com/nymtech/nym/pull/5588
[#5587]: https://github.com/nymtech/nym/pull/5587
[#5585]: https://github.com/nymtech/nym/pull/5585
[#5583]: https://github.com/nymtech/nym/pull/5583
[#5578]: https://github.com/nymtech/nym/pull/5578
[#5577]: https://github.com/nymtech/nym/pull/5577
[#5576]: https://github.com/nymtech/nym/pull/5576
[#5569]: https://github.com/nymtech/nym/pull/5569
[#5554]: https://github.com/nymtech/nym/pull/5554
[#5549]: https://github.com/nymtech/nym/pull/5549
[#5542]: https://github.com/nymtech/nym/pull/5542
[#5541]: https://github.com/nymtech/nym/pull/5541
[#5537]: https://github.com/nymtech/nym/pull/5537
[#5533]: https://github.com/nymtech/nym/pull/5533
[#5526]: https://github.com/nymtech/nym/pull/5526
[#5524]: https://github.com/nymtech/nym/pull/5524
[#5517]: https://github.com/nymtech/nym/pull/5517
[#5516]: https://github.com/nymtech/nym/pull/5516
[#5514]: https://github.com/nymtech/nym/pull/5514
[#5510]: https://github.com/nymtech/nym/pull/5510
[#5509]: https://github.com/nymtech/nym/pull/5509
[#5505]: https://github.com/nymtech/nym/pull/5505
[#5504]: https://github.com/nymtech/nym/pull/5504
[#5503]: https://github.com/nymtech/nym/pull/5503
[#5501]: https://github.com/nymtech/nym/pull/5501
[#5499]: https://github.com/nymtech/nym/pull/5499
[#5495]: https://github.com/nymtech/nym/pull/5495
[#5489]: https://github.com/nymtech/nym/pull/5489
[#5465]: https://github.com/nymtech/nym/pull/5465
## [2025.4-dorina-patched] (2025-03-06)
- use legacy crypto for constructing SURB headers ([#5579])
- bugfix: make sure to correctly decode response content when putting it into error message ([#5571])
- Tweak surb management to be more conservative ([#5570])
- Deserialize v5 authenticator requests ([#5568])
- chore: additional logs when attempting to load ecash keys ([#5567])
- add full response body to error message upon decoding failure ([#5566])
- hotfix: ensure we bail on merkle leaves insertion upon missing data ([#5565])
- feature: v2 authentication request (#5537) ([#5563])
- Create authenticator v5 request/response types ([#5561])
[#5579]: https://github.com/nymtech/nym/pull/5579
[#5571]: https://github.com/nymtech/nym/pull/5571
[#5570]: https://github.com/nymtech/nym/pull/5570
[#5568]: https://github.com/nymtech/nym/pull/5568
[#5567]: https://github.com/nymtech/nym/pull/5567
[#5566]: https://github.com/nymtech/nym/pull/5566
[#5565]: https://github.com/nymtech/nym/pull/5565
[#5563]: https://github.com/nymtech/nym/pull/5563
[#5561]: https://github.com/nymtech/nym/pull/5561
## [2025.4-dorina] (2025-03-04)
- fixed sphinx version metrics registration ([#5546])
- Feature/chain status api ([#5539])
- Add SURBs soft threshold ([#5535])
- Simplify IPR v8 ([#5532])
- Shared instance for DNS AsyncResolver ([#5523])
- merge #5512 again after reverting due to incorrect rebase ([#5520])
- cherry-pick 17d3ff2d775f61aee381d90a304ed416c08f33fc onto dorina ([#5519])
- cherry-pick 6e5d0dac1b75413c5f09122b0d953f8ec6ef48df onto dorina ([#5518])
- chore: workspace global panic preventing lints ([#5512])
- bugfix: dont query for ecash apis unless necessary when spending ticketbooks ([#5508])
- bugfix: bound check when recovering a reply SURB ([#5502])
- chore: removed all old coconut code ([#5500])
- IPR request types v8 ([#5498])
- Support static routes for HTTP requests ([#5487])
- build(deps): bump the patch-updates group across 1 directory with 3 updates ([#5482])
- added missing import to doctest ([#5480])
- adjusted TestSetup::new_complex to ensure bonded node's existence ([#5478])
- Trigger contracts CI on main workspace Cargo changes ([#5477])
- build(deps): bump http from 1.1.0 to 1.2.0 ([#5472])
- build(deps): bump utoipa-swagger-ui from 8.0.3 to 8.1.0 ([#5471])
- build(deps): bump colored from 2.1.0 to 2.2.0 ([#5470])
- build(deps): bump celes from 2.4.0 to 2.5.0 ([#5469])
- build(deps): bump the patch-updates group with 2 updates ([#5467])
- build(deps): bump elliptic from 6.5.4 to 6.6.1 in /docker/typescript_client/upload_contract ([#5463])
- Run cargo autoinherit ([#5460])
- Fix clippy::precedence ([#5457])
- Provide Interval context with node descriptor endpoints ([#5456])
- fix: update fx average rate calcs to ignore 0 values ([#5454])
- Feature/add gbp currency ([#5453])
- Add helper to extract a list of sqlite files with journal files wal/shm ([#5452])
- Add a middleware layer to the nym api allowing for data compression ([#5451])
- Condense core API functionalities and enable gzip decompression for reqwest payloads ([#5450])
- build(deps): bump uniffi_build from 0.25.3 to 0.29.0 ([#5448])
- Upgrade tower to 0.5.2 ([#5446])
- build(deps): bump hickory-proto from 0.24.2 to 0.24.3 ([#5444])
- Seedable clients ([#5440])
- build(deps): bump the patch-updates group across 1 directory with 10 updates ([#5439])
- Remove all recv_with_delay and add shutdown condition to loops in client-core ([#5435])
- Disable the test for checking the remaining bandwidth in nym-node-status-api ([#5425])
- Dz nym node stats ([#5418])
- build(deps): bump hyper from 1.4.1 to 1.6.0 ([#5416])
- build(deps): bump publicsuffix from 2.2.3 to 2.3.0 ([#5367])
- Nymnode entrypoint docker ([#5300])
[#5546]: https://github.com/nymtech/nym/pull/5546
[#5539]: https://github.com/nymtech/nym/pull/5539
[#5535]: https://github.com/nymtech/nym/pull/5535
[#5532]: https://github.com/nymtech/nym/pull/5532
[#5523]: https://github.com/nymtech/nym/pull/5523
[#5520]: https://github.com/nymtech/nym/pull/5520
[#5519]: https://github.com/nymtech/nym/pull/5519
[#5518]: https://github.com/nymtech/nym/pull/5518
[#5512]: https://github.com/nymtech/nym/pull/5512
[#5508]: https://github.com/nymtech/nym/pull/5508
[#5502]: https://github.com/nymtech/nym/pull/5502
[#5500]: https://github.com/nymtech/nym/pull/5500
[#5498]: https://github.com/nymtech/nym/pull/5498
[#5487]: https://github.com/nymtech/nym/pull/5487
[#5482]: https://github.com/nymtech/nym/pull/5482
[#5480]: https://github.com/nymtech/nym/pull/5480
[#5478]: https://github.com/nymtech/nym/pull/5478
[#5477]: https://github.com/nymtech/nym/pull/5477
[#5472]: https://github.com/nymtech/nym/pull/5472
[#5471]: https://github.com/nymtech/nym/pull/5471
[#5470]: https://github.com/nymtech/nym/pull/5470
[#5469]: https://github.com/nymtech/nym/pull/5469
[#5467]: https://github.com/nymtech/nym/pull/5467
[#5463]: https://github.com/nymtech/nym/pull/5463
[#5460]: https://github.com/nymtech/nym/pull/5460
[#5457]: https://github.com/nymtech/nym/pull/5457
[#5456]: https://github.com/nymtech/nym/pull/5456
[#5454]: https://github.com/nymtech/nym/pull/5454
[#5453]: https://github.com/nymtech/nym/pull/5453
[#5452]: https://github.com/nymtech/nym/pull/5452
[#5451]: https://github.com/nymtech/nym/pull/5451
[#5450]: https://github.com/nymtech/nym/pull/5450
[#5448]: https://github.com/nymtech/nym/pull/5448
[#5446]: https://github.com/nymtech/nym/pull/5446
[#5444]: https://github.com/nymtech/nym/pull/5444
[#5440]: https://github.com/nymtech/nym/pull/5440
[#5439]: https://github.com/nymtech/nym/pull/5439
[#5435]: https://github.com/nymtech/nym/pull/5435
[#5425]: https://github.com/nymtech/nym/pull/5425
[#5418]: https://github.com/nymtech/nym/pull/5418
[#5416]: https://github.com/nymtech/nym/pull/5416
[#5367]: https://github.com/nymtech/nym/pull/5367
[#5300]: https://github.com/nymtech/nym/pull/5300
## [2025.3-ruta] (2025-02-10)
- Push down forget me to client configs ([#5431])
- Fix statistics shutdown ([#5426])
- Make wait_for_graceful_shutdown to be pub ([#5424])
- Upgrade to thiserror 2.0 ([#5414])
- build(deps): bump the patch-updates group across 1 directory with 9 updates ([#5406])
- Relocate a validator api function ([#5401])
- Send shutdown instead of panic when reaching max fail ([#5398])
- Change Explorer URL to new smooshed nodes ([#5396])
- reduce log severity for checking topology validity ([#5395])
- MixnetClient can send ClientRequests ([#5381])
- Fix missing path triggers for CI ([#5380])
- Uncouple storage reference for bandwidth client ([#5372])
- build(deps): bump tokio from 1.40.0 to 1.43.0 ([#5370])
- DNS resolver configuration for internal HTTP client lookups ([#5355])
- Update README.md ([#5328])
- Update README.md ([#5327])
[#5431]: https://github.com/nymtech/nym/pull/5431
[#5426]: https://github.com/nymtech/nym/pull/5426
[#5424]: https://github.com/nymtech/nym/pull/5424
[#5414]: https://github.com/nymtech/nym/pull/5414
[#5406]: https://github.com/nymtech/nym/pull/5406
[#5401]: https://github.com/nymtech/nym/pull/5401
[#5398]: https://github.com/nymtech/nym/pull/5398
[#5396]: https://github.com/nymtech/nym/pull/5396
[#5395]: https://github.com/nymtech/nym/pull/5395
[#5381]: https://github.com/nymtech/nym/pull/5381
[#5380]: https://github.com/nymtech/nym/pull/5380
[#5372]: https://github.com/nymtech/nym/pull/5372
[#5370]: https://github.com/nymtech/nym/pull/5370
[#5355]: https://github.com/nymtech/nym/pull/5355
[#5328]: https://github.com/nymtech/nym/pull/5328
[#5327]: https://github.com/nymtech/nym/pull/5327
## [2025.2-hu] (2025-02-04)
- Feature/remove double spending bloomfilter ([#5417])
- HU - Downgrade harmless log message from info to debug ([#5405])
- lower default ticket verification quorum to 0.7 ([#5404])
- Downgrade harmless log message from info to debug ([#5403])
- Redirect from mixnode page to nodes page ([#5397])
- chore :update version of chain watcher and validator rewarder ([#5394])
- bugfix: correctly handle ignore epoch roles flag ([#5390])
- bugfix: terminate mixnet socket listener on shutdown ([#5389])
- feat: make client ignore dual mode nodes by default ([#5388])
- Handle ecash network errors differently ([#5378])
- Remove empty ephemeral keys ([#5376])
- fixed sql migration for adding default message timestamp ([#5374])
- Bind to [::] on nym-node for both IP versions ([#5361])
- exposed NymApiClient method for obtaining node performance history ([#5360])
- Client gateway selection ([#5358])
- chore: refresh wasm sdk ([#5353])
- chore: update indexed_db_futures ([#5347])
- build(deps): bump mikefarah/yq from 4.44.6 to 4.45.1 ([#5342])
- updated cosmrs and tendermint-rpc to their most recent versions ([#5339])
- build(deps): bump ts-rs from 10.0.0 to 10.1.0 ([#5338])
- build(deps): bump tempfile from 3.14.0 to 3.15.0 ([#5337])
- build(deps): bump the patch-updates group with 8 updates ([#5336])
- feature: introduce /load endpoint for self-reported quantised NymNode load ([#5326])
- feature: `CancellationToken`-based shutdowns ([#5325])
- Use expect in geodata test to give error message on failure ([#5314])
- feature: periodically remove stale gateway messages ([#5312])
- build(deps): bump the patch-updates group across 1 directory with 35 updates ([#5310])
- Add dependabot assigns for the root cargo ecosystem ([#5297])
- Move tun constants to network defaults ([#5286])
- Include IPINFO_API_TOKEN in nightly CI ([#5285])
- Nyx Chain Watcher ([#5274])
- bugfix: remove unnecessary arguments for nym-api swagger endpoints ([#5272])
- feature: nym topology revamp ([#5271])
- Add windows to CI builds ([#5269])
- http-api-client: deduplicate code ([#5267])
- build(deps): bump http from 1.1.0 to 1.2.0 ([#5228])
- NS API: add mixnet scraper ([#5200])
- build(deps): bump criterion from 0.4.0 to 0.5.1 ([#4911])
[#5417]: https://github.com/nymtech/nym/pull/5417
[#5405]: https://github.com/nymtech/nym/pull/5405
[#5404]: https://github.com/nymtech/nym/pull/5404
[#5403]: https://github.com/nymtech/nym/pull/5403
[#5397]: https://github.com/nymtech/nym/pull/5397
[#5394]: https://github.com/nymtech/nym/pull/5394
[#5390]: https://github.com/nymtech/nym/pull/5390
[#5389]: https://github.com/nymtech/nym/pull/5389
[#5388]: https://github.com/nymtech/nym/pull/5388
[#5378]: https://github.com/nymtech/nym/pull/5378
[#5376]: https://github.com/nymtech/nym/pull/5376
[#5374]: https://github.com/nymtech/nym/pull/5374
[#5361]: https://github.com/nymtech/nym/pull/5361
[#5360]: https://github.com/nymtech/nym/pull/5360
[#5358]: https://github.com/nymtech/nym/pull/5358
[#5353]: https://github.com/nymtech/nym/pull/5353
[#5347]: https://github.com/nymtech/nym/pull/5347
[#5342]: https://github.com/nymtech/nym/pull/5342
[#5339]: https://github.com/nymtech/nym/pull/5339
[#5338]: https://github.com/nymtech/nym/pull/5338
[#5337]: https://github.com/nymtech/nym/pull/5337
[#5336]: https://github.com/nymtech/nym/pull/5336
[#5326]: https://github.com/nymtech/nym/pull/5326
[#5325]: https://github.com/nymtech/nym/pull/5325
[#5314]: https://github.com/nymtech/nym/pull/5314
[#5312]: https://github.com/nymtech/nym/pull/5312
[#5310]: https://github.com/nymtech/nym/pull/5310
[#5297]: https://github.com/nymtech/nym/pull/5297
[#5286]: https://github.com/nymtech/nym/pull/5286
[#5285]: https://github.com/nymtech/nym/pull/5285
[#5274]: https://github.com/nymtech/nym/pull/5274
[#5272]: https://github.com/nymtech/nym/pull/5272
[#5271]: https://github.com/nymtech/nym/pull/5271
[#5269]: https://github.com/nymtech/nym/pull/5269
[#5267]: https://github.com/nymtech/nym/pull/5267
[#5228]: https://github.com/nymtech/nym/pull/5228
[#5200]: https://github.com/nymtech/nym/pull/5200
[#4911]: https://github.com/nymtech/nym/pull/4911
## [2025.1-reeses] (2025-01-15)
- Feature, Future/legacy alert ([#5346])
- chore: readjusted --mode behaviour to fix the regression ([#5331])
- chore: apply 1.84 linter suggestions ([#5330])
- bugfix: make sure refresh data key matches bond info ([#5329])
- reduce log severity for number of packets being delayed ([#5321])
- feat: warn users if node is run in exit mode only ([#5320])
- Bugfix/contract version assignment ([#5318])
- fixed client session histogram buckets ([#5316])
- amend 250gb limit ([#5313])
- feature: expand nym-node prometheus metrics ([#5298])
- Cherry picked #5286 ([#5287])
- Add close to credential storage ([#5283])
- feature: wireguard metrics ([#5278])
- Add PATCH support to nym-http-api-client ([#5260])
- chore: removed legacy socks5 listener ([#5259])
- bugfix: make sure to apply gateway score filtering when choosing initial node ([#5256])
- Update TS bindings ([#5255])
- Add conversion unit tests for auth msg ([#5251])
- Add control messages to GatewayTransciver ([#5247])
- Remove unneeded async function annotation ([#5246])
- bugfix: make sure to update timestamp of last batch verification to prevent double redemption ([#5239])
- Add FromStr impl for UserAgent ([#5236])
- Extend swagger docs ([#5235])
- TicketType derive Hash and Eq ([#5233])
- Add fd callback to client core ([#5230])
- Extend raw ws fd for gateway client ([#5218])
- Shipping raw metrics to PG ([#5216])
- Change sqlite journal mode to WAL ([#5213])
- Derive serialize for UserAgent ([#5210])
- Restore Location fields ([#5208])
- better date serialization ([#5207])
- Fix overflow ([#5204])
- feature: hopefully final steps of the smoosh™️ ([#5201])
- Fix overflow ([#5184])
- NS API - Gateway stats scraping ([#5180])
- introduced initial internal commands for nym-cli: ecash key and request generation ([#5174])
- Move NS client to separate package under NS API ([#5171])
- build(deps): bump micromatch from 4.0.4 to 4.0.8 in /testnet-faucet ([#4813])
[#5346]: https://github.com/nymtech/nym/pull/5346
[#5331]: https://github.com/nymtech/nym/pull/5331
[#5330]: https://github.com/nymtech/nym/pull/5330
[#5329]: https://github.com/nymtech/nym/pull/5329
[#5321]: https://github.com/nymtech/nym/pull/5321
[#5320]: https://github.com/nymtech/nym/pull/5320
[#5318]: https://github.com/nymtech/nym/pull/5318
[#5316]: https://github.com/nymtech/nym/pull/5316
[#5313]: https://github.com/nymtech/nym/pull/5313
[#5298]: https://github.com/nymtech/nym/pull/5298
[#5287]: https://github.com/nymtech/nym/pull/5287
[#5283]: https://github.com/nymtech/nym/pull/5283
[#5278]: https://github.com/nymtech/nym/pull/5278
[#5260]: https://github.com/nymtech/nym/pull/5260
[#5259]: https://github.com/nymtech/nym/pull/5259
[#5256]: https://github.com/nymtech/nym/pull/5256
[#5255]: https://github.com/nymtech/nym/pull/5255
[#5251]: https://github.com/nymtech/nym/pull/5251
[#5247]: https://github.com/nymtech/nym/pull/5247
[#5246]: https://github.com/nymtech/nym/pull/5246
[#5239]: https://github.com/nymtech/nym/pull/5239
[#5236]: https://github.com/nymtech/nym/pull/5236
[#5235]: https://github.com/nymtech/nym/pull/5235
[#5233]: https://github.com/nymtech/nym/pull/5233
[#5230]: https://github.com/nymtech/nym/pull/5230
[#5218]: https://github.com/nymtech/nym/pull/5218
[#5216]: https://github.com/nymtech/nym/pull/5216
[#5213]: https://github.com/nymtech/nym/pull/5213
[#5210]: https://github.com/nymtech/nym/pull/5210
[#5208]: https://github.com/nymtech/nym/pull/5208
[#5207]: https://github.com/nymtech/nym/pull/5207
[#5204]: https://github.com/nymtech/nym/pull/5204
[#5201]: https://github.com/nymtech/nym/pull/5201
[#5184]: https://github.com/nymtech/nym/pull/5184
[#5180]: https://github.com/nymtech/nym/pull/5180
[#5174]: https://github.com/nymtech/nym/pull/5174
[#5171]: https://github.com/nymtech/nym/pull/5171
[#4813]: https://github.com/nymtech/nym/pull/4813
## [2024.14-crunch-patched] (2024-12-17)
- Fixes an issue to allow previously registered clients to connect to latest nym-nodes
- Fixes compatibility issues between nym-nodes and older clients
## [2024.14-crunch] (2024-12-11) ## [2024.14-crunch] (2024-12-11)
- Merge/release/2024.14-crunch ([#5242]) - Merge/release/2024.14-crunch ([#5242])
- bugfix: added explicit openapi servers to account for route prefixes ([#5237]) - bugfix: added explicit openapi servers to account for route prefixes ([#5237])
- Further config score adjustments ([#5225]) - Further config score adjustments ([#5225])
- feature: remove any filtering on node semver ([#5224]) - feature: remve any filtering on node semver ([#5224])
- Backport #5218 ([#5220]) - Backport #5218 ([#5220])
- Derive serialize for UserAgent (#5210) ([#5217]) - Derive serialize for UserAgent (#5210) ([#5217])
- dont consider legacy nodes for rewarded set selection ([#5215]) - dont consider legacy nodes for rewarded set selection ([#5215])
@@ -675,7 +188,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- bugfix/feature: added NymApiClient method to get all skimmed nodes ([#5062]) - bugfix/feature: added NymApiClient method to get all skimmed nodes ([#5062])
- Merge1/release/2024.13 magura ([#5061]) - Merge1/release/2024.13 magura ([#5061])
- added hacky routes to return nymnodes alongside legacy nodes ([#5051]) - added hacky routes to return nymnodes alongside legacy nodes ([#5051])
- bugfix: mark migrated gateways as rewarded in the previous epoch in case they're, their, there in the rewarded set ([#5049]) - bugfix: mark migrated gateways as rewarded in the previous epoch in case theyre in the rewarded set ([#5049])
- bugfix: adjust runtime storage migration ([#5047]) - bugfix: adjust runtime storage migration ([#5047])
- bugfix: supersede 'cb13be27f8f61d9ae74d924e85d2e6787895eb14' by using… ([#5046]) - bugfix: supersede 'cb13be27f8f61d9ae74d924e85d2e6787895eb14' by using… ([#5046])
- bugfix: restore default http port for nym-api ([#5045]) - bugfix: restore default http port for nym-api ([#5045])
@@ -736,7 +249,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- Fix broken build after merge ([#4937]) - Fix broken build after merge ([#4937])
- bugfix: correctly paginate through 'search_tx' endpoint ([#4936]) - bugfix: correctly paginate through 'search_tx' endpoint ([#4936])
- Add more conversions for responses of authenticator messages ([#4929]) - Add more conversions for responses of authenticator messages ([#4929])
- Directory Services, Devices v2.1 ([#4903]) - Directory Sevices v2.1 ([#4903])
- Migrate Legacy Node (Frontend) ([#4826]) - Migrate Legacy Node (Frontend) ([#4826])
- Fix critical issues SI84 and SI85 from Cure53 ([#4758]) - Fix critical issues SI84 and SI85 from Cure53 ([#4758])
@@ -1120,7 +633,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- Remove stale peers ([#4640]) - Remove stale peers ([#4640])
- Add generic wg private network routing ([#4636]) - Add generic wg private network routing ([#4636])
- Feature/new node endpoints ([#4635]) - Feature/new node endpoints ([#4635])
- standardised ContractBuildInformation and added it to all contracts ([#4631]) - standarised ContractBuildInformation and added it to all contracts ([#4631])
- validate nym-node public ips on startup ([#4630]) - validate nym-node public ips on startup ([#4630])
- Bump defguard wg ([#4625]) - Bump defguard wg ([#4625])
- Fix cargo warnings ([#4624]) - Fix cargo warnings ([#4624])
@@ -1741,7 +1254,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- clean-up nym-api startup arguments/flags to use clap 3 and its macro-derived arguments ([#2772]) - clean-up nym-api startup arguments/flags to use clap 3 and its macro-derived arguments ([#2772])
- renamed all references to validator_api to nym_api - renamed all references to validator_api to nym_api
- renamed all references to nymd to nyxd ([#2696]) - renamed all references to nymd to nyxd ([#2696])
- all-binaries: standardised argument names (note: old names should still be accepted) ([#2762] - all-binaries: standarised argument names (note: old names should still be accepted) ([#2762]
### Fixed ### Fixed
@@ -2246,7 +1759,7 @@ The release also include some additional work for distributed key generation in
- Explorer UI tests missing data-testid [\#903](https://github.com/nymtech/nym/pull/903) ([tommyv1987](https://github.com/tommyv1987)) - Explorer UI tests missing data-testid [\#903](https://github.com/nymtech/nym/pull/903) ([tommyv1987](https://github.com/tommyv1987))
- Fix up Nym-Wallet README.md [\#899](https://github.com/nymtech/nym/pull/899) ([tommyv1987](https://github.com/tommyv1987)) - Fix up Nym-Wallet README.md [\#899](https://github.com/nymtech/nym/pull/899) ([tommyv1987](https://github.com/tommyv1987))
- Feature/batch delegator rewarding [\#898](https://github.com/nymtech/nym/pull/898) ([jstuczyn](https://github.com/jstuczyn)) - Feature/batch delegator rewarding [\#898](https://github.com/nymtech/nym/pull/898) ([jstuczyn](https://github.com/jstuczyn))
- Bug map nodemap [\#897](https://github.com/nymtech/nym/pull/897) ([Aid19801](https://github.com/Aid19801)) - Bug mapp nodemap [\#897](https://github.com/nymtech/nym/pull/897) ([Aid19801](https://github.com/Aid19801))
- Bug fix/macos keyboard shortcuts [\#896](https://github.com/nymtech/nym/pull/896) ([fmtabbara](https://github.com/fmtabbara)) - Bug fix/macos keyboard shortcuts [\#896](https://github.com/nymtech/nym/pull/896) ([fmtabbara](https://github.com/fmtabbara))
- Add a Mobile Nav to the Network Explorer [\#895](https://github.com/nymtech/nym/pull/895) ([Aid19801](https://github.com/Aid19801)) - Add a Mobile Nav to the Network Explorer [\#895](https://github.com/nymtech/nym/pull/895) ([Aid19801](https://github.com/Aid19801))
- Only use ts-rs in tests [\#894](https://github.com/nymtech/nym/pull/894) ([durch](https://github.com/durch)) - Only use ts-rs in tests [\#894](https://github.com/nymtech/nym/pull/894) ([durch](https://github.com/durch))
Generated
+2077 -2557
View File
File diff suppressed because it is too large Load Diff
+117 -126
View File
@@ -32,8 +32,9 @@ members = [
"common/client-libs/validator-client", "common/client-libs/validator-client",
"common/commands", "common/commands",
"common/config", "common/config",
"common/cosmwasm-smart-contracts/coconut-bandwidth-contract",
"common/cosmwasm-smart-contracts/coconut-dkg", "common/cosmwasm-smart-contracts/coconut-dkg",
"common/cosmwasm-smart-contracts/contracts-common", "common/cosmwasm-smart-contracts/easy_addr", "common/cosmwasm-smart-contracts/contracts-common",
"common/cosmwasm-smart-contracts/ecash-contract", "common/cosmwasm-smart-contracts/ecash-contract",
"common/cosmwasm-smart-contracts/group-contract", "common/cosmwasm-smart-contracts/group-contract",
"common/cosmwasm-smart-contracts/mixnet-contract", "common/cosmwasm-smart-contracts/mixnet-contract",
@@ -47,12 +48,13 @@ members = [
"common/credentials-interface", "common/credentials-interface",
"common/crypto", "common/crypto",
"common/dkg", "common/dkg",
"common/ecash-double-spending",
"common/ecash-time", "common/ecash-time",
"common/execute", "common/execute",
"common/exit-policy", "common/exit-policy",
"common/gateway-requests", "common/gateway-requests",
"common/gateway-stats-storage",
"common/gateway-storage", "common/gateway-storage",
"common/gateway-stats-storage",
"common/http-api-client", "common/http-api-client",
"common/http-api-common", "common/http-api-common",
"common/inclusion-probability", "common/inclusion-probability",
@@ -65,6 +67,7 @@ members = [
"common/nym-id", "common/nym-id",
"common/nym-metrics", "common/nym-metrics",
"common/nym_offline_compact_ecash", "common/nym_offline_compact_ecash",
"common/nymcoconut",
"common/nymsphinx", "common/nymsphinx",
"common/nymsphinx/acknowledgements", "common/nymsphinx/acknowledgements",
"common/nymsphinx/addressing", "common/nymsphinx/addressing",
@@ -90,34 +93,17 @@ members = [
"common/topology", "common/topology",
"common/tun", "common/tun",
"common/types", "common/types",
"common/verloc",
"common/wasm/client-core", "common/wasm/client-core",
"common/wasm/storage", "common/wasm/storage",
"common/wasm/utils", "common/wasm/utils",
"common/wireguard", "common/wireguard",
"common/wireguard-types", "common/wireguard-types",
"documentation/autodoc", "documentation/autodoc",
# "explorer-api", "explorer-api",
# "explorer-api/explorer-api-requests", "explorer-api/explorer-api-requests",
# "explorer-api/explorer-client", "explorer-api/explorer-client",
"gateway", "gateway",
"integrations/bity", "integrations/bity",
"nym-api",
"nym-api/nym-api-requests",
"nym-browser-extension/storage",
"nym-credential-proxy/nym-credential-proxy",
"nym-credential-proxy/nym-credential-proxy-requests",
"nym-credential-proxy/vpn-api-lib-wasm",
"nym-network-monitor",
"nym-node",
"nym-node-status-api/nym-node-status-agent",
"nym-node-status-api/nym-node-status-api",
"nym-node-status-api/nym-node-status-client",
"nym-node/nym-node-metrics",
"nym-node/nym-node-requests",
"nym-outfox",
"nym-validator-rewarder",
"nyx-chain-watcher",
"sdk/ffi/cpp", "sdk/ffi/cpp",
"sdk/ffi/go", "sdk/ffi/go",
"sdk/ffi/shared", "sdk/ffi/shared",
@@ -126,17 +112,27 @@ members = [
"service-providers/common", "service-providers/common",
"service-providers/ip-packet-router", "service-providers/ip-packet-router",
"service-providers/network-requester", "service-providers/network-requester",
"tools/echo-server", "nym-api",
"tools/echo-server", "nym-api/nym-api-requests",
"tools/internal/contract-state-importer/importer-cli", "nym-browser-extension/storage",
"tools/internal/contract-state-importer/importer-contract", "nym-credential-proxy/nym-credential-proxy",
"tools/internal/mixnet-connectivity-check", "nym-credential-proxy/nym-credential-proxy-requests",
# "tools/internal/sdk-version-bump", "nym-credential-proxy/vpn-api-lib-wasm",
"nym-network-monitor",
"nyx-chain-watcher",
"nym-node",
"nym-node/nym-node-requests",
"nym-node/nym-node-metrics",
"nym-node-status-api/nym-node-status-agent",
"nym-node-status-api/nym-node-status-api",
"nym-node-status-api/nym-node-status-client",
"nym-outfox",
"nym-validator-rewarder",
# "tools/echo-server",
"tools/internal/ssl-inject", "tools/internal/ssl-inject",
"tools/internal/testnet-manager", # "tools/internal/sdk-version-bump",
"tools/internal/testnet-manager", "tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract", "tools/internal/testnet-manager/dkg-bypass-contract",
"tools/internal/testnet-manager/dkg-bypass-contract", "tools/internal/validator-status-check",
"tools/nym-cli", "tools/nym-cli",
"tools/nym-id-cli", "tools/nym-id-cli",
"tools/nym-nr-query", "tools/nym-nr-query",
@@ -147,11 +143,19 @@ members = [
"wasm/mix-fetch", "wasm/mix-fetch",
"wasm/node-tester", "wasm/node-tester",
"wasm/zknym-lib", "wasm/zknym-lib",
"tools/echo-server",
"tools/internal/contract-state-importer/importer-cli",
"tools/internal/contract-state-importer/importer-contract",
"tools/internal/testnet-manager",
"tools/internal/testnet-manager/dkg-bypass-contract",
"common/verloc",
"tools/internal/mixnet-connectivity-check", "tools/internal/mixnet-check-all-gateways",
] ]
default-members = [ default-members = [
"clients/native", "clients/native",
"clients/socks5", "clients/socks5",
"explorer-api",
"nym-api", "nym-api",
"nym-credential-proxy/nym-credential-proxy", "nym-credential-proxy/nym-credential-proxy",
"nym-node", "nym-node",
@@ -169,6 +173,7 @@ exclude = [
"explorer", "explorer",
"contracts", "contracts",
"nym-wallet", "nym-wallet",
"nym-vpn/ui/src-tauri",
"cpu-cycles", "cpu-cycles",
] ]
@@ -184,49 +189,45 @@ readme = "README.md"
[workspace.dependencies] [workspace.dependencies]
addr = "0.15.6" addr = "0.15.6"
aead = "0.5.2"
aes = "0.8.1" aes = "0.8.1"
aes-gcm = "0.10.1" aes-gcm = "0.10.1"
aes-gcm-siv = "0.11.1" aes-gcm-siv = "0.11.1"
ammonia = "4" aead = "0.5.2"
anyhow = "1.0.97" anyhow = "1.0.90"
arc-swap = "1.7.1"
argon2 = "0.5.0" argon2 = "0.5.0"
async-trait = "0.1.88" async-trait = "0.1.83"
axum = "0.7.5"
axum-client-ip = "0.6.1" axum-client-ip = "0.6.1"
axum = "0.7.5"
axum-extra = "0.9.4" axum-extra = "0.9.4"
axum-test = "16.2.0"
base64 = "0.22.1" base64 = "0.22.1"
base85rs = "0.1.3"
bincode = "1.3.3" bincode = "1.3.3"
bip39 = { version = "2.0.0", features = ["zeroize"] } bip39 = { version = "2.0.0", features = ["zeroize"] }
bit-vec = "0.7.0" # can we unify those? bit-vec = "0.7.0" # can we unify those?
bitvec = "1.0.0" bitvec = "1.0.0"
blake3 = "1.6.1" blake3 = "1.5.4"
bloomfilter = "1.0.14" bloomfilter = "1.0.14"
bs58 = "0.5.1" bs58 = "0.5.1"
bytecodec = "0.4.15" bytecodec = "0.4.15"
bytes = "1.10.1" bytes = "1.7.2"
cargo_metadata = "0.18.1" cargo_metadata = "0.18.1"
celes = "2.6.0" celes = "2.4.0"
cfg-if = "1.0.0" cfg-if = "1.0.0"
chacha20 = "0.9.0" chacha20 = "0.9.0"
chacha20poly1305 = "0.10.1" chacha20poly1305 = "0.10.1"
chrono = "0.4.40" chrono = "0.4.31"
cipher = "0.4.3" cipher = "0.4.3"
clap = "4.5.32" clap = "4.5.20"
clap_complete = "4.5" clap_complete = "4.5"
clap_complete_fig = "4.5" clap_complete_fig = "4.5"
colored = "2.2" colored = "2.0"
comfy-table = "7.1.4" comfy-table = "7.1.1"
console = "0.15.11" console = "0.15.8"
console-subscriber = "0.1.1" console-subscriber = "0.1.1"
console_error_panic_hook = "0.1" console_error_panic_hook = "0.1"
const-str = "0.5.6" const-str = "0.5.6"
const_format = "0.2.34" const_format = "0.2.33"
criterion = "0.5" criterion = "0.4"
csv = "1.3.1" csv = "1.3.0"
ctr = "0.9.1" ctr = "0.9.1"
cupid = "0.6.1" cupid = "0.6.1"
curve25519-dalek = "4.1" curve25519-dalek = "4.1"
@@ -239,60 +240,58 @@ doc-comment = "0.3"
dotenvy = "0.15.6" dotenvy = "0.15.6"
ecdsa = "0.16" ecdsa = "0.16"
ed25519-dalek = "2.1" ed25519-dalek = "2.1"
encoding_rs = "0.8.35"
env_logger = "0.11.7"
envy = "0.4"
etherparse = "0.13.0" etherparse = "0.13.0"
envy = "0.4"
eyre = "0.6.9" eyre = "0.6.9"
fastrand = "2.1.1" fastrand = "2.1.1"
flate2 = "1.1.0" flate2 = "1.0.34"
futures = "0.3.31" futures = "0.3.28"
futures-util = "0.3" futures-util = "0.3"
generic-array = "0.14.7" generic-array = "0.14.7"
getrandom = "0.2.10" getrandom = "0.2.10"
getset = "0.1.5" getset = "0.1.3"
handlebars = "3.5.5" handlebars = "3.5.5"
headers = "0.4.0" headers = "0.4.0"
hex = "0.4.3" hex = "0.4.3"
hex-literal = "0.3.3" hex-literal = "0.3.3"
hickory-resolver = "0.24.4"
hkdf = "0.12.3" hkdf = "0.12.3"
hmac = "0.12.1" hmac = "0.12.1"
http = "1" http = "1"
http-body-util = "0.1" http-body-util = "0.1"
httpcodec = "0.2.3" httpcodec = "0.2.3"
human-repr = "1.1.0" humantime = "2.1.0"
humantime = "2.2.0"
humantime-serde = "1.1.1" humantime-serde = "1.1.1"
hyper = "1.6.0" human-repr = "1.1.0"
hyper = "1.4.1"
hyper-util = "0.1" hyper-util = "0.1"
indicatif = "0.17.11" indicatif = "0.17.8"
inquire = "0.6.2" inquire = "0.6.2"
ip_network = "0.4.1" ip_network = "0.4.1"
ipnetwork = "0.20" ipnetwork = "0.20"
isocountry = "0.3.2" isocountry = "0.3.2"
itertools = "0.14.0" itertools = "0.13.0"
k256 = "0.13" k256 = "0.13"
lazy_static = "1.5.0" lazy_static = "1.5.0"
ledger-transport = "0.10.0" ledger-transport = "0.10.0"
ledger-transport-hid = "0.10.0" ledger-transport-hid = "0.10.0"
log = "0.4" log = "0.4"
maxminddb = "0.23.0" maxminddb = "0.23.0"
rs_merkle = "1.4.2"
mime = "0.3.17" mime = "0.3.17"
moka = { version = "0.12", features = ["future"] } moka = { version = "0.12", features = ["future"] }
nix = "0.27.1" nix = "0.27.1"
notify = "5.1.0" notify = "5.1.0"
okapi = "0.7.0" okapi = "0.7.0"
once_cell = "1.21.1" once_cell = "1.20.2"
opentelemetry = "0.19.0" opentelemetry = "0.19.0"
opentelemetry-jaeger = "0.18.0" opentelemetry-jaeger = "0.18.0"
parking_lot = "0.12.3" parking_lot = "0.12.3"
pem = "0.8" pem = "0.8"
petgraph = "0.6.5" petgraph = "0.6.5"
pin-project = "1.1" pin-project = "1.1"
pin-project-lite = "0.2.16" pin-project-lite = "0.2.14"
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
publicsuffix = "2.3.0" publicsuffix = "2.2.3"
quote = "1" quote = "1"
rand = "0.8.5" rand = "0.8.5"
rand_chacha = "0.3" rand_chacha = "0.3"
@@ -306,61 +305,57 @@ reqwest = { version = "0.12.4", default-features = false }
rocket = "0.5.0" rocket = "0.5.0"
rocket_cors = "0.6.0" rocket_cors = "0.6.0"
rocket_okapi = "0.8.0" rocket_okapi = "0.8.0"
rs_merkle = "1.5.0"
safer-ffi = "0.1.13" safer-ffi = "0.1.13"
schemars = "0.8.22" schemars = "0.8.21"
semver = "1.0.26" semver = "1.0.23"
serde = "1.0.219" serde = "1.0.211"
serde_bytes = "0.11.17" serde_bytes = "0.11.15"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0.140" serde_json = "1.0.132"
serde_json_path = "0.7.2" serde_json_path = "0.7.1"
serde_repr = "0.1" serde_repr = "0.1"
serde_with = "3.9.0" serde_with = "3.9.0"
serde_yaml = "0.9.25" serde_yaml = "0.9.25"
sha2 = "0.10.8" sha2 = "0.10.8"
si-scale = "0.2.3" si-scale = "0.2.3"
sphinx-packet = "=0.3.2" sphinx-packet = "0.1.1"
sqlx = "0.7.4" sqlx = "0.7.4"
strum = "0.26" strum = "0.26"
strum_macros = "0.26" strum_macros = "0.26"
subtle-encoding = "0.5" subtle-encoding = "0.5"
syn = "1" syn = "1"
sysinfo = "0.33.0" sysinfo = "0.30.13"
tap = "1.0.1" tap = "1.0.1"
tar = "0.4.44" tar = "0.4.42"
tempfile = "3.19" tempfile = "3.14"
thiserror = "2.0" thiserror = "1.0.64"
time = "0.3.39" time = "0.3.30"
tokio = "1.44" tokio = "1.39"
tokio-postgres = "0.7" tokio-stream = "0.1.16"
tokio-stream = "0.1.17"
tokio-test = "0.4.4" tokio-test = "0.4.4"
tokio-tun = "0.11.5" tokio-tun = "0.11.5"
tokio-tungstenite = { version = "0.20.1" } tokio-tungstenite = { version = "0.20.1" }
tokio-util = "0.7.14" tokio-util = "0.7.12"
toml = "0.8.20" toml = "0.8.14"
tower = "0.5.2" tower = "0.4.13"
tower-http = "0.5.2" tower-http = "0.5.2"
tracing = "0.1.41" tracing = "0.1.37"
tracing-log = "0.2"
tracing-opentelemetry = "0.19.0" tracing-opentelemetry = "0.19.0"
tracing-subscriber = "0.3.19" tracing-subscriber = "0.3.16"
tracing-tree = "0.2.2" tracing-tree = "0.2.2"
ts-rs = "10.1.0" tracing-log = "0.2"
ts-rs = "10.0.0"
tungstenite = { version = "0.20.1", default-features = false } tungstenite = { version = "0.20.1", default-features = false }
uniffi = "0.29.0"
uniffi_build = "0.29.0"
url = "2.5" url = "2.5"
utoipa = "5.2" utoipa = "5.2"
utoipa-swagger-ui = "8.1" utoipa-swagger-ui = "8.0"
utoipauto = "0.2" utoipauto = "0.2"
uuid = "*" uuid = "*"
vergen = { version = "=8.3.1", default-features = false } vergen = { version = "=8.3.1", default-features = false }
walkdir = "2" walkdir = "2"
wasm-bindgen-test = "0.3.49" wasm-bindgen-test = "0.3.43"
x25519-dalek = "2.0.0" x25519-dalek = "2.0.0"
zeroize = "1.7.0" zeroize = "1.6.0"
prometheus = { version = "0.13.0" } prometheus = { version = "0.13.0" }
@@ -368,46 +363,52 @@ prometheus = { version = "0.13.0" }
# unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork # unfortunately until https://github.com/zkcrypto/bls12_381/issues/10 is resolved, we have to rely on the fork
# as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm # as we need to be able to serialize Gt so that we could create the lookup table for baby-step-giant-step algorithm
# plus to make our live easier we need serde support from https://github.com/zkcrypto/bls12_381/pull/125 # plus to make our live easier we need serde support from https://github.com/zkcrypto/bls12_381/pull/125
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect-updated" } bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" }
group = { version = "0.13.0", default-features = false } group = { version = "0.13.0", default-features = false }
ff = { version = "0.13.1", default-features = false } ff = { version = "0.13.0", default-features = false }
subtle = "2.5.0" subtle = "2.5.0"
# cosmwasm-related # cosmwasm-related
cosmwasm-schema = "=2.2.2" cosmwasm-schema = "=1.4.3"
cosmwasm-std = "=2.2.2" cosmwasm-std = "=1.4.3"
# use 1.0.1 as that's the version used by cosmwasm-std 2.2.1 # use 0.5.0 as that's the version used by cosmwasm-std 1.4.3
# (and ideally we don't want to pull the same dependency twice) # (and ideally we don't want to pull the same dependency twice)
serde-json-wasm = "=1.0.1" serde-json-wasm = "=0.5.0"
cosmwasm-storage = "=1.4.3"
# same version as used by cosmwasm # same version as used by cosmwasm
cw-utils = "=2.0.0" cw-utils = "=1.0.1"
cw-storage-plus = "=2.0.0" cw-storage-plus = "=1.2.0"
cw2 = { version = "=2.0.0" } cw2 = { version = "=1.1.2" }
cw3 = { version = "=2.0.0" } cw3 = { version = "=1.1.2" }
cw4 = { version = "=2.0.0" } cw4 = { version = "=1.1.2" }
cw-controllers = { version = "=2.0.0" } cw-controllers = { version = "=1.1.0" }
# cosmrs-related # cosmrs-related
bip32 = { version = "0.5.3", default-features = false } bip32 = { version = "0.5.2", default-features = false }
# temporarily using a fork again (yay.) because we need staking and slashing support (which are already on main but not released)
cosmrs = { version = "0.21.1" } # plus response message parsing (which is, as of the time of writing this message, waiting to get merged)
tendermint = "0.40.0" #cosmrs = { path = "../cosmos-rust-fork/cosmos-rust/cosmrs" }
tendermint-rpc = "0.40.0" cosmrs = { git = "https://github.com/cosmos/cosmos-rust", rev = "4b1332e6d8258ac845cef71589c8d362a669675a" } # unfortuntely we need a fork by yours truly to get the staking support
prost = { version = "0.13", default-features = false } tendermint = "0.37.0" # same version as used by cosmrs
tendermint-rpc = "0.37.0" # same version as used by cosmrs
prost = { version = "0.12", default-features = false }
# wasm-related dependencies # wasm-related dependencies
gloo-utils = "0.2.0" gloo-utils = "0.2.0"
gloo-net = "0.6.0" gloo-net = "0.5.0"
indexed_db_futures = "0.6.1" # use a separate branch due to feature unification failures
js-sys = "0.3.76" # this is blocked until the upstream removes outdates `wasm_bindgen` feature usage
# indexed_db_futures = "0.4.1"
indexed_db_futures = { git = "https://github.com/TiemenSch/rust-indexed-db", branch = "update-uuid" }
js-sys = "0.3.70"
serde-wasm-bindgen = "0.6.5" serde-wasm-bindgen = "0.6.5"
tsify = "0.4.5" tsify = "0.4.5"
wasm-bindgen = "0.2.99" wasm-bindgen = "0.2.99"
wasm-bindgen-futures = "0.4.49" wasm-bindgen-futures = "0.4.45"
wasmtimer = "0.4.1" wasmtimer = "0.2.0"
web-sys = "0.3.76" web-sys = "0.3.72"
# Profile settings for individual crates # Profile settings for individual crates
@@ -435,13 +436,3 @@ opt-level = 'z'
[profile.release.package.mix-fetch-wasm] [profile.release.package.mix-fetch-wasm]
# lto = true # lto = true
opt-level = 'z' opt-level = 'z'
[workspace.lints.clippy]
unwrap_used = "deny"
expect_used = "deny"
todo = "deny"
dbg_macro = "deny"
exit = "deny"
panic = "deny"
unimplemented = "deny"
unreachable = "deny"
+18 -8
View File
@@ -133,22 +133,17 @@ clippy: sdk-wasm-lint
# Build contracts ready for deploy # Build contracts ready for deploy
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
CONTRACTS=vesting_contract mixnet_contract nym_ecash cw3_flex_multisig cw4_group nym_coconut_dkg CONTRACTS=vesting_contract mixnet_contract nym_ecash
CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS)) CONTRACTS_WASM=$(addsuffix .wasm, $(CONTRACTS))
CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release CONTRACTS_OUT_DIR=contracts/target/wasm32-unknown-unknown/release
contracts: build-release-contracts wasm-opt-contracts cosmwasm-check-contracts contracts: build-release-contracts wasm-opt-contracts
wasm-opt-contracts: wasm-opt-contracts:
for contract in $(CONTRACTS_WASM); do \ for contract in $(CONTRACTS_WASM); do \
wasm-opt --signext-lowering -Os $(CONTRACTS_OUT_DIR)/$$contract -o $(CONTRACTS_OUT_DIR)/$$contract; \ wasm-opt --signext-lowering -Os $(CONTRACTS_OUT_DIR)/$$contract -o $(CONTRACTS_OUT_DIR)/$$contract; \
done done
cosmwasm-check-contracts:
for contract in $(CONTRACTS_WASM); do \
cosmwasm-check $(CONTRACTS_OUT_DIR)/$$contract; \
done
# Consider adding 's' to make plural consistent (beware: used in github workflow) # Consider adding 's' to make plural consistent (beware: used in github workflow)
contract-schema: contract-schema:
$(MAKE) -C contracts schema $(MAKE) -C contracts schema
@@ -157,9 +152,18 @@ contract-schema:
# Convenience targets for crates that are already part of the main workspace # Convenience targets for crates that are already part of the main workspace
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
build-explorer-api:
cargo build -p explorer-api
build-nym-cli: build-nym-cli:
cargo build -p nym-cli --release cargo build -p nym-cli --release
build-nym-gateway:
cargo build -p nym-gateway --release
build-nym-mixnode:
cargo build -p nym-mixnode --release
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Misc # Misc
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -172,7 +176,13 @@ run-api-tests:
cd nym-api/tests/functional_test && yarn test:qa cd nym-api/tests/functional_test && yarn test:qa
# Build debian package, and update PPA # Build debian package, and update PPA
deb-mixnode: build-nym-mixnode
cargo deb -p nym-mixnode
deb-gateway: build-nym-gateway
cargo deb -p nym-gateway
deb-cli: build-nym-cli deb-cli: build-nym-cli
cargo deb -p nym-cli cargo deb -p nym-cli
deb: deb-cli deb: deb-mixnode deb-gateway deb-cli
+7 -17
View File
@@ -13,8 +13,8 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
* `nym-client` - an executable which you can build into your own applications. Use it for interacting with Nym nodes. * `nym-client` - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
* `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-explorer` - a (projected) block explorer and (existing) mixnet viewer. * `nym-explorer` - a (projected) block explorer and (existing) mixnet viewer.
* `nym-wallet` - a desktop wallet implemented using the [Tauri](https://tauri.app)) framework. * `nym-wallet` - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
* `nym-cli` - a tool for interacting with the network from the CLI. * `nym-cli` - a tool for interacting with the network from the CLI.
<!-- coming soon <!-- coming soon
* `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").
--> -->
@@ -42,10 +42,10 @@ client ───► Gateway ──┘ mix │ mix ┌─►mix ───►
References for developers: References for developers:
* [Dev Docs](https://nym.com/docs/developers) * [Dev Docs](https://nymtech.net/docs/developers)
* [SDKs](https://nym.com/docs/developers/rust) * [SDKs](https://nymtech.net/docs/developers/rust)
* [Network Docs](https://nym.com/docs/network) * [Network Docs](https://nymtech.net/docs/network)
* [Release Cycle - git flow](https://nym.com/docs/operators/release-cycle) * [Release Cycle - git flow](https://nymtech.net/docs/operators/release-cycle)
### Developer chat ### Developer chat
@@ -66,14 +66,4 @@ As a general approach, licensing is as follows this pattern:
- libraries and components are Apache 2.0 or MIT - libraries and components are Apache 2.0 or MIT
- documentation is Apache 2.0 or CC0-1.0 - documentation is Apache 2.0 or CC0-1.0
Nym Node Operators and Validators Terms and Conditions can be found [here](https://nym.com/operators-validators-terms). Nym Node Operators and Validators Temrs and Conditions can be found [here](https://nymtech.net/terms-and-conditions/operators/v1.0.0).
## Getting Started
```bash
yarn install
```
```bash
yarn build
```
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-client" name = "nym-client"
version = "1.1.52" version = "1.1.45"
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>"]
description = "Implementation of the Nym Client" description = "Implementation of the Nym Client"
edition = "2021" edition = "2021"
+2 -6
View File
@@ -56,7 +56,7 @@ pub fn default_data_directory<P: AsRef<Path>>(id: P) -> PathBuf {
.join(DEFAULT_DATA_DIR) .join(DEFAULT_DATA_DIR)
} }
#[derive(Debug, Deserialize, PartialEq, Serialize, Clone)] #[derive(Debug, Deserialize, PartialEq, Serialize)]
pub struct Config { pub struct Config {
#[serde(flatten)] #[serde(flatten)]
pub base: BaseClientConfig, pub base: BaseClientConfig,
@@ -94,10 +94,6 @@ impl CliClientConfig for Config {
} }
impl Config { impl Config {
pub fn base(&self) -> BaseClientConfig {
self.base.clone()
}
pub fn new<S: AsRef<str>>(id: S) -> Self { pub fn new<S: AsRef<str>>(id: S) -> Self {
Config { Config {
base: BaseClientConfig::new(id.as_ref(), env!("CARGO_PKG_VERSION")), base: BaseClientConfig::new(id.as_ref(), env!("CARGO_PKG_VERSION")),
@@ -213,7 +209,7 @@ impl SocketType {
} }
} }
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] #[derive(Debug, Deserialize, PartialEq, Eq, Serialize)]
#[serde(default, deny_unknown_fields)] #[serde(default, deny_unknown_fields)]
pub struct Socket { pub struct Socket {
pub socket_type: SocketType, pub socket_type: SocketType,
@@ -107,8 +107,5 @@ enabled = {{ debug.stats_reporting.enabled }}
provider_address = '{{ debug.stats_reporting.provider_address }}' provider_address = '{{ debug.stats_reporting.provider_address }}'
reporting_interval = '{{ debug.stats_reporting.reporting_interval }}' reporting_interval = '{{ debug.stats_reporting.reporting_interval }}'
[debug.forget_me]
client = {{ debug.forget_me.client }}
stats = {{ debug.forget_me.stats }}
"#; "#;
+6 -16
View File
@@ -20,7 +20,7 @@ pub use nym_sphinx::addressing::clients::Recipient;
pub mod config; pub mod config;
type NativeClientBuilder = BaseClientBuilder<QueryHttpRpcNyxdClient, OnDiskPersistent>; type NativeClientBuilder<'a> = BaseClientBuilder<'a, QueryHttpRpcNyxdClient, OnDiskPersistent>;
pub struct SocketClient { pub struct SocketClient {
/// Client configuration options, including, among other things, packet sending rates, /// Client configuration options, including, among other things, packet sending rates,
@@ -32,10 +32,6 @@ pub struct SocketClient {
} }
impl SocketClient { impl SocketClient {
pub fn config(&self) -> Config {
self.config.clone()
}
pub fn new(config: Config, custom_mixnet: Option<PathBuf>) -> Self { pub fn new(config: Config, custom_mixnet: Option<PathBuf>) -> Self {
SocketClient { SocketClient {
config, config,
@@ -49,7 +45,7 @@ impl SocketClient {
client_output: ClientOutput, client_output: ClientOutput,
client_state: ClientState, client_state: ClientState,
self_address: &Recipient, self_address: &Recipient,
task_client: nym_task::TaskClient, shutdown: nym_task::TaskClient,
packet_type: PacketType, packet_type: PacketType,
) { ) {
info!("Starting websocket listener..."); info!("Starting websocket listener...");
@@ -77,15 +73,10 @@ impl SocketClient {
shared_lane_queue_lengths, shared_lane_queue_lengths,
reply_controller_sender, reply_controller_sender,
Some(packet_type), Some(packet_type),
task_client.fork("websocket_handler"),
); );
websocket::Listener::new( websocket::Listener::new(config.socket.host, config.socket.listening_port)
config.socket.host, .start(websocket_handler, shutdown);
config.socket.listening_port,
task_client.with_suffix("websocket_listener"),
)
.start(websocket_handler);
} }
/// blocking version of `start_socket` method. Will run forever (or until SIGINT is sent) /// blocking version of `start_socket` method. Will run forever (or until SIGINT is sent)
@@ -117,9 +108,8 @@ impl SocketClient {
let storage = self.initialise_storage().await?; let storage = self.initialise_storage().await?;
let user_agent = nym_bin_common::bin_info!().into(); let user_agent = nym_bin_common::bin_info!().into();
let mut base_client = let mut base_client = BaseClientBuilder::new(&self.config.base, storage, dkg_query_client)
BaseClientBuilder::new(self.config().base(), storage, dkg_query_client) .with_user_agent(user_agent);
.with_user_agent(user_agent);
if let Some(custom_mixnet) = &self.custom_mixnet { if let Some(custom_mixnet) = &self.custom_mixnet {
base_client = base_client.with_stored_topology(custom_mixnet)?; base_client = base_client.with_stored_topology(custom_mixnet)?;
-1
View File
@@ -82,7 +82,6 @@ impl From<Init> for OverrideConfig {
nyxd_urls: init_config.common_args.nyxd_urls, nyxd_urls: init_config.common_args.nyxd_urls,
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode, enabled_credentials_mode: init_config.common_args.enabled_credentials_mode,
stats_reporting_address: init_config.common_args.stats_reporting_address, stats_reporting_address: init_config.common_args.stats_reporting_address,
forget_me: init_config.common_args.forget_me.into(),
} }
} }
} }
-3
View File
@@ -16,7 +16,6 @@ use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client::client::Recipient; use nym_client::client::Recipient;
use nym_client_core::cli_helpers::CliClient; use nym_client_core::cli_helpers::CliClient;
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use nym_client_core::config::ForgetMe;
use nym_config::OptionalSet; use nym_config::OptionalSet;
use std::error::Error; use std::error::Error;
use std::net::IpAddr; use std::net::IpAddr;
@@ -107,7 +106,6 @@ pub(crate) struct OverrideConfig {
nyxd_urls: Option<Vec<url::Url>>, nyxd_urls: Option<Vec<url::Url>>,
enabled_credentials_mode: Option<bool>, enabled_credentials_mode: Option<bool>,
stats_reporting_address: Option<Recipient>, stats_reporting_address: Option<Recipient>,
forget_me: ForgetMe,
} }
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
@@ -135,7 +133,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
args.fastmode, args.fastmode,
) )
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover) .with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
.with_base(BaseClientConfig::with_forget_me, args.forget_me)
.with_optional(Config::with_port, args.port) .with_optional(Config::with_port, args.port)
.with_optional(Config::with_host, args.host) .with_optional(Config::with_host, args.host)
.with_optional_custom_env_ext( .with_optional_custom_env_ext(
-1
View File
@@ -41,7 +41,6 @@ impl From<Run> for OverrideConfig {
nyxd_urls: run_config.common_args.nyxd_urls, nyxd_urls: run_config.common_args.nyxd_urls,
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode, enabled_credentials_mode: run_config.common_args.enabled_credentials_mode,
stats_reporting_address: run_config.common_args.stats_reporting_address, stats_reporting_address: run_config.common_args.stats_reporting_address,
forget_me: run_config.common_args.forget_me.into(),
} }
} }
} }
+40 -66
View File
@@ -19,7 +19,6 @@ use nym_sphinx::receiver::ReconstructedMessage;
use nym_task::connections::{ use nym_task::connections::{
ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane, ConnectionCommand, ConnectionCommandSender, ConnectionId, LaneQueueLengths, TransmissionLane,
}; };
use nym_task::TaskClient;
use std::time::Duration; use std::time::Duration;
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio::time::Instant; use tokio::time::Instant;
@@ -44,11 +43,9 @@ pub(crate) struct HandlerBuilder {
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
packet_type: Option<PacketType>, packet_type: Option<PacketType>,
task_client: TaskClient,
} }
impl HandlerBuilder { impl HandlerBuilder {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new( pub(crate) fn new(
msg_input: InputMessageSender, msg_input: InputMessageSender,
client_connection_tx: ConnectionCommandSender, client_connection_tx: ConnectionCommandSender,
@@ -57,7 +54,6 @@ impl HandlerBuilder {
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
packet_type: Option<PacketType>, packet_type: Option<PacketType>,
task_client: TaskClient,
) -> Self { ) -> Self {
Self { Self {
msg_input, msg_input,
@@ -67,14 +63,11 @@ impl HandlerBuilder {
lane_queue_lengths, lane_queue_lengths,
reply_controller_sender, reply_controller_sender,
packet_type, packet_type,
task_client,
} }
} }
// TODO: make sure we only ever have one active handler // TODO: make sure we only ever have one active handler
pub fn create_active_handler(&self) -> Handler { pub fn create_active_handler(&self) -> Handler {
let mut task_client = self.task_client.fork("active_handler");
task_client.disarm();
Handler { Handler {
msg_input: self.msg_input.clone(), msg_input: self.msg_input.clone(),
client_connection_tx: self.client_connection_tx.clone(), client_connection_tx: self.client_connection_tx.clone(),
@@ -85,7 +78,6 @@ impl HandlerBuilder {
lane_queue_lengths: self.lane_queue_lengths.clone(), lane_queue_lengths: self.lane_queue_lengths.clone(),
reply_controller_sender: self.reply_controller_sender.clone(), reply_controller_sender: self.reply_controller_sender.clone(),
packet_type: self.packet_type, packet_type: self.packet_type,
task_client,
} }
} }
} }
@@ -100,18 +92,16 @@ pub(crate) struct Handler {
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
packet_type: Option<PacketType>, packet_type: Option<PacketType>,
task_client: TaskClient,
} }
impl Drop for Handler { impl Drop for Handler {
fn drop(&mut self) { fn drop(&mut self) {
if let Err(err) = self if self
.buffer_requester .buffer_requester
.unbounded_send(ReceivedBufferMessage::ReceiverDisconnect) .unbounded_send(ReceivedBufferMessage::ReceiverDisconnect)
.is_err()
{ {
if !self.task_client.is_shutdown_poll() { error!("we failed to disconnect the receiver from the buffer! presumably the shutdown procedure has been initiated!")
error!("failed to disconnect the receiver from the buffer: {err}");
}
} }
} }
} }
@@ -135,23 +125,10 @@ impl Handler {
}; };
// get the number of pending replies waiting for reply surbs // get the number of pending replies waiting for reply surbs
let reply_queue_length = match self let reply_queue_length = self
.reply_controller_sender .reply_controller_sender
.get_lane_queue_length(connection_id) .get_lane_queue_length(connection_id)
.await .await;
{
Ok(length) => length,
Err(err) => {
if !self.task_client.is_shutdown_poll() {
error!(
"Failed to get reply queue length for connection {connection_id}: {err}"
);
}
// We're just going to assume that the queue is empty, and I think that's okay
// during shutdown.
0
}
};
let queue_length = base_length + reply_queue_length; let queue_length = base_length + reply_queue_length;
@@ -191,11 +168,10 @@ impl Handler {
// the ack control is now responsible for chunking, etc. // the ack control is now responsible for chunking, etc.
let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type); let input_msg = InputMessage::new_regular(recipient, message, lane, self.packet_type);
if let Err(err) = self.msg_input.send(input_msg).await { self.msg_input
if !self.task_client.is_shutdown_poll() { .send(input_msg)
error!("Failed to send message to the input buffer: {err}"); .await
} .expect("InputMessageReceiver has stopped receiving!");
}
// Only reply back with a `LaneQueueLength` if the sender providided a connection id // Only reply back with a `LaneQueueLength` if the sender providided a connection id
let TransmissionLane::ConnectionId(connection_id) = lane else { let TransmissionLane::ConnectionId(connection_id) = lane else {
@@ -224,11 +200,10 @@ impl Handler {
let input_msg = let input_msg =
InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type); InputMessage::new_anonymous(recipient, message, reply_surbs, lane, self.packet_type);
if let Err(err) = self.msg_input.send(input_msg).await { self.msg_input
if !self.task_client.is_shutdown_poll() { .send(input_msg)
error!("Failed to send anonymous message to the input buffer: {err}"); .await
} .expect("InputMessageReceiver has stopped receiving!");
}
// Only reply back with a `LaneQueueLength` if the sender providided a connection id // Only reply back with a `LaneQueueLength` if the sender providided a connection id
let TransmissionLane::ConnectionId(connection_id) = lane else { let TransmissionLane::ConnectionId(connection_id) = lane else {
@@ -252,11 +227,10 @@ impl Handler {
}); });
let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type); let input_msg = InputMessage::new_reply(recipient_tag, message, lane, self.packet_type);
if let Err(err) = self.msg_input.send(input_msg).await { self.msg_input
if !self.task_client.is_shutdown_poll() { .send(input_msg)
error!("Failed to send reply message to the input buffer: {err}"); .await
} .expect("InputMessageReceiver has stopped receiving!");
}
// Only reply back with a `LaneQueueLength` if the sender providided a connection id // Only reply back with a `LaneQueueLength` if the sender providided a connection id
let TransmissionLane::ConnectionId(connection_id) = lane else { let TransmissionLane::ConnectionId(connection_id) = lane else {
@@ -271,14 +245,9 @@ impl Handler {
} }
fn handle_closed_connection(&self, connection_id: u64) -> Option<ServerResponse> { fn handle_closed_connection(&self, connection_id: u64) -> Option<ServerResponse> {
if let Err(err) = self self.client_connection_tx
.client_connection_tx
.unbounded_send(ConnectionCommand::Close(connection_id)) .unbounded_send(ConnectionCommand::Close(connection_id))
{ .unwrap();
if !self.task_client.is_shutdown_poll() {
error!("Failed to send close connection command: {err}");
}
}
None None
} }
@@ -393,10 +362,11 @@ impl Handler {
} }
} }
async fn listen_for_requests(&mut self, mut msg_receiver: ReconstructedMessagesReceiver) { async fn listen_for_requests(
let mut task_client = self.task_client.fork("select"); &mut self,
task_client.disarm(); mut msg_receiver: ReconstructedMessagesReceiver,
mut task_client: nym_task::TaskClient,
) {
while !task_client.is_shutdown() { while !task_client.is_shutdown() {
tokio::select! { tokio::select! {
// we can either get a client request from the websocket // we can either get a client request from the websocket
@@ -445,7 +415,15 @@ impl Handler {
} }
// consume self to make sure `drop` is called after this is done // consume self to make sure `drop` is called after this is done
pub(crate) async fn handle_connection(mut self, socket: TcpStream) { pub(crate) async fn handle_connection(
mut self,
socket: TcpStream,
mut task_client: nym_task::TaskClient,
) {
// We don't want a crash in the connection handler to trigger a shutdown of the whole
// process.
task_client.disarm();
let ws_stream = match accept_async(socket).await { let ws_stream = match accept_async(socket).await {
Ok(ws_stream) => ws_stream, Ok(ws_stream) => ws_stream,
Err(err) => { Err(err) => {
@@ -458,18 +436,14 @@ impl Handler {
let (reconstructed_sender, reconstructed_receiver) = mpsc::unbounded(); let (reconstructed_sender, reconstructed_receiver) = mpsc::unbounded();
// tell the buffer to start sending stuff to us // tell the buffer to start sending stuff to us
if let Err(err) = self.buffer_requester
self.buffer_requester .unbounded_send(ReceivedBufferMessage::ReceiverAnnounce(
.unbounded_send(ReceivedBufferMessage::ReceiverAnnounce( reconstructed_sender,
reconstructed_sender, ))
)) .expect("the buffer request failed!");
{
if !self.task_client.is_shutdown_poll() {
error!("failed to announce the receiver to the buffer: {err}");
}
}
self.listen_for_requests(reconstructed_receiver).await; self.listen_for_requests(reconstructed_receiver, task_client)
.await;
} }
} }
+17 -11
View File
@@ -3,7 +3,6 @@
use super::handler::HandlerBuilder; use super::handler::HandlerBuilder;
use log::*; use log::*;
use nym_task::TaskClient;
use std::net::IpAddr; use std::net::IpAddr;
use std::{net::SocketAddr, process, sync::Arc}; use std::{net::SocketAddr, process, sync::Arc};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
@@ -23,19 +22,21 @@ impl State {
pub(crate) struct Listener { pub(crate) struct Listener {
address: SocketAddr, address: SocketAddr,
state: State, state: State,
task_client: TaskClient,
} }
impl Listener { impl Listener {
pub(crate) fn new(host: IpAddr, port: u16, task_client: TaskClient) -> Self { pub(crate) fn new(host: IpAddr, port: u16) -> Self {
Listener { Listener {
address: SocketAddr::new(host, port), address: SocketAddr::new(host, port),
state: State::AwaitingConnection, state: State::AwaitingConnection,
task_client,
} }
} }
pub(crate) async fn run(&mut self, handler: HandlerBuilder) { pub(crate) async fn run(
&mut self,
handler: HandlerBuilder,
mut task_client: nym_task::TaskClient,
) {
let tcp_listener = match tokio::net::TcpListener::bind(self.address).await { let tcp_listener = match tokio::net::TcpListener::bind(self.address).await {
Ok(listener) => listener, Ok(listener) => listener,
Err(err) => { Err(err) => {
@@ -46,11 +47,11 @@ impl Listener {
let notify = Arc::new(Notify::new()); let notify = Arc::new(Notify::new());
while !self.task_client.is_shutdown() { loop {
tokio::select! { tokio::select! {
// When the handler finishes we check if shutdown is signalled // When the handler finishes we check if shutdown is signalled
_ = notify.notified() => { _ = notify.notified() => {
if self.task_client.is_shutdown() { if task_client.is_shutdown() {
log::trace!("Websocket listener: detected shutdown after connection closed"); log::trace!("Websocket listener: detected shutdown after connection closed");
break; break;
} }
@@ -59,7 +60,7 @@ impl Listener {
} }
// ... but when there is no connected client at the time of shutdown being // ... but when there is no connected client at the time of shutdown being
// signalled, we handle it here. // signalled, we handle it here.
_ = self.task_client.recv() => { _ = task_client.recv() => {
if !self.state.is_connected() { if !self.state.is_connected() {
log::trace!("Not connected: shutting down"); log::trace!("Not connected: shutting down");
break; break;
@@ -87,8 +88,9 @@ impl Listener {
// hanging because the executor doesn't come back here // hanging because the executor doesn't come back here
let notify_clone = Arc::clone(&notify); let notify_clone = Arc::clone(&notify);
let fresh_handler = handler.create_active_handler(); let fresh_handler = handler.create_active_handler();
let task_client_handler = task_client.clone();
tokio::spawn(async move { tokio::spawn(async move {
fresh_handler.handle_connection(socket).await; fresh_handler.handle_connection(socket, task_client_handler).await;
notify_clone.notify_one(); notify_clone.notify_one();
}); });
self.state = State::Connected; self.state = State::Connected;
@@ -102,9 +104,13 @@ impl Listener {
log::debug!("Websocket listener: Exiting"); log::debug!("Websocket listener: Exiting");
} }
pub(crate) fn start(mut self, handler: HandlerBuilder) -> JoinHandle<()> { pub(crate) fn start(
mut self,
handler: HandlerBuilder,
shutdown: nym_task::TaskClient,
) -> JoinHandle<()> {
info!("Running websocket on {:?}", self.address.to_string()); info!("Running websocket on {:?}", self.address.to_string());
tokio::spawn(async move { self.run(handler).await }) tokio::spawn(async move { self.run(handler, shutdown).await })
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "nym-socks5-client" name = "nym-socks5-client"
version = "1.1.52" version = "1.1.45"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"] authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address" description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021" edition = "2021"
-1
View File
@@ -93,7 +93,6 @@ impl From<Init> for OverrideConfig {
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode, enabled_credentials_mode: init_config.common_args.enabled_credentials_mode,
outfox: false, outfox: false,
stats_reporting_address: init_config.common_args.stats_reporting_address, stats_reporting_address: init_config.common_args.stats_reporting_address,
forget_me: init_config.common_args.forget_me.into(),
} }
} }
} }
+1 -3
View File
@@ -17,7 +17,7 @@ use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::cli_helpers::CliClient; use nym_client_core::cli_helpers::CliClient;
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
use nym_client_core::config::{ForgetMe, GroupBy, TopologyStructure}; use nym_client_core::config::{GroupBy, TopologyStructure};
use nym_config::OptionalSet; use nym_config::OptionalSet;
use nym_sphinx::addressing::Recipient; use nym_sphinx::addressing::Recipient;
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::{PacketSize, PacketType};
@@ -113,7 +113,6 @@ pub(crate) struct OverrideConfig {
enabled_credentials_mode: Option<bool>, enabled_credentials_mode: Option<bool>,
outfox: bool, outfox: bool,
stats_reporting_address: Option<Recipient>, stats_reporting_address: Option<Recipient>,
forget_me: ForgetMe,
} }
pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> { pub(crate) async fn execute(args: Cli) -> Result<(), Box<dyn Error + Send + Sync>> {
@@ -180,7 +179,6 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
BaseClientConfig::with_topology_structure, BaseClientConfig::with_topology_structure,
topology_structure, topology_structure,
) )
.with_base(BaseClientConfig::with_forget_me, args.forget_me)
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies) .with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
.with_optional(Config::with_port, args.port) .with_optional(Config::with_port, args.port)
.with_optional(Config::with_ip, args.ip) .with_optional(Config::with_ip, args.ip)
-1
View File
@@ -65,7 +65,6 @@ impl From<Run> for OverrideConfig {
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode, enabled_credentials_mode: run_config.common_args.enabled_credentials_mode,
outfox: run_config.outfox, outfox: run_config.outfox,
stats_reporting_address: run_config.common_args.stats_reporting_address, stats_reporting_address: run_config.common_args.stats_reporting_address,
forget_me: run_config.common_args.forget_me.into(),
} }
} }
} }
-4
View File
@@ -113,8 +113,4 @@ enabled = {{ core.debug.stats_reporting.enabled }}
provider_address = '{{ core.debug.stats_reporting.provider_address }}' provider_address = '{{ core.debug.stats_reporting.provider_address }}'
reporting_interval = '{{ core.debug.stats_reporting.reporting_interval }}' reporting_interval = '{{ core.debug.stats_reporting.reporting_interval }}'
[core.debug.forget_me]
client = {{ core.debug.forget_me.client }}
stats = {{ core.debug.forget_me.stats }}
"#; "#;
-1
View File
@@ -1,3 +1,2 @@
allow-unwrap-in-tests = true allow-unwrap-in-tests = true
allow-expect-in-tests = true allow-expect-in-tests = true
allow-panic-in-tests = true
+2 -3
View File
@@ -6,15 +6,14 @@ pub mod v1;
pub mod v2; pub mod v2;
pub mod v3; pub mod v3;
pub mod v4; pub mod v4;
pub mod v5;
mod error; mod error;
mod util; mod util;
pub use error::Error; pub use error::Error;
pub use v5 as latest; pub use v4 as latest;
pub const CURRENT_VERSION: u8 = 5; pub const CURRENT_VERSION: u8 = 4;
fn make_bincode_serializer() -> impl bincode::Options { fn make_bincode_serializer() -> impl bincode::Options {
use bincode::Options; use bincode::Options;
+20 -92
View File
@@ -8,8 +8,8 @@ use nym_sphinx::addressing::clients::Recipient;
use nym_wireguard_types::PeerPublicKey; use nym_wireguard_types::PeerPublicKey;
use crate::{ use crate::{
v1, v2, v3, v4, v1, v2, v3,
v5::{self, registration::IpPair}, v4::{self, registration::IpPair},
Error, Error,
}; };
@@ -19,7 +19,6 @@ pub enum AuthenticatorVersion {
V2, V2,
V3, V3,
V4, V4,
V5,
UNKNOWN, UNKNOWN,
} }
@@ -35,8 +34,6 @@ impl From<Protocol> for AuthenticatorVersion {
AuthenticatorVersion::V3 AuthenticatorVersion::V3
} else if value.version == v4::VERSION { } else if value.version == v4::VERSION {
AuthenticatorVersion::V4 AuthenticatorVersion::V4
} else if value.version == v5::VERSION {
AuthenticatorVersion::V5
} else { } else {
AuthenticatorVersion::UNKNOWN AuthenticatorVersion::UNKNOWN
} }
@@ -71,12 +68,6 @@ impl InitMessage for v4::registration::InitMessage {
} }
} }
impl InitMessage for v5::registration::InitMessage {
fn pub_key(&self) -> PeerPublicKey {
self.pub_key
}
}
pub trait FinalMessage { pub trait FinalMessage {
fn pub_key(&self) -> PeerPublicKey; fn pub_key(&self) -> PeerPublicKey;
fn verify(&self, private_key: &PrivateKey, nonce: u64) -> Result<(), Error>; fn verify(&self, private_key: &PrivateKey, nonce: u64) -> Result<(), Error>;
@@ -147,24 +138,6 @@ impl FinalMessage for v4::registration::FinalMessage {
self.gateway_client.verify(private_key, nonce) self.gateway_client.verify(private_key, nonce)
} }
fn private_ips(&self) -> IpPair {
self.gateway_client.private_ips.into()
}
fn credential(&self) -> Option<CredentialSpendingData> {
self.credential.clone()
}
}
impl FinalMessage for v5::registration::FinalMessage {
fn pub_key(&self) -> PeerPublicKey {
self.gateway_client.pub_key
}
fn verify(&self, private_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
self.gateway_client.verify(private_key, nonce)
}
fn private_ips(&self) -> IpPair { fn private_ips(&self) -> IpPair {
self.gateway_client.private_ips self.gateway_client.private_ips
} }
@@ -209,39 +182,29 @@ impl TopUpMessage for v4::topup::TopUpMessage {
} }
} }
impl TopUpMessage for v5::topup::TopUpMessage {
fn pub_key(&self) -> PeerPublicKey {
self.pub_key
}
fn credential(&self) -> CredentialSpendingData {
self.credential.clone()
}
}
pub enum AuthenticatorRequest { pub enum AuthenticatorRequest {
Initial { Initial {
msg: Box<dyn InitMessage + Send + Sync + 'static>, msg: Box<dyn InitMessage + Send + Sync + 'static>,
protocol: Protocol, protocol: Protocol,
reply_to: Option<Recipient>, reply_to: Recipient,
request_id: u64, request_id: u64,
}, },
Final { Final {
msg: Box<dyn FinalMessage + Send + Sync + 'static>, msg: Box<dyn FinalMessage + Send + Sync + 'static>,
protocol: Protocol, protocol: Protocol,
reply_to: Option<Recipient>, reply_to: Recipient,
request_id: u64, request_id: u64,
}, },
QueryBandwidth { QueryBandwidth {
msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>, msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>,
protocol: Protocol, protocol: Protocol,
reply_to: Option<Recipient>, reply_to: Recipient,
request_id: u64, request_id: u64,
}, },
TopUpBandwidth { TopUpBandwidth {
msg: Box<dyn TopUpMessage + Send + Sync + 'static>, msg: Box<dyn TopUpMessage + Send + Sync + 'static>,
protocol: Protocol, protocol: Protocol,
reply_to: Option<Recipient>, reply_to: Recipient,
request_id: u64, request_id: u64,
}, },
} }
@@ -255,7 +218,7 @@ impl From<v1::request::AuthenticatorRequest> for AuthenticatorRequest {
version: value.version, version: value.version,
service_provider_type: ServiceProviderType::Authenticator, service_provider_type: ServiceProviderType::Authenticator,
}, },
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
}, },
v1::request::AuthenticatorRequestData::Final(gateway_client) => Self::Final { v1::request::AuthenticatorRequestData::Final(gateway_client) => Self::Final {
@@ -264,7 +227,7 @@ impl From<v1::request::AuthenticatorRequest> for AuthenticatorRequest {
version: value.version, version: value.version,
service_provider_type: ServiceProviderType::Authenticator, service_provider_type: ServiceProviderType::Authenticator,
}, },
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
}, },
v1::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => { v1::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
@@ -274,7 +237,7 @@ impl From<v1::request::AuthenticatorRequest> for AuthenticatorRequest {
version: value.version, version: value.version,
service_provider_type: ServiceProviderType::Authenticator, service_provider_type: ServiceProviderType::Authenticator,
}, },
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
} }
} }
@@ -288,20 +251,20 @@ impl From<v2::request::AuthenticatorRequest> for AuthenticatorRequest {
v2::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial { v2::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
msg: Box::new(init_message), msg: Box::new(init_message),
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
}, },
v2::request::AuthenticatorRequestData::Final(final_message) => Self::Final { v2::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
msg: final_message, msg: final_message,
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
}, },
v2::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => { v2::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
Self::QueryBandwidth { Self::QueryBandwidth {
msg: Box::new(peer_public_key), msg: Box::new(peer_public_key),
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
} }
} }
@@ -315,20 +278,20 @@ impl From<v3::request::AuthenticatorRequest> for AuthenticatorRequest {
v3::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial { v3::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
msg: Box::new(init_message), msg: Box::new(init_message),
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
}, },
v3::request::AuthenticatorRequestData::Final(final_message) => Self::Final { v3::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
msg: final_message, msg: final_message,
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
}, },
v3::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => { v3::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
Self::QueryBandwidth { Self::QueryBandwidth {
msg: Box::new(peer_public_key), msg: Box::new(peer_public_key),
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
} }
} }
@@ -336,7 +299,7 @@ impl From<v3::request::AuthenticatorRequest> for AuthenticatorRequest {
Self::TopUpBandwidth { Self::TopUpBandwidth {
msg: top_up_message, msg: top_up_message,
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
} }
} }
@@ -350,20 +313,20 @@ impl From<v4::request::AuthenticatorRequest> for AuthenticatorRequest {
v4::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial { v4::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
msg: Box::new(init_message), msg: Box::new(init_message),
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
}, },
v4::request::AuthenticatorRequestData::Final(final_message) => Self::Final { v4::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
msg: final_message, msg: final_message,
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
}, },
v4::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => { v4::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
Self::QueryBandwidth { Self::QueryBandwidth {
msg: Box::new(peer_public_key), msg: Box::new(peer_public_key),
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id, request_id: value.request_id,
} }
} }
@@ -371,42 +334,7 @@ impl From<v4::request::AuthenticatorRequest> for AuthenticatorRequest {
Self::TopUpBandwidth { Self::TopUpBandwidth {
msg: top_up_message, msg: top_up_message,
protocol: value.protocol, protocol: value.protocol,
reply_to: Some(value.reply_to), reply_to: value.reply_to,
request_id: value.request_id,
}
}
}
}
}
impl From<v5::request::AuthenticatorRequest> for AuthenticatorRequest {
fn from(value: v5::request::AuthenticatorRequest) -> Self {
match value.data {
v5::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
msg: Box::new(init_message),
protocol: value.protocol,
reply_to: None,
request_id: value.request_id,
},
v5::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
msg: final_message,
protocol: value.protocol,
reply_to: None,
request_id: value.request_id,
},
v5::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
Self::QueryBandwidth {
msg: Box::new(peer_public_key),
protocol: value.protocol,
reply_to: None,
request_id: value.request_id,
}
}
v5::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
Self::TopUpBandwidth {
msg: top_up_message,
protocol: value.protocol,
reply_to: None,
request_id: value.request_id, request_id: value.request_id,
} }
} }
@@ -28,7 +28,7 @@ pub type HmacSha256 = Hmac<Sha256>;
pub type Nonce = u64; pub type Nonce = u64;
pub type Taken = Option<SystemTime>; pub type Taken = Option<SystemTime>;
pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IpPair { pub struct IpPair {
@@ -60,7 +60,7 @@ impl From<IpAddr> for IpPair {
std::net::IpAddr::V4(ipv4_addr) => (ipv4_addr.octets()[2], ipv4_addr.octets()[3]), std::net::IpAddr::V4(ipv4_addr) => (ipv4_addr.octets()[2], ipv4_addr.octets()[3]),
std::net::IpAddr::V6(ipv6_addr) => (ipv6_addr.octets()[14], ipv6_addr.octets()[15]), std::net::IpAddr::V6(ipv6_addr) => (ipv6_addr.octets()[14], ipv6_addr.octets()[15]),
}; };
let last_bytes = ((before_last_byte as u16) << 8) | last_byte as u16; let last_bytes = (before_last_byte as u16) << 8 | last_byte as u16;
let ipv4 = Ipv4Addr::new( let ipv4 = Ipv4Addr::new(
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[0], WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[0],
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[1], WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[1],
@@ -1,478 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use crate::{v4, v5};
impl From<v4::request::AuthenticatorRequest> for v5::request::AuthenticatorRequest {
fn from(authenticator_request: v4::request::AuthenticatorRequest) -> Self {
Self {
protocol: Protocol {
version: 5,
service_provider_type: ServiceProviderType::Authenticator,
},
data: authenticator_request.data.into(),
request_id: authenticator_request.request_id,
}
}
}
impl From<v4::request::AuthenticatorRequestData> for v5::request::AuthenticatorRequestData {
fn from(authenticator_request_data: v4::request::AuthenticatorRequestData) -> Self {
match authenticator_request_data {
v4::request::AuthenticatorRequestData::Initial(init_msg) => {
v5::request::AuthenticatorRequestData::Initial(init_msg.into())
}
v4::request::AuthenticatorRequestData::Final(final_msg) => {
v5::request::AuthenticatorRequestData::Final(Box::new((*final_msg).into()))
}
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
v5::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
}
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
v5::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into())
}
}
}
}
impl From<v4::registration::InitMessage> for v5::registration::InitMessage {
fn from(init_msg: v4::registration::InitMessage) -> Self {
Self {
pub_key: init_msg.pub_key,
}
}
}
impl From<v4::registration::FinalMessage> for v5::registration::FinalMessage {
fn from(final_msg: v4::registration::FinalMessage) -> Self {
Self {
gateway_client: final_msg.gateway_client.into(),
credential: final_msg.credential,
}
}
}
impl From<v4::registration::GatewayClient> for v5::registration::GatewayClient {
fn from(gateway_client: v4::registration::GatewayClient) -> Self {
Self {
pub_key: gateway_client.pub_key,
private_ips: gateway_client.private_ips.into(),
mac: gateway_client.mac.into(),
}
}
}
impl From<v5::registration::GatewayClient> for v4::registration::GatewayClient {
fn from(gateway_client: v5::registration::GatewayClient) -> Self {
Self {
pub_key: gateway_client.pub_key,
private_ips: gateway_client.private_ips.into(),
mac: gateway_client.mac.into(),
}
}
}
impl From<v4::registration::ClientMac> for v5::registration::ClientMac {
fn from(client_mac: v4::registration::ClientMac) -> Self {
Self::new((*client_mac).clone())
}
}
impl From<v5::registration::ClientMac> for v4::registration::ClientMac {
fn from(client_mac: v5::registration::ClientMac) -> Self {
Self::new((*client_mac).clone())
}
}
impl From<Box<v4::topup::TopUpMessage>> for Box<v5::topup::TopUpMessage> {
fn from(top_up_message: Box<v4::topup::TopUpMessage>) -> Self {
Box::new(v5::topup::TopUpMessage {
pub_key: top_up_message.pub_key,
credential: top_up_message.credential,
})
}
}
impl From<v4::response::AuthenticatorResponse> for v5::response::AuthenticatorResponse {
fn from(value: v4::response::AuthenticatorResponse) -> Self {
Self {
protocol: Protocol {
version: 5,
service_provider_type: value.protocol.service_provider_type,
},
data: value.data.into(),
}
}
}
impl From<v4::response::AuthenticatorResponseData> for v5::response::AuthenticatorResponseData {
fn from(authenticator_response_data: v4::response::AuthenticatorResponseData) -> Self {
match authenticator_response_data {
v4::response::AuthenticatorResponseData::PendingRegistration(pending_response) => {
v5::response::AuthenticatorResponseData::PendingRegistration(
pending_response.into(),
)
}
v4::response::AuthenticatorResponseData::Registered(registered_response) => {
v5::response::AuthenticatorResponseData::Registered(registered_response.into())
}
v4::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response,
) => v5::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response.into(),
),
v4::response::AuthenticatorResponseData::TopUpBandwidth(top_up_response) => {
v5::response::AuthenticatorResponseData::TopUpBandwidth(top_up_response.into())
}
}
}
}
impl From<v4::response::RegisteredResponse> for v5::response::RegisteredResponse {
fn from(value: v4::response::RegisteredResponse) -> Self {
Self {
request_id: value.request_id,
reply: value.reply.into(),
}
}
}
impl From<v4::response::PendingRegistrationResponse> for v5::response::PendingRegistrationResponse {
fn from(value: v4::response::PendingRegistrationResponse) -> Self {
Self {
request_id: value.request_id,
reply: value.reply.into(),
}
}
}
impl From<v4::registration::RegistrationData> for v5::registration::RegistrationData {
fn from(value: v4::registration::RegistrationData) -> Self {
Self {
nonce: value.nonce,
gateway_data: value.gateway_data.into(),
wg_port: value.wg_port,
}
}
}
impl From<v5::registration::RegistrationData> for v4::registration::RegistrationData {
fn from(value: v5::registration::RegistrationData) -> Self {
Self {
nonce: value.nonce,
gateway_data: value.gateway_data.into(),
wg_port: value.wg_port,
}
}
}
impl From<v4::response::RemainingBandwidthResponse> for v5::response::RemainingBandwidthResponse {
fn from(value: v4::response::RemainingBandwidthResponse) -> Self {
Self {
request_id: value.request_id,
reply: value.reply.map(Into::into),
}
}
}
impl From<v4::response::TopUpBandwidthResponse> for v5::response::TopUpBandwidthResponse {
fn from(value: v4::response::TopUpBandwidthResponse) -> Self {
Self {
request_id: value.request_id,
reply: value.reply.into(),
}
}
}
impl From<v4::registration::RegistredData> for v5::registration::RegistredData {
fn from(value: v4::registration::RegistredData) -> Self {
Self {
pub_key: value.pub_key,
private_ips: value.private_ips.into(),
wg_port: value.wg_port,
}
}
}
impl From<v4::registration::RemainingBandwidthData> for v5::registration::RemainingBandwidthData {
fn from(value: v4::registration::RemainingBandwidthData) -> Self {
Self {
available_bandwidth: value.available_bandwidth,
}
}
}
impl From<v4::registration::IpPair> for v5::registration::IpPair {
fn from(value: v4::registration::IpPair) -> Self {
Self {
ipv4: value.ipv4,
ipv6: value.ipv6,
}
}
}
impl From<v5::registration::IpPair> for v4::registration::IpPair {
fn from(value: v5::registration::IpPair) -> Self {
Self {
ipv4: value.ipv4,
ipv6: value.ipv6,
}
}
}
#[cfg(test)]
mod tests {
use std::{
net::{Ipv4Addr, Ipv6Addr},
str::FromStr,
};
use nym_credentials_interface::CredentialSpendingData;
use nym_crypto::asymmetric::encryption::PrivateKey;
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use x25519_dalek::PublicKey;
use super::*;
use crate::{
util::tests::{CREDENTIAL_BYTES, RECIPIENT},
v4,
};
#[test]
fn upgrade_initial_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v4::request::AuthenticatorRequest::new_initial_request(
v4::registration::InitMessage::new(pub_key),
reply_to,
);
let upgraded_msg = v5::request::AuthenticatorRequest::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 5,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v5::request::AuthenticatorRequestData::Initial(v5::registration::InitMessage {
pub_key
})
);
}
#[test]
fn upgrade_final_req() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
let ipv6 = Ipv6Addr::from_str("fc01::a0a").unwrap();
let ips = v4::registration::IpPair::new(ipv4, ipv6);
let nonce = 42;
let gateway_client = v4::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
ips,
nonce,
);
let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap());
let final_message = v4::registration::FinalMessage {
gateway_client: gateway_client.clone(),
credential: credential.clone(),
};
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) =
v4::request::AuthenticatorRequest::new_final_request(final_message, reply_to);
let upgraded_msg = v5::request::AuthenticatorRequest::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 5,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v5::request::AuthenticatorRequestData::Final(Box::new(
v5::registration::FinalMessage {
gateway_client: v5::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
v5::registration::IpPair::new(ipv4, ipv6),
nonce
),
credential
}
))
);
}
#[test]
fn upgrade_query_req() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let (msg, _) = v4::request::AuthenticatorRequest::new_query_request(pub_key, reply_to);
let upgraded_msg = v5::request::AuthenticatorRequest::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 5,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v5::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
);
}
#[test]
fn upgrade_pending_reg_resp() {
let mut rng = rand::thread_rng();
let local_secret = PrivateKey::new(&mut rng);
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
let ipv6 = Ipv6Addr::from_str("fc01::a0a").unwrap();
let ips = v4::registration::IpPair::new(ipv4, ipv6);
let nonce = 42;
let wg_port = 51822;
let gateway_data = v4::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
ips,
nonce,
);
let registration_data = v4::registration::RegistrationData {
nonce,
gateway_data,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v4::response::AuthenticatorResponse::new_pending_registration_success(
registration_data,
request_id,
reply_to,
);
let upgraded_msg = v5::response::AuthenticatorResponse::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 5,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v5::response::AuthenticatorResponseData::PendingRegistration(
v5::response::PendingRegistrationResponse {
request_id,
reply: v5::registration::RegistrationData {
nonce,
gateway_data: v5::registration::GatewayClient::new(
&local_secret,
(&remote_secret).into(),
v5::registration::IpPair::new(ipv4, ipv6),
nonce
),
wg_port
}
}
)
);
}
#[test]
fn upgrade_registered_resp() {
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
let ipv4 = Ipv4Addr::from_str("10.1.10.10").unwrap();
let ipv6 = Ipv6Addr::from_str("fc01::a0a").unwrap();
let private_ips = v4::registration::IpPair::new(ipv4, ipv6);
let wg_port = 51822;
let registred_data = v4::registration::RegistredData {
pub_key,
private_ips,
wg_port,
};
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v4::response::AuthenticatorResponse::new_registered(
registred_data,
reply_to,
request_id,
);
let upgraded_msg = v5::response::AuthenticatorResponse::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 5,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v5::response::AuthenticatorResponseData::Registered(v5::response::RegisteredResponse {
request_id,
reply: v5::registration::RegistredData {
wg_port,
pub_key,
private_ips: v5::registration::IpPair::new(ipv4, ipv6)
}
})
);
}
#[test]
fn upgrade_remaining_bandwidth_resp() {
let available_bandwidth = 42;
let remaining_bandwidth_data = Some(v4::registration::RemainingBandwidthData {
available_bandwidth,
});
let request_id = 123;
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
let msg = v4::response::AuthenticatorResponse::new_remaining_bandwidth(
remaining_bandwidth_data,
reply_to,
request_id,
);
let upgraded_msg = v5::response::AuthenticatorResponse::from(msg);
assert_eq!(
upgraded_msg.protocol,
Protocol {
version: 5,
service_provider_type: ServiceProviderType::Authenticator
}
);
assert_eq!(
upgraded_msg.data,
v5::response::AuthenticatorResponseData::RemainingBandwidth(
v5::response::RemainingBandwidthResponse {
request_id,
reply: Some(v5::registration::RemainingBandwidthData {
available_bandwidth,
})
}
)
);
}
}
@@ -1,10 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod conversion;
pub mod registration;
pub mod request;
pub mod response;
pub mod topup;
pub const VERSION: u8 = 5;
@@ -1,287 +0,0 @@
// -2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::Error;
use base64::{engine::general_purpose, Engine};
use nym_credentials_interface::CredentialSpendingData;
use nym_network_defaults::constants::{WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6};
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::time::SystemTime;
use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::PrivateKey;
#[cfg(feature = "verify")]
use sha2::Sha256;
pub type PendingRegistrations = HashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = HashMap<IpPair, Taken>;
#[cfg(feature = "verify")]
pub type HmacSha256 = Hmac<Sha256>;
pub type Nonce = u64;
pub type Taken = Option<SystemTime>;
pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IpPair {
pub ipv4: Ipv4Addr,
pub ipv6: Ipv6Addr,
}
impl IpPair {
pub fn new(ipv4: Ipv4Addr, ipv6: Ipv6Addr) -> Self {
IpPair { ipv4, ipv6 }
}
}
impl From<(Ipv4Addr, Ipv6Addr)> for IpPair {
fn from((ipv4, ipv6): (Ipv4Addr, Ipv6Addr)) -> Self {
IpPair { ipv4, ipv6 }
}
}
impl fmt::Display for IpPair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.ipv4, self.ipv6)
}
}
impl From<IpAddr> for IpPair {
fn from(value: IpAddr) -> Self {
let (before_last_byte, last_byte) = match value {
std::net::IpAddr::V4(ipv4_addr) => (ipv4_addr.octets()[2], ipv4_addr.octets()[3]),
std::net::IpAddr::V6(ipv6_addr) => (ipv6_addr.octets()[14], ipv6_addr.octets()[15]),
};
let last_bytes = ((before_last_byte as u16) << 8) | last_byte as u16;
let ipv4 = Ipv4Addr::new(
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[0],
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[1],
before_last_byte,
last_byte,
);
let ipv6 = Ipv6Addr::new(
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[0],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[1],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[2],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[3],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[4],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[5],
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[6],
last_bytes,
);
IpPair::new(ipv4, ipv6)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct InitMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
}
impl InitMessage {
pub fn new(pub_key: PeerPublicKey) -> Self {
InitMessage { pub_key }
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct FinalMessage {
/// Gateway client data
pub gateway_client: GatewayClient,
/// Ecash credential
pub credential: Option<CredentialSpendingData>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct RegistredData {
pub pub_key: PeerPublicKey,
pub private_ips: IpPair,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct RemainingBandwidthData {
pub available_bandwidth: i64,
}
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
/// Gateway/Nym node can then verify pub_key payload using the same process
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct GatewayClient {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
/// Assigned private IPs (v4 and v6)
pub private_ips: IpPair,
/// Sha256 hmac on the data (alongside the prior nonce)
pub mac: ClientMac,
}
impl GatewayClient {
#[cfg(feature = "verify")]
pub fn new(
local_secret: &PrivateKey,
remote_public: x25519_dalek::PublicKey,
private_ips: IpPair,
nonce: u64,
) -> Self {
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
#[allow(clippy::expect_used)]
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
let dh = static_secret.diffie_hellman(&remote_public);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
.expect("x25519 shared secret is always 32 bytes long");
mac.update(local_public.as_bytes());
mac.update(private_ips.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
GatewayClient {
pub_key: PeerPublicKey::new(local_public),
private_ips,
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
}
}
// Reusable secret should be gateways Wireguard PK
// Client should perform this step when generating its payload, using its own WG PK
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
#[allow(clippy::expect_used)]
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
let dh = static_secret.diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
.expect("x25519 shared secret is always 32 bytes long");
mac.update(self.pub_key.as_bytes());
mac.update(self.private_ips.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
mac.verify_slice(&self.mac)
.map_err(|source| Error::FailedClientMacVerification {
client: self.pub_key.to_string(),
source,
})
}
pub fn pub_key(&self) -> PeerPublicKey {
self.pub_key
}
}
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone, PartialEq)]
pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", general_purpose::STANDARD.encode(&self.0))
}
}
impl ClientMac {
#[allow(dead_code)]
pub fn new(mac: Vec<u8>) -> Self {
ClientMac(mac)
}
}
impl Deref for ClientMac {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl FromStr for ClientMac {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mac_bytes: Vec<u8> =
general_purpose::STANDARD
.decode(s)
.map_err(|source| Error::MalformedClientMac {
mac: s.to_string(),
source,
})?;
Ok(ClientMac(mac_bytes))
}
}
impl Serialize for ClientMac {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let encoded_key = general_purpose::STANDARD.encode(self.0.clone());
serializer.serialize_str(&encoded_key)
}
}
impl<'de> Deserialize<'de> for ClientMac {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let encoded_key = String::deserialize(deserializer)?;
ClientMac::from_str(&encoded_key).map_err(serde::de::Error::custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
#[test]
fn create_ip_pair() {
let ipv4: IpAddr = Ipv4Addr::from_str("10.1.10.50").unwrap().into();
let ipv6: IpAddr = Ipv6Addr::from_str("fc01::0a32").unwrap().into();
assert_eq!(IpPair::from(ipv4), IpPair::from(ipv6));
}
#[test]
#[cfg(feature = "verify")]
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let nonce = 1234567890;
let client = GatewayClient::new(
client_key_pair.private_key(),
x25519_dalek::PublicKey::from(gateway_key_pair.public_key().to_bytes()),
IpPair::new("10.0.0.42".parse().unwrap(), "fc00::42".parse().unwrap()),
nonce,
);
assert!(client.verify(gateway_key_pair.private_key(), nonce).is_ok())
}
}
@@ -1,132 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::{
registration::{FinalMessage, InitMessage},
topup::TopUpMessage,
};
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
fn generate_random() -> u64 {
use rand::RngCore;
let mut rng = rand::rngs::OsRng;
rng.next_u64()
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct AuthenticatorRequest {
pub protocol: Protocol,
pub data: AuthenticatorRequestData,
pub request_id: u64,
}
impl AuthenticatorRequest {
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn new_initial_request(init_message: InitMessage) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::Initial(init_message),
request_id,
},
request_id,
)
}
pub fn new_final_request(final_message: FinalMessage) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::Final(Box::new(final_message)),
request_id,
},
request_id,
)
}
pub fn new_query_request(peer_public_key: PeerPublicKey) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::QueryBandwidth(peer_public_key),
request_id,
},
request_id,
)
}
pub fn new_topup_request(top_up_message: TopUpMessage) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::TopUpBandwidth(Box::new(top_up_message)),
request_id,
},
request_id,
)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(Box<FinalMessage>),
QueryBandwidth(PeerPublicKey),
TopUpBandwidth(Box<TopUpMessage>),
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn check_first_bytes_protocol() {
let version = 5;
let data = AuthenticatorRequest {
protocol: Protocol {
version,
service_provider_type: ServiceProviderType::Authenticator,
},
data: AuthenticatorRequestData::Initial(InitMessage::new(
PeerPublicKey::from_str("yvNUDpT5l7W/xDhiu6HkqTHDQwbs/B3J5UrLmORl1EQ=").unwrap(),
)),
request_id: 1,
};
let bytes = *data.to_bytes().unwrap().first_chunk::<2>().unwrap();
assert_eq!(bytes, [version, ServiceProviderType::Authenticator as u8]);
}
}
@@ -1,132 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::registration::{RegistrationData, RegistredData, RemainingBandwidthData};
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct AuthenticatorResponse {
pub protocol: Protocol,
pub data: AuthenticatorResponseData,
}
impl AuthenticatorResponse {
pub fn new_pending_registration_success(
registration_data: RegistrationData,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
reply: registration_data,
request_id,
}),
}
}
pub fn new_registered(registred_data: RegistredData, request_id: u64) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::Registered(RegisteredResponse {
reply: registred_data,
request_id,
}),
}
}
pub fn new_remaining_bandwidth(
remaining_bandwidth_data: Option<RemainingBandwidthData>,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::RemainingBandwidth(RemainingBandwidthResponse {
reply: remaining_bandwidth_data,
request_id,
}),
}
}
pub fn new_topup_bandwidth(
remaining_bandwidth_data: RemainingBandwidthData,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::TopUpBandwidth(TopUpBandwidthResponse {
reply: remaining_bandwidth_data,
request_id,
}),
}
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn id(&self) -> Option<u64> {
match &self.data {
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
AuthenticatorResponseData::RemainingBandwidth(response) => Some(response.request_id),
AuthenticatorResponseData::TopUpBandwidth(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
RemainingBandwidth(RemainingBandwidthResponse),
TopUpBandwidth(TopUpBandwidthResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply: Option<RemainingBandwidthData>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct TopUpBandwidthResponse {
pub request_id: u64,
pub reply: RemainingBandwidthData,
}
@@ -1,15 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct TopUpMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
/// Ecash credential
pub credential: CredentialSpendingData,
}
+7 -4
View File
@@ -105,24 +105,26 @@ impl<C, St: Storage> BandwidthController<C, St> {
async fn get_aggregate_verification_key( async fn get_aggregate_verification_key(
&self, &self,
epoch_id: EpochId, epoch_id: EpochId,
ecash_apis: &mut ApiClientsWrapper<'_, C>, apis: &mut ApiClientsWrapper,
) -> Result<VerificationKeyAuth, BandwidthControllerError> ) -> Result<VerificationKeyAuth, BandwidthControllerError>
where where
C: DkgQueryClient + Sync + Send, C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static, <St as Storage>::StorageError: Send + Sync + 'static,
{ {
let ecash_apis = apis.get_or_init(epoch_id, &self.client).await?;
get_aggregate_verification_key(&self.storage, epoch_id, ecash_apis).await get_aggregate_verification_key(&self.storage, epoch_id, ecash_apis).await
} }
async fn get_coin_index_signatures( async fn get_coin_index_signatures(
&self, &self,
epoch_id: EpochId, epoch_id: EpochId,
ecash_apis: &mut ApiClientsWrapper<'_, C>, apis: &mut ApiClientsWrapper,
) -> Result<Vec<AnnotatedCoinIndexSignature>, BandwidthControllerError> ) -> Result<Vec<AnnotatedCoinIndexSignature>, BandwidthControllerError>
where where
C: DkgQueryClient + Sync + Send, C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static, <St as Storage>::StorageError: Send + Sync + 'static,
{ {
let ecash_apis = apis.get_or_init(epoch_id, &self.client).await?;
get_coin_index_signatures(&self.storage, epoch_id, ecash_apis).await get_coin_index_signatures(&self.storage, epoch_id, ecash_apis).await
} }
@@ -130,12 +132,13 @@ impl<C, St: Storage> BandwidthController<C, St> {
&self, &self,
epoch_id: EpochId, epoch_id: EpochId,
expiration_date: Date, expiration_date: Date,
ecash_apis: &mut ApiClientsWrapper<'_, C>, apis: &mut ApiClientsWrapper,
) -> Result<Vec<AnnotatedExpirationDateSignature>, BandwidthControllerError> ) -> Result<Vec<AnnotatedExpirationDateSignature>, BandwidthControllerError>
where where
C: DkgQueryClient + Sync + Send, C: DkgQueryClient + Sync + Send,
<St as Storage>::StorageError: Send + Sync + 'static, <St as Storage>::StorageError: Send + Sync + 'static,
{ {
let ecash_apis = apis.get_or_init(epoch_id, &self.client).await?;
get_expiration_date_signatures(&self.storage, epoch_id, expiration_date, ecash_apis).await get_expiration_date_signatures(&self.storage, epoch_id, expiration_date, ecash_apis).await
} }
@@ -151,7 +154,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
{ {
let epoch_id = retrieved_ticketbook.ticketbook.epoch_id(); let epoch_id = retrieved_ticketbook.ticketbook.epoch_id();
let expiration_date = retrieved_ticketbook.ticketbook.expiration_date(); let expiration_date = retrieved_ticketbook.ticketbook.expiration_date();
let mut api_clients = ApiClientsWrapper::new(&self.client, epoch_id); let mut api_clients = Default::default();
let verification_key = self let verification_key = self
.get_aggregate_verification_key(epoch_id, &mut api_clients) .get_aggregate_verification_key(epoch_id, &mut api_clients)
+20 -63
View File
@@ -21,67 +21,30 @@ use rand::thread_rng;
use std::fmt::Display; use std::fmt::Display;
use std::future::Future; use std::future::Future;
pub(crate) trait EcashClientsProvider { // it really doesn't need the RwLock because it's never moved across tasks,
async fn try_get_ecash_clients( // but we need all the Send/Sync action
&mut self, #[derive(Default)]
) -> Result<Vec<EcashApiClient>, BandwidthControllerError>; pub(crate) struct ApiClientsWrapper(Option<Vec<EcashApiClient>>);
}
impl EcashClientsProvider for Vec<EcashApiClient> { impl ApiClientsWrapper {
async fn try_get_ecash_clients( pub(crate) async fn get_or_init<C>(
&mut self, &mut self,
) -> Result<Vec<EcashApiClient>, BandwidthControllerError> {
Ok(self.clone())
}
}
impl<C> EcashClientsProvider for &mut ApiClientsWrapper<'_, C>
where
C: DkgQueryClient + Sync + Send,
{
async fn try_get_ecash_clients(
&mut self,
) -> Result<Vec<EcashApiClient>, BandwidthControllerError> {
self.clients().await
}
}
pub(crate) enum ApiClientsWrapper<'a, C> {
Uninitialised {
query_client: &'a C,
epoch_id: EpochId, epoch_id: EpochId,
}, dkg_client: &C,
Cached { ) -> Result<Vec<EcashApiClient>, BandwidthControllerError>
clients: Vec<EcashApiClient>,
},
}
impl<'a, C> ApiClientsWrapper<'a, C> {
pub(crate) fn new(query_client: &'a C, epoch_id: EpochId) -> Self {
ApiClientsWrapper::Uninitialised {
query_client,
epoch_id,
}
}
async fn clients(&mut self) -> Result<Vec<EcashApiClient>, BandwidthControllerError>
where where
C: DkgQueryClient + Sync + Send, C: DkgQueryClient + Sync + Send,
{ {
match self { if let Some(cached) = &self.0 {
ApiClientsWrapper::Uninitialised { return Ok(cached.clone());
query_client,
epoch_id,
} => {
let clients = all_ecash_api_clients(*query_client, *epoch_id).await?;
*self = ApiClientsWrapper::Cached {
clients: clients.clone(),
};
Ok(clients)
}
ApiClientsWrapper::Cached { clients } => Ok(clients.clone()),
} }
let clients = all_ecash_api_clients(dkg_client, epoch_id).await?;
// technically we don't have to be cloning all the clients here, but it's way simpler than
// dealing with locking and whatnot given the performance penalty is negligible
self.0 = Some(clients.clone());
Ok(clients)
} }
} }
@@ -113,7 +76,7 @@ where
pub(crate) async fn get_aggregate_verification_key<St>( pub(crate) async fn get_aggregate_verification_key<St>(
storage: &St, storage: &St,
epoch_id: EpochId, epoch_id: EpochId,
mut ecash_apis: impl EcashClientsProvider, ecash_apis: Vec<EcashApiClient>,
) -> Result<VerificationKeyAuth, BandwidthControllerError> ) -> Result<VerificationKeyAuth, BandwidthControllerError>
where where
St: Storage, St: Storage,
@@ -127,8 +90,6 @@ where
return Ok(stored); return Ok(stored);
}; };
let ecash_apis = ecash_apis.try_get_ecash_clients().await?;
let master_vk = query_random_apis_until_success( let master_vk = query_random_apis_until_success(
ecash_apis, ecash_apis,
|api| async move { api.api_client.master_verification_key(Some(epoch_id)).await }, |api| async move { api.api_client.master_verification_key(Some(epoch_id)).await },
@@ -154,7 +115,7 @@ where
pub(crate) async fn get_coin_index_signatures<St>( pub(crate) async fn get_coin_index_signatures<St>(
storage: &St, storage: &St,
epoch_id: EpochId, epoch_id: EpochId,
mut ecash_apis: impl EcashClientsProvider, ecash_apis: Vec<EcashApiClient>,
) -> Result<Vec<AnnotatedCoinIndexSignature>, BandwidthControllerError> ) -> Result<Vec<AnnotatedCoinIndexSignature>, BandwidthControllerError>
where where
St: Storage, St: Storage,
@@ -168,8 +129,6 @@ where
return Ok(stored); return Ok(stored);
}; };
let ecash_apis = ecash_apis.try_get_ecash_clients().await?;
let index_sigs = query_random_apis_until_success( let index_sigs = query_random_apis_until_success(
ecash_apis, ecash_apis,
|api| async move { |api| async move {
@@ -200,7 +159,7 @@ pub(crate) async fn get_expiration_date_signatures<St>(
storage: &St, storage: &St,
epoch_id: EpochId, epoch_id: EpochId,
expiration_date: Date, expiration_date: Date,
mut ecash_apis: impl EcashClientsProvider, ecash_apis: Vec<EcashApiClient>,
) -> Result<Vec<AnnotatedExpirationDateSignature>, BandwidthControllerError> ) -> Result<Vec<AnnotatedExpirationDateSignature>, BandwidthControllerError>
where where
St: Storage, St: Storage,
@@ -214,8 +173,6 @@ where
return Ok(stored); return Ok(stored);
}; };
let ecash_apis = ecash_apis.try_get_ecash_clients().await?;
let expiration_sigs = query_random_apis_until_success( let expiration_sigs = query_random_apis_until_success(
ecash_apis, ecash_apis,
|api| async move { |api| async move {
-1
View File
@@ -40,7 +40,6 @@ nym-crypto = { path = "../crypto" }
nym-explorer-client = { path = "../../explorer-api/explorer-client" } nym-explorer-client = { path = "../../explorer-api/explorer-client" }
nym-gateway-client = { path = "../client-libs/gateway-client" } nym-gateway-client = { path = "../client-libs/gateway-client" }
nym-gateway-requests = { path = "../gateway-requests" } nym-gateway-requests = { path = "../gateway-requests" }
nym-http-api-client = { path = "../http-api-client" }
nym-metrics = { path = "../nym-metrics" } nym-metrics = { path = "../nym-metrics" }
nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" } nym-nonexhaustive-delayqueue = { path = "../nonexhaustive-delayqueue" }
nym-sphinx = { path = "../nymsphinx" } nym-sphinx = { path = "../nymsphinx" }
+4 -90
View File
@@ -45,12 +45,11 @@ const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70;
// clients/client-core/src/client/replies/reply_storage/surb_storage.rs // clients/client-core/src/client/replies/reply_storage/surb_storage.rs
const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10; const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10;
const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200; const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200;
const DEFAULT_MINIMUM_REPLY_SURB_THRESHOLD_BUFFER: usize = 0;
// define how much to request at once // define how much to request at once
// clients/client-core/src/client/replies/reply_controller.rs // clients/client-core/src/client/replies/reply_controller.rs
const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10; const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 50; const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100;
const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500; const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
@@ -146,11 +145,6 @@ impl Config {
self self
} }
pub fn with_forget_me(mut self, forget_me: ForgetMe) -> Self {
self.debug.forget_me = forget_me;
self
}
// TODO: this should be refactored properly // TODO: this should be refactored properly
// as of 12.09.23 the below is true (not sure how this comment will rot in the future) // as of 12.09.23 the below is true (not sure how this comment will rot in the future)
// medium_toggle: // medium_toggle:
@@ -523,7 +517,7 @@ impl Default for Acknowledgements {
} }
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] #[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default)] #[serde(default, deny_unknown_fields)]
pub struct Topology { pub struct Topology {
/// 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.
@@ -559,15 +553,12 @@ pub struct Topology {
/// Specifies whether this client should attempt to retrieve all available network nodes /// Specifies whether this client should attempt to retrieve all available network nodes
/// as opposed to just active mixnodes/gateways. /// as opposed to just active mixnodes/gateways.
/// Useless without `ignore_epoch_roles = true`
pub use_extended_topology: bool, pub use_extended_topology: bool,
/// Specifies whether this client should ignore the current epoch role of the target egress node /// Specifies whether this client should ignore the current epoch role of the target egress node
/// when constructing the final hop packets. /// when constructing the final hop packets.
pub ignore_egress_epoch_role: bool, pub ignore_egress_epoch_role: bool,
/// Specifies whether this client should ignore the current epoch role of the ingress node
/// when attempting to establish new connection
pub ignore_ingress_epoch_role: bool,
} }
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
@@ -605,9 +596,7 @@ impl Default for Topology {
minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE, minimum_mixnode_performance: DEFAULT_MIN_MIXNODE_PERFORMANCE,
minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE, minimum_gateway_performance: DEFAULT_MIN_GATEWAY_PERFORMANCE,
use_extended_topology: false, use_extended_topology: false,
ignore_egress_epoch_role: false,
ignore_egress_epoch_role: true,
ignore_ingress_epoch_role: true,
} }
} }
} }
@@ -622,10 +611,6 @@ pub struct ReplySurbs {
/// Defines the maximum number of reply surbs the client wants to keep in its storage at any times. /// Defines the maximum number of reply surbs the client wants to keep in its storage at any times.
pub maximum_reply_surb_storage_threshold: usize, pub maximum_reply_surb_storage_threshold: usize,
/// Defines the soft threshold ontop of the minimum reply surb storage threshold for when the client
/// should proactively request additional reply surbs.
pub minimum_reply_surb_threshold_buffer: usize,
/// Defines the minimum number of reply surbs the client would request. /// Defines the minimum number of reply surbs the client would request.
pub minimum_reply_surb_request_size: u32, pub minimum_reply_surb_request_size: u32,
@@ -658,9 +643,6 @@ pub struct ReplySurbs {
/// Specifies the number of mixnet hops the packet should go through. If not specified, then /// Specifies the number of mixnet hops the packet should go through. If not specified, then
/// the default value is used. /// the default value is used.
pub surb_mix_hops: Option<u8>, pub surb_mix_hops: Option<u8>,
/// Specifies if we should reset all the sender tags on startup
pub fresh_sender_tags: bool,
} }
impl Default for ReplySurbs { impl Default for ReplySurbs {
@@ -668,7 +650,6 @@ impl Default for ReplySurbs {
ReplySurbs { ReplySurbs {
minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD, minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD,
maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD, maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD,
minimum_reply_surb_threshold_buffer: DEFAULT_MINIMUM_REPLY_SURB_THRESHOLD_BUFFER,
minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE, minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE,
maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE, maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE,
maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE, maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE,
@@ -678,7 +659,6 @@ impl Default for ReplySurbs {
maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE, maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE,
maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE, maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE,
surb_mix_hops: None, surb_mix_hops: None,
fresh_sender_tags: false,
} }
} }
} }
@@ -734,9 +714,6 @@ pub struct DebugConfig {
/// Defines all configuration options related to stats reporting. /// Defines all configuration options related to stats reporting.
pub stats_reporting: StatsReporting, pub stats_reporting: StatsReporting,
/// Defines all configuration options related to the forget me flag.
pub forget_me: ForgetMe,
} }
impl DebugConfig { impl DebugConfig {
@@ -759,69 +736,6 @@ impl Default for DebugConfig {
topology: Default::default(), topology: Default::default(),
reply_surbs: Default::default(), reply_surbs: Default::default(),
stats_reporting: Default::default(), stats_reporting: Default::default(),
forget_me: Default::default(),
}
}
}
#[derive(Clone, Default, Debug, Deserialize, PartialEq, Serialize, Copy)]
pub struct ForgetMe {
client: bool,
stats: bool,
}
impl From<bool> for ForgetMe {
fn from(value: bool) -> Self {
if value {
Self::new_all()
} else {
Self::new_none()
}
}
}
impl ForgetMe {
pub fn new_all() -> Self {
Self {
client: true,
stats: true,
}
}
pub fn new_client() -> Self {
Self {
client: true,
stats: false,
}
}
pub fn new_stats() -> Self {
Self {
client: false,
stats: true,
}
}
pub fn new(client: bool, stats: bool) -> Self {
Self { client, stats }
}
pub fn any(&self) -> bool {
self.client || self.stats
}
pub fn client(&self) -> bool {
self.client
}
pub fn stats(&self) -> bool {
self.stats
}
pub fn new_none() -> Self {
Self {
client: false,
stats: false,
} }
} }
} }
@@ -181,9 +181,8 @@ impl From<ConfigV5> for Config {
maximum_reply_surb_age: value.debug.reply_surbs.maximum_reply_surb_age, maximum_reply_surb_age: value.debug.reply_surbs.maximum_reply_surb_age,
maximum_reply_key_age: value.debug.reply_surbs.maximum_reply_key_age, maximum_reply_key_age: value.debug.reply_surbs.maximum_reply_key_age,
surb_mix_hops: value.debug.reply_surbs.surb_mix_hops, surb_mix_hops: value.debug.reply_surbs.surb_mix_hops,
..Default::default()
}, },
..Default::default() stats_reporting: Default::default(),
}, },
} }
} }
@@ -15,7 +15,6 @@ pub mod error;
mod manager; mod manager;
mod models; mod models;
#[derive(Clone)]
pub struct OnDiskGatewaysDetails { pub struct OnDiskGatewaysDetails {
manager: StorageManager, manager: StorageManager,
} }
@@ -20,12 +20,12 @@ pub enum InMemStorageError {
MalformedGateway(#[from] BadGateway), MalformedGateway(#[from] BadGateway),
} }
#[derive(Clone, Debug, Default)] #[derive(Debug, Default)]
pub struct InMemGatewaysDetails { pub struct InMemGatewaysDetails {
inner: Arc<RwLock<InMemStorageInner>>, inner: Arc<RwLock<InMemStorageInner>>,
} }
#[derive(Clone, Debug, Default)] #[derive(Debug, Default)]
struct InMemStorageInner { struct InMemStorageInner {
active_gateway: Option<String>, active_gateway: Option<String>,
gateways: HashMap<String, GatewayRegistration>, gateways: HashMap<String, GatewayRegistration>,
@@ -115,12 +115,11 @@ where
hardcoded_topology.entry_capable_nodes().cloned().collect() hardcoded_topology.entry_capable_nodes().cloned().collect()
} else { } else {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
crate::init::helpers::gateways_for_init( crate::init::helpers::current_gateways(
&mut rng, &mut rng,
&core.client.nym_api_urls, &core.client.nym_api_urls,
user_agent, user_agent,
core.debug.topology.minimum_gateway_performance, core.debug.topology.minimum_gateway_performance,
core.debug.topology.ignore_ingress_epoch_role,
) )
.await? .await?
}; };
@@ -139,8 +138,6 @@ where
let gateway_setup = GatewaySetup::New { let gateway_setup = GatewaySetup::New {
specification: selection_spec, specification: selection_spec,
available_gateways, available_gateways,
#[cfg(unix)]
connection_fd_callback: None,
}; };
let init_details = let init_details =
@@ -93,10 +93,6 @@ pub struct CommonClientInitArgs {
/// Sets the address to report statistics /// Sets the address to report statistics
#[cfg_attr(feature = "cli", clap(long, hide = true))] #[cfg_attr(feature = "cli", clap(long, hide = true))]
pub stats_reporting_address: Option<Recipient>, pub stats_reporting_address: Option<Recipient>,
/// Sets the forget me flag
#[cfg_attr(feature = "cli", clap(long, hide = true, default_value_t = false))]
pub forget_me: bool,
} }
pub struct InitResultsWithConfig<T> { pub struct InitResultsWithConfig<T> {
@@ -174,12 +170,11 @@ where
hardcoded_topology.entry_capable_nodes().cloned().collect() hardcoded_topology.entry_capable_nodes().cloned().collect()
} else { } else {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
crate::init::helpers::gateways_for_init( crate::init::helpers::current_gateways(
&mut rng, &mut rng,
&core.client.nym_api_urls, &core.client.nym_api_urls,
user_agent, user_agent,
core.debug.topology.minimum_gateway_performance, core.debug.topology.minimum_gateway_performance,
core.debug.topology.ignore_ingress_epoch_role,
) )
.await? .await?
}; };
@@ -187,8 +182,6 @@ where
let gateway_setup = GatewaySetup::New { let gateway_setup = GatewaySetup::New {
specification: selection_spec, specification: selection_spec,
available_gateways, available_gateways,
#[cfg(unix)]
connection_fd_callback: None,
}; };
let init_details = let init_details =
@@ -61,8 +61,4 @@ pub struct CommonClientRunArgs {
/// Sets the address to report statistics /// Sets the address to report statistics
#[cfg_attr(feature = "cli", clap(long, hide = true))] #[cfg_attr(feature = "cli", clap(long, hide = true))]
pub stats_reporting_address: Option<Recipient>, pub stats_reporting_address: Option<Recipient>,
/// Sets the forget me flag
#[cfg_attr(feature = "cli", clap(long, hide = true, default_value_t = false))]
pub forget_me: bool,
} }
@@ -1,7 +1,6 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net> // Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use super::mix_traffic::ClientRequestSender;
use super::received_buffer::ReceivedBufferMessage; use super::received_buffer::ReceivedBufferMessage;
use super::statistics_control::StatisticsControl; use super::statistics_control::StatisticsControl;
use crate::client::base_client::storage::helpers::store_client_keys; use crate::client::base_client::storage::helpers::store_client_keys;
@@ -32,15 +31,13 @@ use crate::init::{
setup_gateway, setup_gateway,
types::{GatewaySetup, InitialisationResult}, types::{GatewaySetup, InitialisationResult},
}; };
use crate::{config, spawn_future}; use crate::{config, spawn_future, ForgetMe};
use futures::channel::mpsc; use futures::channel::mpsc;
use log::*; use log::*;
use nym_bandwidth_controller::BandwidthController; use nym_bandwidth_controller::BandwidthController;
use nym_client_core_config_types::ForgetMe;
use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore}; use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore};
use nym_credential_storage::storage::Storage as CredentialStorage; use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_crypto::asymmetric::{encryption, identity}; use nym_crypto::asymmetric::{encryption, identity};
use nym_crypto::hkdf::DerivationMaterial;
use nym_gateway_client::client::config::GatewayClientConfig; use nym_gateway_client::client::config::GatewayClientConfig;
use nym_gateway_client::{ use nym_gateway_client::{
AcknowledgementReceiver, GatewayClient, GatewayConfig, MixnetMessageReceiver, PacketRouter, AcknowledgementReceiver, GatewayClient, GatewayConfig, MixnetMessageReceiver, PacketRouter,
@@ -178,8 +175,8 @@ impl From<bool> for CredentialsToggle {
} }
} }
pub struct BaseClientBuilder<C, S: MixnetClientStorage> { pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> {
config: Config, config: &'a Config,
client_store: S, client_store: S,
dkg_query_client: Option<C>, dkg_query_client: Option<C>,
@@ -194,19 +191,19 @@ pub struct BaseClientBuilder<C, S: MixnetClientStorage> {
#[cfg(unix)] #[cfg(unix)]
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>, connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
derivation_material: Option<DerivationMaterial>, forget_me: ForgetMe,
} }
impl<C, S> BaseClientBuilder<C, S> impl<'a, C, S> BaseClientBuilder<'a, C, S>
where where
S: MixnetClientStorage + 'static, S: MixnetClientStorage + 'static,
C: DkgQueryClient + Send + Sync + 'static, C: DkgQueryClient + Send + Sync + 'static,
{ {
pub fn new( pub fn new(
base_config: Config, base_config: &'a Config,
client_store: S, client_store: S,
dkg_query_client: Option<C>, dkg_query_client: Option<C>,
) -> BaseClientBuilder<C, S> { ) -> BaseClientBuilder<'a, C, S> {
BaseClientBuilder { BaseClientBuilder {
config: base_config, config: base_config,
client_store, client_store,
@@ -219,22 +216,13 @@ where
setup_method: GatewaySetup::MustLoad { gateway_id: None }, setup_method: GatewaySetup::MustLoad { gateway_id: None },
#[cfg(unix)] #[cfg(unix)]
connection_fd_callback: None, connection_fd_callback: None,
derivation_material: None, forget_me: Default::default(),
} }
} }
#[must_use]
pub fn with_derivation_material(
mut self,
derivation_material: Option<DerivationMaterial>,
) -> Self {
self.derivation_material = derivation_material;
self
}
#[must_use] #[must_use]
pub fn with_forget_me(mut self, forget_me: &ForgetMe) -> Self { pub fn with_forget_me(mut self, forget_me: &ForgetMe) -> Self {
self.config.debug.forget_me = *forget_me; self.forget_me = forget_me.clone();
self self
} }
@@ -310,7 +298,7 @@ where
topology_accessor: TopologyAccessor, topology_accessor: TopologyAccessor,
mix_tx: BatchMixMessageSender, mix_tx: BatchMixMessageSender,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient, shutdown: TaskClient,
) { ) {
info!("Starting loop cover traffic stream..."); info!("Starting loop cover traffic stream...");
@@ -323,10 +311,9 @@ where
debug_config.traffic, debug_config.traffic,
debug_config.cover_traffic, debug_config.cover_traffic,
stats_tx, stats_tx,
task_client,
); );
stream.start(); stream.start_with_shutdown(shutdown);
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@@ -341,7 +328,7 @@ where
reply_controller_receiver: ReplyControllerReceiver, reply_controller_receiver: ReplyControllerReceiver,
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver, client_connection_rx: ConnectionCommandReceiver,
task_client: TaskClient, shutdown: TaskClient,
packet_type: PacketType, packet_type: PacketType,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
) { ) {
@@ -359,9 +346,8 @@ where
lane_queue_lengths, lane_queue_lengths,
client_connection_rx, client_connection_rx,
stats_tx, stats_tx,
task_client,
) )
.start(packet_type); .start_with_shutdown(shutdown, packet_type);
} }
// buffer controlling all messages fetched from provider // buffer controlling all messages fetched from provider
@@ -384,9 +370,8 @@ where
reply_key_storage, reply_key_storage,
reply_controller_sender, reply_controller_sender,
metrics_reporter, metrics_reporter,
shutdown,
); );
controller.start() controller.start_with_shutdown(shutdown)
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@@ -487,7 +472,6 @@ where
.claim_initial_bandwidth() .claim_initial_bandwidth()
.await .await
.map_err(gateway_failure)?; .map_err(gateway_failure)?;
gateway_client gateway_client
.start_listening_for_mixnet_messages() .start_listening_for_mixnet_messages()
.map_err(gateway_failure)?; .map_err(gateway_failure)?;
@@ -575,22 +559,15 @@ where
topology_accessor: TopologyAccessor, topology_accessor: TopologyAccessor,
local_gateway: NodeIdentity, local_gateway: NodeIdentity,
wait_for_gateway: bool, wait_for_gateway: bool,
mut task_client: TaskClient, mut shutdown: TaskClient,
) -> Result<(), ClientCoreError> { ) -> Result<(), ClientCoreError> {
let topology_refresher_config = let topology_refresher_config =
TopologyRefresherConfig::new(topology_config.topology_refresh_rate); TopologyRefresherConfig::new(topology_config.topology_refresh_rate);
if topology_config.disable_refreshing {
// if we're not spawning the refresher, don't cause shutdown immediately
info!("The background topology refesher is not going to be started");
task_client.disarm();
}
let mut topology_refresher = TopologyRefresher::new( let mut topology_refresher = TopologyRefresher::new(
topology_refresher_config, topology_refresher_config,
topology_accessor, topology_accessor,
topology_provider, topology_provider,
task_client,
); );
// 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
@@ -631,11 +608,15 @@ where
} }
} }
if !topology_config.disable_refreshing { if topology_config.disable_refreshing {
// if we're not spawning the refresher, don't cause shutdown immediately
info!("The topology refesher is not going to be started");
shutdown.disarm();
} else {
// don't spawn the refresher if we don't want to be refreshing the topology. // don't spawn the refresher if we don't want to be refreshing the topology.
// only use the initial values obtained // only use the initial values obtained
info!("Starting topology refresher..."); info!("Starting topology refresher...");
topology_refresher.start(); topology_refresher.start_with_shutdown(shutdown);
} }
Ok(()) Ok(())
@@ -646,29 +627,30 @@ where
user_agent: Option<UserAgent>, user_agent: Option<UserAgent>,
client_stats_id: String, client_stats_id: String,
input_sender: Sender<InputMessage>, input_sender: Sender<InputMessage>,
task_client: TaskClient, shutdown: TaskClient,
) -> ClientStatsSender { ) -> ClientStatsSender {
info!("Starting statistics control..."); info!("Starting statistics control...");
StatisticsControl::create_and_start( StatisticsControl::create_and_start_with_shutdown(
config.debug.stats_reporting, config.debug.stats_reporting,
user_agent user_agent
.map(|u| u.application) .map(|u| u.application)
.unwrap_or("unknown".to_string()), .unwrap_or("unknown".to_string()),
client_stats_id, client_stats_id,
input_sender.clone(), input_sender.clone(),
task_client, shutdown.with_suffix("controller"),
) )
} }
fn start_mix_traffic_controller( fn start_mix_traffic_controller(
gateway_transceiver: Box<dyn GatewayTransceiver + Send>, gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
shutdown: TaskClient, shutdown: TaskClient,
) -> (BatchMixMessageSender, ClientRequestSender) { forget_me: ForgetMe,
) -> BatchMixMessageSender {
info!("Starting mix traffic controller..."); info!("Starting mix traffic controller...");
let (mix_traffic_controller, mix_tx, client_tx) = let (mix_traffic_controller, mix_tx) =
MixTrafficController::new(gateway_transceiver, shutdown); MixTrafficController::new(gateway_transceiver, forget_me);
mix_traffic_controller.start(); mix_traffic_controller.start_with_shutdown(shutdown);
(mix_tx, client_tx) mix_tx
} }
// TODO: rename it as it implies the data is persistent whilst one can use InMemBackend // TODO: rename it as it implies the data is persistent whilst one can use InMemBackend
@@ -703,7 +685,6 @@ where
setup_method: GatewaySetup, setup_method: GatewaySetup,
key_store: &S::KeyStore, key_store: &S::KeyStore,
details_store: &S::GatewaysDetailsStore, details_store: &S::GatewaysDetailsStore,
derivation_material: Option<DerivationMaterial>,
) -> Result<InitialisationResult, ClientCoreError> ) -> Result<InitialisationResult, ClientCoreError>
where where
<S::KeyStore as KeyStore>::StorageError: Sync + Send, <S::KeyStore as KeyStore>::StorageError: Sync + Send,
@@ -713,12 +694,7 @@ where
if key_store.load_keys().await.is_err() { if key_store.load_keys().await.is_err() {
info!("could not find valid client keys - a new set will be generated"); info!("could not find valid client keys - a new set will be generated");
let mut rng = OsRng; let mut rng = OsRng;
let keys = if let Some(derivation_material) = derivation_material { let keys = ClientKeys::generate_new(&mut rng);
ClientKeys::from_master_key(&mut rng, &derivation_material)
.map_err(|_| ClientCoreError::HkdfDerivationError {})?
} else {
ClientKeys::generate_new(&mut rng)
};
store_client_keys(keys, key_store).await?; store_client_keys(keys, key_store).await?;
} }
@@ -740,7 +716,6 @@ where
self.setup_method, self.setup_method,
self.client_store.key_store(), self.client_store.key_store(),
self.client_store.gateway_details_store(), self.client_store.gateway_details_store(),
self.derivation_material,
) )
.await?; .await?;
@@ -797,7 +772,7 @@ where
); );
let stats_reporter = Self::start_statistics_control( let stats_reporter = Self::start_statistics_control(
&self.config, self.config,
self.user_agent.clone(), self.user_agent.clone(),
generate_client_stats_id(*self_address.identity()), generate_client_stats_id(*self_address.identity()),
input_sender.clone(), input_sender.clone(),
@@ -823,7 +798,7 @@ where
let gateway_transceiver = Self::setup_gateway_transceiver( let gateway_transceiver = Self::setup_gateway_transceiver(
self.custom_gateway_transceiver, self.custom_gateway_transceiver,
&self.config, self.config,
init_res, init_res,
bandwidth_controller, bandwidth_controller,
&details_store, &details_store,
@@ -857,9 +832,10 @@ where
// traffic stream. // traffic stream.
// The MixTrafficController then sends the actual traffic // The MixTrafficController then sends the actual traffic
let (message_sender, client_request_sender) = Self::start_mix_traffic_controller( let message_sender = Self::start_mix_traffic_controller(
gateway_transceiver, gateway_transceiver,
shutdown.fork("mix_traffic_controller"), shutdown.fork("mix_traffic_controller"),
self.forget_me,
); );
// Channels that the websocket listener can use to signal downstream to the real traffic // Channels that the websocket listener can use to signal downstream to the real traffic
@@ -934,8 +910,6 @@ where
}, },
stats_reporter, stats_reporter,
task_handle: shutdown, task_handle: shutdown,
client_request_sender,
forget_me: self.config.debug.forget_me,
}) })
} }
} }
@@ -947,7 +921,6 @@ pub struct BaseClient {
pub client_output: ClientOutputStatus, pub client_output: ClientOutputStatus,
pub client_state: ClientState, pub client_state: ClientState,
pub stats_reporter: ClientStatsSender, pub stats_reporter: ClientStatsSender,
pub client_request_sender: ClientRequestSender,
pub task_handle: TaskHandle, pub task_handle: TaskHandle,
pub forget_me: ForgetMe,
} }
@@ -88,7 +88,7 @@ pub async fn setup_fs_reply_surb_backend<P: AsRef<Path>>(
let db_path = db_path.as_ref(); let db_path = db_path.as_ref();
if db_path.exists() { if db_path.exists() {
info!("loading existing surb database"); info!("loading existing surb database");
match fs_backend::Backend::try_load(db_path, surb_config.fresh_sender_tags).await { match fs_backend::Backend::try_load(db_path).await {
Ok(backend) => Ok(backend), Ok(backend) => Ok(backend),
Err(err) => { Err(err) => {
error!("failed to setup persistent storage backend for our reply needs: {err}. We're going to create a fresh database instead. This behaviour might change in the future"); error!("failed to setup persistent storage backend for our reply needs: {err}. We're going to create a fresh database instead. This behaviour might change in the future");
@@ -4,8 +4,6 @@
// TODO: combine those more closely. Perhaps into a single underlying store. // TODO: combine those more closely. Perhaps into a single underlying store.
// Like for persistent, on-disk, storage, what's the point of having 3 different databases? // Like for persistent, on-disk, storage, what's the point of having 3 different databases?
use rand::rngs::OsRng;
use crate::client::key_manager::persistence::{InMemEphemeralKeys, KeyStore}; use crate::client::key_manager::persistence::{InMemEphemeralKeys, KeyStore};
use crate::client::replies::reply_storage; use crate::client::replies::reply_storage;
use crate::client::replies::reply_storage::ReplyStorageBackend; use crate::client::replies::reply_storage::ReplyStorageBackend;
@@ -65,7 +63,7 @@ pub trait MixnetClientStorage {
fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore; fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore;
} }
#[derive(Clone)] #[derive(Default)]
pub struct Ephemeral { pub struct Ephemeral {
key_store: InMemEphemeralKeys, key_store: InMemEphemeralKeys,
reply_store: reply_storage::Empty, reply_store: reply_storage::Empty,
@@ -73,14 +71,9 @@ pub struct Ephemeral {
gateway_details_store: InMemGatewaysDetails, gateway_details_store: InMemGatewaysDetails,
} }
impl Default for Ephemeral { impl Ephemeral {
fn default() -> Self { pub fn new() -> Self {
Ephemeral { Default::default()
key_store: InMemEphemeralKeys::new(&mut OsRng),
reply_store: Default::default(),
credential_store: Default::default(),
gateway_details_store: Default::default(),
}
} }
} }
@@ -121,7 +114,6 @@ impl MixnetClientStorage for Ephemeral {
} }
} }
#[derive(Clone)]
#[cfg(all( #[cfg(all(
not(target_arch = "wasm32"), not(target_arch = "wasm32"),
feature = "fs-surb-storage", feature = "fs-surb-storage",
@@ -13,7 +13,6 @@ use nym_sphinx::cover::generate_loop_cover_packet;
use nym_sphinx::params::{PacketSize, PacketType}; use nym_sphinx::params::{PacketSize, PacketType};
use nym_sphinx::utils::sample_poisson_duration; use nym_sphinx::utils::sample_poisson_duration;
use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender}; use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender};
use nym_task::TaskClient;
use rand::{rngs::OsRng, CryptoRng, Rng}; use rand::{rngs::OsRng, CryptoRng, Rng};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
@@ -65,8 +64,6 @@ where
packet_type: PacketType, packet_type: PacketType,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
} }
impl<R> Stream for LoopCoverTrafficStream<R> impl<R> Stream for LoopCoverTrafficStream<R>
@@ -113,7 +110,6 @@ impl LoopCoverTrafficStream<OsRng> {
traffic_config: config::Traffic, traffic_config: config::Traffic,
cover_config: config::CoverTraffic, cover_config: config::CoverTraffic,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
) -> Self { ) -> Self {
let rng = OsRng; let rng = OsRng;
@@ -132,7 +128,6 @@ impl LoopCoverTrafficStream<OsRng> {
secondary_packet_size: traffic_config.secondary_packet_size, secondary_packet_size: traffic_config.secondary_packet_size,
packet_type: traffic_config.packet_type, packet_type: traffic_config.packet_type,
stats_tx, stats_tx,
task_client,
} }
} }
@@ -180,7 +175,7 @@ impl LoopCoverTrafficStream<OsRng> {
} }
}; };
let cover_message = match generate_loop_cover_packet( let cover_message = generate_loop_cover_packet(
&mut self.rng, &mut self.rng,
topology_ref, topology_ref,
&self.ack_key, &self.ack_key,
@@ -189,15 +184,8 @@ impl LoopCoverTrafficStream<OsRng> {
self.cover_traffic.loop_cover_traffic_average_delay, self.cover_traffic.loop_cover_traffic_average_delay,
cover_traffic_packet_size, cover_traffic_packet_size,
self.packet_type, self.packet_type,
) { )
Ok(cover_message) => cover_message, .expect("Somehow failed to generate a loop cover message with a valid topology");
Err(err) => {
warn!(
"Somehow failed to generate a loop cover message with a valid topology: {err}"
);
return;
}
};
if let Err(err) = self.mix_tx.try_send(vec![cover_message]) { if let Err(err) = self.mix_tx.try_send(vec![cover_message]) {
match err { match err {
@@ -229,7 +217,7 @@ impl LoopCoverTrafficStream<OsRng> {
tokio::task::yield_now().await; tokio::task::yield_now().await;
} }
pub fn start(mut self) { pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
if self.cover_traffic.disable_loop_cover_traffic_stream { if self.cover_traffic.disable_loop_cover_traffic_stream {
// we should have never got here in the first place - the task should have never been created to begin with // we should have never got here in the first place - the task should have never been created to begin with
// so panic and review the code that lead to this branch // so panic and review the code that lead to this branch
@@ -243,8 +231,6 @@ impl LoopCoverTrafficStream<OsRng> {
); );
self.set_next_delay(sampled); self.set_next_delay(sampled);
let mut shutdown = self.task_client.fork("select");
spawn_future(async move { spawn_future(async move {
debug!("Started LoopCoverTrafficStream with graceful shutdown support"); debug!("Started LoopCoverTrafficStream with graceful shutdown support");
@@ -28,7 +28,6 @@ pub enum InputMessage {
recipient: Recipient, recipient: Recipient,
data: Vec<u8>, data: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
max_retransmissions: Option<u32>,
}, },
/// Creates a message used for a duplex anonymous communication where the recipient /// Creates a message used for a duplex anonymous communication where the recipient
@@ -44,7 +43,6 @@ pub enum InputMessage {
data: Vec<u8>, data: Vec<u8>,
reply_surbs: u32, reply_surbs: u32,
lane: TransmissionLane, lane: TransmissionLane,
max_retransmissions: Option<u32>,
}, },
/// Attempt to use our internally received and stored `ReplySurb` to send the message back /// Attempt to use our internally received and stored `ReplySurb` to send the message back
@@ -55,7 +53,6 @@ pub enum InputMessage {
recipient_tag: AnonymousSenderTag, recipient_tag: AnonymousSenderTag,
data: Vec<u8>, data: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
max_retransmissions: Option<u32>,
}, },
MessageWrapper { MessageWrapper {
@@ -95,7 +92,6 @@ impl InputMessage {
recipient, recipient,
data, data,
lane, lane,
max_retransmissions: None,
}; };
if let Some(packet_type) = packet_type { if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type) InputMessage::new_wrapper(message, packet_type)
@@ -116,7 +112,28 @@ impl InputMessage {
data, data,
reply_surbs, reply_surbs,
lane, lane,
max_retransmissions: None, };
if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type)
} else {
message
}
}
// IMHO `new_anonymous` should take `mix_hops: Option<u8>` as an argument instead of creating
// this function, but that would potentially break backwards compatibility with the current API
pub fn new_anonymous_with_custom_hops(
recipient: Recipient,
data: Vec<u8>,
reply_surbs: u32,
lane: TransmissionLane,
packet_type: Option<PacketType>,
) -> Self {
let message = InputMessage::Anonymous {
recipient,
data,
reply_surbs,
lane,
}; };
if let Some(packet_type) = packet_type { if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type) InputMessage::new_wrapper(message, packet_type)
@@ -135,7 +152,6 @@ impl InputMessage {
recipient_tag, recipient_tag,
data, data,
lane, lane,
max_retransmissions: None,
}; };
if let Some(packet_type) = packet_type { if let Some(packet_type) = packet_type {
InputMessage::new_wrapper(message, packet_type) InputMessage::new_wrapper(message, packet_type)
@@ -153,34 +169,4 @@ impl InputMessage {
InputMessage::MessageWrapper { message, .. } => message.lane(), InputMessage::MessageWrapper { message, .. } => message.lane(),
} }
} }
pub fn set_max_retransmissions(&mut self, max_retransmissions: u32) -> &mut Self {
match self {
InputMessage::Regular {
max_retransmissions: m,
..
}
| InputMessage::Anonymous {
max_retransmissions: m,
..
}
| InputMessage::Reply {
max_retransmissions: m,
..
} => {
*m = Some(max_retransmissions);
}
InputMessage::Premade { .. } => {}
InputMessage::MessageWrapper { message, .. } => {
message.set_max_retransmissions(max_retransmissions);
}
}
self
}
pub fn with_max_retransmissions(mut self, max_retransmissions: u32) -> Self {
self.set_max_retransmissions(max_retransmissions);
self
}
} }
@@ -2,10 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::key_manager::persistence::KeyStore; use crate::client::key_manager::persistence::KeyStore;
use nym_crypto::{ use nym_crypto::asymmetric::{encryption, identity};
asymmetric::{encryption, identity},
hkdf::{DerivationMaterial, InvalidLength},
};
use nym_gateway_requests::shared_key::{LegacySharedKeys, SharedGatewayKey, SharedSymmetricKey}; use nym_gateway_requests::shared_key::{LegacySharedKeys, SharedGatewayKey, SharedSymmetricKey};
use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::acknowledgements::AckKey;
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, RngCore};
@@ -13,7 +10,6 @@ use std::sync::Arc;
use zeroize::ZeroizeOnDrop; use zeroize::ZeroizeOnDrop;
pub mod persistence; pub mod persistence;
mod test;
// Note: to support key rotation in the future, all keys will require adding an extra smart pointer, // Note: to support key rotation in the future, all keys will require adding an extra smart pointer,
// most likely an AtomicCell, or if it doesn't work as I think it does, a Mutex. Although I think // most likely an AtomicCell, or if it doesn't work as I think it does, a Mutex. Although I think
@@ -47,24 +43,6 @@ impl ClientKeys {
} }
} }
pub fn from_master_key<R>(
rng: &mut R,
derivation_material: &DerivationMaterial,
) -> Result<Self, InvalidLength>
where
R: RngCore + CryptoRng,
{
let secret = derivation_material.derive_secret()?;
Ok(ClientKeys {
identity_keypair: Arc::new(identity::KeyPair::from_secret(
secret,
derivation_material.index(),
)),
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
ack_key: Arc::new(AckKey::new(rng)),
})
}
pub fn from_keys( pub fn from_keys(
id_keypair: identity::KeyPair, id_keypair: identity::KeyPair,
enc_keypair: encryption::KeyPair, enc_keypair: encryption::KeyPair,
@@ -3,9 +3,7 @@
use crate::client::key_manager::ClientKeys; use crate::client::key_manager::ClientKeys;
use async_trait::async_trait; use async_trait::async_trait;
use rand::{CryptoRng, RngCore};
use std::error::Error; use std::error::Error;
use std::sync::Arc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@@ -66,7 +64,6 @@ pub enum OnDiskKeysError {
}, },
} }
#[derive(Clone)]
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub struct OnDiskKeys { pub struct OnDiskKeys {
paths: ClientKeysPaths, paths: ClientKeysPaths,
@@ -196,20 +193,9 @@ impl KeyStore for OnDiskKeys {
} }
} }
#[derive(Clone)] #[derive(Default)]
pub struct InMemEphemeralKeys { pub struct InMemEphemeralKeys {
keys: Arc<Mutex<ClientKeys>>, keys: Mutex<Option<ClientKeys>>,
}
impl InMemEphemeralKeys {
pub fn new<R>(rng: &mut R) -> Self
where
R: RngCore + CryptoRng,
{
InMemEphemeralKeys {
keys: Arc::new(Mutex::new(ClientKeys::generate_new(rng))),
}
}
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@@ -222,11 +208,11 @@ impl KeyStore for InMemEphemeralKeys {
type StorageError = EphemeralKeysError; type StorageError = EphemeralKeysError;
async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> { async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
Ok(self.keys.lock().await.clone()) self.keys.lock().await.clone().ok_or(EphemeralKeysError)
} }
async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError> { async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError> {
*self.keys.lock().await = keys.clone(); *self.keys.lock().await = Some(keys.clone());
Ok(()) Ok(())
} }
} }
@@ -1,89 +0,0 @@
#[cfg(test)]
mod tests {
use crate::client::key_manager::ClientKeys;
use nym_crypto::hkdf::DerivationMaterial;
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
#[test]
fn test_from_master_key_success() {
// Set up a deterministic RNG.
let seed = [33u8; 32];
let mut rng = ChaCha20Rng::from_seed(seed);
// Set up the derivation material.
let master_key = b"this is a secret master key";
let salt = b"unique-salt";
let derivation_material = DerivationMaterial::new(master_key, 0, salt);
// Generate ClientKeys from the master key.
let client_keys = ClientKeys::from_master_key(&mut rng, &derivation_material)
.expect("Failed to create client keys");
assert_eq!(
client_keys.identity_keypair().public_key().to_string(),
String::from("FX4Undr5LPPBA7zThWWpAKXKQTXSbW1C28PnxbCqUkU4")
);
assert_eq!(
client_keys.identity_keypair().private_key().to_string(),
String::from("6S3uMi2rU5SwyUUYCiMrF5qqdcYnEDMYLggBSvavVzEt")
);
}
#[test]
fn test_from_master_key_deterministic_identity() {
// Using identical derivation material should result in the exactly same identity keypair.
let seed = [1u8; 32];
let mut rng1 = ChaCha20Rng::from_seed(seed);
let mut rng2 = ChaCha20Rng::from_seed(seed);
let master_key = b"another secret master key";
let salt = b"deterministic-salt";
let index = 7u32;
let derivation_material = DerivationMaterial::new(master_key, index, salt);
let client_keys1 = ClientKeys::from_master_key(&mut rng1, &derivation_material)
.expect("Failed to create client keys (first instance)");
let client_keys2 = ClientKeys::from_master_key(&mut rng2, &derivation_material)
.expect("Failed to create client keys (second instance)");
assert_eq!(
client_keys1.identity_keypair().public_key().to_string(),
client_keys2.identity_keypair().public_key().to_string()
);
assert_eq!(
client_keys1.identity_keypair().private_key().to_string(),
client_keys2.identity_keypair().private_key().to_string()
);
}
#[test]
fn test_from_master_key_different_indices() {
// Changing the index should yield a different identity key.
let seed = [5u8; 32];
let mut rng = ChaCha20Rng::from_seed(seed);
let master_key = b"same secret key";
let salt = b"same-salt";
let derivation_material1 = DerivationMaterial::new(master_key, 1, salt);
let derivation_material2 = DerivationMaterial::new(master_key, 2, salt);
let client_keys1 = ClientKeys::from_master_key(&mut rng, &derivation_material1)
.expect("Failed to create client keys for index 1");
let client_keys2 = ClientKeys::from_master_key(&mut rng, &derivation_material2)
.expect("Failed to create client keys for index 2");
assert_ne!(
client_keys1.identity_keypair().public_key().to_string(),
client_keys2.identity_keypair().public_key().to_string()
);
assert_ne!(
client_keys1.identity_keypair().private_key().to_string(),
client_keys2.identity_keypair().private_key().to_string()
);
}
}
@@ -2,18 +2,13 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::mix_traffic::transceiver::GatewayTransceiver; use crate::client::mix_traffic::transceiver::GatewayTransceiver;
use crate::error::ClientCoreError; use crate::{spawn_future, ForgetMe};
use crate::spawn_future;
use log::*; use log::*;
use nym_gateway_requests::ClientRequest; use nym_gateway_requests::ClientRequest;
use nym_sphinx::forwarding::packet::MixPacket; use nym_sphinx::forwarding::packet::MixPacket;
use nym_task::TaskClient;
use transceiver::ErasedGatewayError;
pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>; pub type BatchMixMessageSender = tokio::sync::mpsc::Sender<Vec<MixPacket>>;
pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>; pub type BatchMixMessageReceiver = tokio::sync::mpsc::Receiver<Vec<MixPacket>>;
pub type ClientRequestReceiver = tokio::sync::mpsc::Receiver<ClientRequest>;
pub type ClientRequestSender = tokio::sync::mpsc::Sender<ClientRequest>;
pub mod transceiver; pub mod transceiver;
@@ -28,73 +23,52 @@ pub struct MixTrafficController {
gateway_transceiver: Box<dyn GatewayTransceiver + Send>, gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
mix_rx: BatchMixMessageReceiver, mix_rx: BatchMixMessageReceiver,
client_rx: ClientRequestReceiver,
// TODO: this is temporary work-around. // TODO: this is temporary work-around.
// in long run `gateway_client` will be moved away from `MixTrafficController` anyway. // in long run `gateway_client` will be moved away from `MixTrafficController` anyway.
consecutive_gateway_failure_count: usize, consecutive_gateway_failure_count: usize,
forget_me: ForgetMe,
task_client: TaskClient,
} }
impl MixTrafficController { impl MixTrafficController {
pub fn new<T>( pub fn new<T>(
gateway_transceiver: T, gateway_transceiver: T,
task_client: TaskClient, forget_me: ForgetMe,
) -> ( ) -> (MixTrafficController, BatchMixMessageSender)
MixTrafficController,
BatchMixMessageSender,
ClientRequestSender,
)
where where
T: GatewayTransceiver + Send + 'static, T: GatewayTransceiver + Send + 'static,
{ {
let (message_sender, message_receiver) = let (message_sender, message_receiver) =
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE); tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
let (client_sender, client_receiver) = tokio::sync::mpsc::channel(8);
( (
MixTrafficController { MixTrafficController {
gateway_transceiver: Box::new(gateway_transceiver), gateway_transceiver: Box::new(gateway_transceiver),
mix_rx: message_receiver, mix_rx: message_receiver,
client_rx: client_receiver,
consecutive_gateway_failure_count: 0, consecutive_gateway_failure_count: 0,
task_client, forget_me,
}, },
message_sender, message_sender,
client_sender,
) )
} }
pub fn new_dynamic( pub fn new_dynamic(
gateway_transceiver: Box<dyn GatewayTransceiver + Send>, gateway_transceiver: Box<dyn GatewayTransceiver + Send>,
task_client: TaskClient, forget_me: ForgetMe,
) -> ( ) -> (MixTrafficController, BatchMixMessageSender) {
MixTrafficController,
BatchMixMessageSender,
ClientRequestSender,
) {
let (message_sender, message_receiver) = let (message_sender, message_receiver) =
tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE); tokio::sync::mpsc::channel(MIX_MESSAGE_RECEIVER_BUFFER_SIZE);
let (client_sender, client_receiver) = tokio::sync::mpsc::channel(8);
( (
MixTrafficController { MixTrafficController {
gateway_transceiver, gateway_transceiver,
mix_rx: message_receiver, mix_rx: message_receiver,
client_rx: client_receiver,
consecutive_gateway_failure_count: 0, consecutive_gateway_failure_count: 0,
task_client, forget_me,
}, },
message_sender, message_sender,
client_sender,
) )
} }
async fn on_messages( async fn on_messages(&mut self, mut mix_packets: Vec<MixPacket>) {
&mut self,
mut mix_packets: Vec<MixPacket>,
) -> Result<(), ErasedGatewayError> {
debug_assert!(!mix_packets.is_empty()); debug_assert!(!mix_packets.is_empty());
let result = if mix_packets.len() == 1 { let result = if mix_packets.len() == 1 {
@@ -106,60 +80,64 @@ impl MixTrafficController {
.await .await
}; };
if result.is_err() { match result {
self.consecutive_gateway_failure_count += 1; Err(err) => {
} else { error!("Failed to send sphinx packet(s) to the gateway: {err}");
trace!("We *might* have managed to forward sphinx packet(s) to the gateway!"); self.consecutive_gateway_failure_count += 1;
self.consecutive_gateway_failure_count = 0; if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
// todo: in the future this should initiate a 'graceful' shutdown or try
// to reconnect?
panic!("failed to send sphinx packet to the gateway {MAX_FAILURE_COUNT} times in a row - assuming the gateway is dead. Can't do anything about it yet :(")
}
}
Ok(_) => {
trace!("We *might* have managed to forward sphinx packet(s) to the gateway!");
self.consecutive_gateway_failure_count = 0;
}
} }
result
} }
pub fn start(mut self) { pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
spawn_future(async move { spawn_future(async move {
debug!("Started MixTrafficController with graceful shutdown support"); debug!("Started MixTrafficController with graceful shutdown support");
while !self.task_client.is_shutdown() { loop {
tokio::select! { tokio::select! {
mix_packets = self.mix_rx.recv() => match mix_packets { mix_packets = self.mix_rx.recv() => match mix_packets {
Some(mix_packets) => { Some(mix_packets) => {
if let Err(err) = self.on_messages(mix_packets).await { self.on_messages(mix_packets).await;
error!("Failed to send sphinx packet(s) to the gateway: {err}");
if self.consecutive_gateway_failure_count == MAX_FAILURE_COUNT {
// Disconnect from the gateway. If we should try to re-connect
// is handled at a higher layer.
error!("Failed to send sphinx packet to the gateway {MAX_FAILURE_COUNT} times in a row - assuming the gateway is dead");
// Do we need to handle the embedded mixnet client case
// separately?
self.task_client.send_we_stopped(Box::new(ClientCoreError::GatewayFailedToForwardMessages));
break;
}
}
}, },
None => { None => {
log::trace!("MixTrafficController: Stopping since channel closed"); log::trace!("MixTrafficController: Stopping since channel closed");
break; break;
} }
}, },
client_request = self.client_rx.recv() => match client_request { _ = shutdown.recv_with_delay() => {
Some(client_request) => {
match self.gateway_transceiver.send_client_request(client_request).await {
Ok(_) => (),
Err(e) => error!("Failed to send client request: {}", e),
};
},
None => {
log::trace!("MixTrafficController, client request channel closed");
}
},
_ = self.task_client.recv() => {
log::trace!("MixTrafficController: Received shutdown"); log::trace!("MixTrafficController: Received shutdown");
break; break;
} }
} }
} }
self.task_client.recv_timeout().await; shutdown.recv_timeout().await;
if self.forget_me.any() {
log::info!("Sending forget me request to the gateway");
match self
.gateway_transceiver
.send_client_request(ClientRequest::ForgetMe {
client: self.forget_me.client(),
stats: self.forget_me.stats(),
})
.await
{
Ok(_) => {
log::info!("Successfully sent forget me request to the gateway");
}
Err(err) => {
log::error!("Failed to send forget me request to the gateway: {err}");
}
}
}
log::debug!("MixTrafficController: Exiting"); log::debug!("MixTrafficController: Exiting");
}); });
@@ -86,9 +86,7 @@ impl<G: GatewayTransceiver + ?Sized + Send> GatewayTransceiver for Box<G> {
&mut self, &mut self,
message: ClientRequest, message: ClientRequest,
) -> Result<(), GatewayClientError> { ) -> Result<(), GatewayClientError> {
let _ = (**self).send_client_request(message.clone()).await?; (**self).send_client_request(message).await
log::debug!("Sent client request: {:?}", message);
Ok(())
} }
} }
@@ -145,7 +143,14 @@ where
&mut self, &mut self,
message: ClientRequest, message: ClientRequest,
) -> Result<(), GatewayClientError> { ) -> Result<(), GatewayClientError> {
self.gateway_client.send_client_request(message).await if let Some(shared_key) = self.gateway_client.shared_key() {
self.gateway_client
.send_websocket_message(message.encrypt(&*shared_key)?)
.await?;
Ok(())
} else {
Err(GatewayClientError::ConnectionInInvalidState)
}
} }
} }
@@ -11,7 +11,6 @@ use nym_sphinx::{
acknowledgements::{identifier::recover_identifier, AckKey}, acknowledgements::{identifier::recover_identifier, AckKey},
chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID}, chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID},
}; };
use nym_task::TaskClient;
use std::sync::Arc; use std::sync::Arc;
/// Module responsible for listening for any data resembling acknowledgements from the network /// Module responsible for listening for any data resembling acknowledgements from the network
@@ -21,7 +20,6 @@ pub(super) struct AcknowledgementListener {
ack_receiver: AcknowledgementReceiver, ack_receiver: AcknowledgementReceiver,
action_sender: AckActionSender, action_sender: AckActionSender,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
} }
impl AcknowledgementListener { impl AcknowledgementListener {
@@ -30,14 +28,12 @@ impl AcknowledgementListener {
ack_receiver: AcknowledgementReceiver, ack_receiver: AcknowledgementReceiver,
action_sender: AckActionSender, action_sender: AckActionSender,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
) -> Self { ) -> Self {
AcknowledgementListener { AcknowledgementListener {
ack_key, ack_key,
ack_receiver, ack_receiver,
action_sender, action_sender,
stats_tx, stats_tx,
task_client,
} }
} }
@@ -68,14 +64,9 @@ impl AcknowledgementListener {
trace!("Received {} from the mix network", frag_id); trace!("Received {} from the mix network", frag_id);
self.stats_tx self.stats_tx
.report(PacketStatisticsEvent::RealAckReceived(ack_content.len()).into()); .report(PacketStatisticsEvent::RealAckReceived(ack_content.len()).into());
if let Err(err) = self self.action_sender
.action_sender
.unbounded_send(Action::new_remove(frag_id)) .unbounded_send(Action::new_remove(frag_id))
{ .unwrap();
if !self.task_client.is_shutdown_poll() {
error!("Failed to send remove action to action controller: {err}");
}
}
} }
async fn handle_ack_receiver_item(&mut self, item: Vec<Vec<u8>>) { async fn handle_ack_receiver_item(&mut self, item: Vec<Vec<u8>>) {
@@ -85,10 +76,10 @@ impl AcknowledgementListener {
} }
} }
pub(super) async fn run(&mut self) { pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
debug!("Started AcknowledgementListener with graceful shutdown support"); debug!("Started AcknowledgementListener with graceful shutdown support");
while !self.task_client.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
acks = self.ack_receiver.next() => match acks { acks = self.ack_receiver.next() => match acks {
Some(acks) => self.handle_ack_receiver_item(acks).await, Some(acks) => self.handle_ack_receiver_item(acks).await,
@@ -97,12 +88,12 @@ impl AcknowledgementListener {
break; break;
} }
}, },
_ = self.task_client.recv() => { _ = shutdown.recv_with_delay() => {
log::trace!("AcknowledgementListener: Received shutdown"); log::trace!("AcknowledgementListener: Received shutdown");
} }
} }
} }
self.task_client.recv_timeout().await; shutdown.recv_timeout().await;
log::debug!("AcknowledgementListener: Exiting"); log::debug!("AcknowledgementListener: Exiting");
} }
} }
@@ -9,7 +9,6 @@ use log::*;
use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey}; use nym_nonexhaustive_delayqueue::{Expired, NonExhaustiveDelayQueue, QueueKey};
use nym_sphinx::chunking::fragment::FragmentIdentifier; use nym_sphinx::chunking::fragment::FragmentIdentifier;
use nym_sphinx::Delay as SphinxDelay; use nym_sphinx::Delay as SphinxDelay;
use nym_task::TaskClient;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
@@ -102,8 +101,6 @@ pub(super) struct ActionController {
/// Channel for notifying `RetransmissionRequestListener` about expired acknowledgements. /// Channel for notifying `RetransmissionRequestListener` about expired acknowledgements.
retransmission_sender: RetransmissionRequestSender, retransmission_sender: RetransmissionRequestSender,
task_client: TaskClient,
} }
impl ActionController { impl ActionController {
@@ -111,7 +108,6 @@ impl ActionController {
config: Config, config: Config,
retransmission_sender: RetransmissionRequestSender, retransmission_sender: RetransmissionRequestSender,
incoming_actions: AckActionReceiver, incoming_actions: AckActionReceiver,
task_client: TaskClient,
) -> Self { ) -> Self {
ActionController { ActionController {
config, config,
@@ -119,7 +115,6 @@ impl ActionController {
pending_acks_timers: NonExhaustiveDelayQueue::new(), pending_acks_timers: NonExhaustiveDelayQueue::new(),
incoming_actions, incoming_actions,
retransmission_sender, retransmission_sender,
task_client,
} }
} }
@@ -221,7 +216,14 @@ impl ActionController {
} }
// note: when the entry expires it's automatically removed from pending_acks_timers // note: when the entry expires it's automatically removed from pending_acks_timers
fn handle_expired_ack_timer(&mut self, expired_ack: Expired<FragmentIdentifier>) { fn handle_expired_ack_timer(
&mut self,
expired_ack: Expired<FragmentIdentifier>,
task_client: &mut nym_task::TaskClient,
) {
// I'm honestly not sure how to handle it, because getting it means other things in our
// system are already misbehaving. If we ever see this panic, then I guess we should worry
// about it. Perhaps just reschedule it at later point?
let frag_id = expired_ack.into_inner(); let frag_id = expired_ack.into_inner();
trace!("{frag_id} has expired"); trace!("{frag_id} has expired");
@@ -236,13 +238,15 @@ impl ActionController {
// downgrading an arc and then upgrading vs cloning is difference of 30ns vs 15ns // downgrading an arc and then upgrading vs cloning is difference of 30ns vs 15ns
// so it's literally a NO difference while it might prevent us from unnecessarily // so it's literally a NO difference while it might prevent us from unnecessarily
// resending data (in maybe 1 in 1 million cases, but it's something) // resending data (in maybe 1 in 1 million cases, but it's something)
if let Err(err) = self if self
.retransmission_sender .retransmission_sender
.unbounded_send(Arc::downgrade(pending_ack_data)) .unbounded_send(Arc::downgrade(pending_ack_data))
.is_err()
{ {
if !self.task_client.is_shutdown_poll() { assert!(
log::error!("Failed to send pending ack for retransmission: {err}"); task_client.is_shutdown_poll(),
} "Failed to send pending ack for retransmission"
);
} }
} else { } else {
// this shouldn't cause any issues but shouldn't have happened to begin with! // this shouldn't cause any issues but shouldn't have happened to begin with!
@@ -261,10 +265,10 @@ impl ActionController {
} }
} }
pub(super) async fn run(&mut self) { pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
debug!("Started ActionController with graceful shutdown support"); debug!("Started ActionController with graceful shutdown support");
while !self.task_client.is_shutdown() { loop {
tokio::select! { tokio::select! {
action = self.incoming_actions.next() => match action { action = self.incoming_actions.next() => match action {
Some(action) => self.process_action(action), Some(action) => self.process_action(action),
@@ -276,19 +280,19 @@ impl ActionController {
} }
}, },
expired_ack = self.pending_acks_timers.next() => match expired_ack { expired_ack = self.pending_acks_timers.next() => match expired_ack {
Some(expired_ack) => self.handle_expired_ack_timer(expired_ack), Some(expired_ack) => self.handle_expired_ack_timer(expired_ack, &mut shutdown),
None => { None => {
log::trace!("ActionController: Stopping since ack channel closed"); log::trace!("ActionController: Stopping since ack channel closed");
break; break;
} }
}, },
_ = self.task_client.recv() => { _ = shutdown.recv_with_delay() => {
log::trace!("ActionController: Received shutdown"); log::trace!("ActionController: Received shutdown");
break; break;
} }
} }
} }
self.task_client.recv_timeout().await; shutdown.recv_timeout().await;
log::debug!("ActionController: Exiting"); log::debug!("ActionController: Exiting");
} }
} }
@@ -11,7 +11,6 @@ use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::forwarding::packet::MixPacket; use nym_sphinx::forwarding::packet::MixPacket;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketType;
use nym_task::connections::TransmissionLane; use nym_task::connections::TransmissionLane;
use nym_task::TaskClient;
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
/// Module responsible for dealing with the received messages: splitting them, creating acknowledgements, /// Module responsible for dealing with the received messages: splitting them, creating acknowledgements,
@@ -24,7 +23,6 @@ where
input_receiver: InputMessageReceiver, input_receiver: InputMessageReceiver,
message_handler: MessageHandler<R>, message_handler: MessageHandler<R>,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
task_client: TaskClient,
} }
impl<R> InputMessageListener<R> impl<R> InputMessageListener<R>
@@ -38,13 +36,11 @@ where
input_receiver: InputMessageReceiver, input_receiver: InputMessageReceiver,
message_handler: MessageHandler<R>, message_handler: MessageHandler<R>,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
task_client: TaskClient,
) -> Self { ) -> Self {
InputMessageListener { InputMessageListener {
input_receiver, input_receiver,
message_handler, message_handler,
reply_controller_sender, reply_controller_sender,
task_client,
} }
} }
@@ -65,17 +61,10 @@ where
recipient_tag: AnonymousSenderTag, recipient_tag: AnonymousSenderTag,
data: Vec<u8>, data: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
max_retransmissions: Option<u32>,
) { ) {
// offload reply handling to the dedicated task // offload reply handling to the dedicated task
if let Err(err) = self.reply_controller_sender
self.reply_controller_sender .send_reply(recipient_tag, data, lane)
.send_reply(recipient_tag, data, lane, max_retransmissions)
{
if !self.task_client.is_shutdown_poll() {
error!("failed to send a reply - {err}");
}
}
} }
async fn handle_plain_message( async fn handle_plain_message(
@@ -84,11 +73,10 @@ where
content: Vec<u8>, content: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType, packet_type: PacketType,
max_retransmissions: Option<u32>,
) { ) {
if let Err(err) = self if let Err(err) = self
.message_handler .message_handler
.try_send_plain_message(recipient, content, lane, packet_type, max_retransmissions) .try_send_plain_message(recipient, content, lane, packet_type)
.await .await
{ {
warn!("failed to send a plain message - {err}") warn!("failed to send a plain message - {err}")
@@ -102,18 +90,10 @@ where
reply_surbs: u32, reply_surbs: u32,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType, packet_type: PacketType,
max_retransmissions: Option<u32>,
) { ) {
if let Err(err) = self if let Err(err) = self
.message_handler .message_handler
.try_send_message_with_reply_surbs( .try_send_message_with_reply_surbs(recipient, content, reply_surbs, lane, packet_type)
recipient,
content,
reply_surbs,
lane,
packet_type,
max_retransmissions,
)
.await .await
{ {
warn!("failed to send a repliable message - {err}") warn!("failed to send a repliable message - {err}")
@@ -126,42 +106,25 @@ where
recipient, recipient,
data, data,
lane, lane,
max_retransmissions,
} => { } => {
self.handle_plain_message( self.handle_plain_message(recipient, data, lane, PacketType::Mix)
recipient, .await
data,
lane,
PacketType::Mix,
max_retransmissions,
)
.await
} }
InputMessage::Anonymous { InputMessage::Anonymous {
recipient, recipient,
data, data,
reply_surbs, reply_surbs,
lane, lane,
max_retransmissions,
} => { } => {
self.handle_repliable_message( self.handle_repliable_message(recipient, data, reply_surbs, lane, PacketType::Mix)
recipient, .await
data,
reply_surbs,
lane,
PacketType::Mix,
max_retransmissions,
)
.await
} }
InputMessage::Reply { InputMessage::Reply {
recipient_tag, recipient_tag,
data, data,
lane, lane,
max_retransmissions,
} => { } => {
self.handle_reply(recipient_tag, data, lane, max_retransmissions) self.handle_reply(recipient_tag, data, lane).await;
.await;
} }
InputMessage::Premade { msgs, lane } => self.handle_premade_packets(msgs, lane).await, InputMessage::Premade { msgs, lane } => self.handle_premade_packets(msgs, lane).await,
InputMessage::MessageWrapper { InputMessage::MessageWrapper {
@@ -172,42 +135,25 @@ where
recipient, recipient,
data, data,
lane, lane,
max_retransmissions,
} => { } => {
self.handle_plain_message( self.handle_plain_message(recipient, data, lane, packet_type)
recipient, .await
data,
lane,
packet_type,
max_retransmissions,
)
.await
} }
InputMessage::Anonymous { InputMessage::Anonymous {
recipient, recipient,
data, data,
reply_surbs, reply_surbs,
lane, lane,
max_retransmissions,
} => { } => {
self.handle_repliable_message( self.handle_repliable_message(recipient, data, reply_surbs, lane, packet_type)
recipient, .await
data,
reply_surbs,
lane,
packet_type,
max_retransmissions,
)
.await
} }
InputMessage::Reply { InputMessage::Reply {
recipient_tag, recipient_tag,
data, data,
lane, lane,
max_retransmissions,
} => { } => {
self.handle_reply(recipient_tag, data, lane, max_retransmissions) self.handle_reply(recipient_tag, data, lane).await;
.await;
} }
InputMessage::Premade { msgs, lane } => { InputMessage::Premade { msgs, lane } => {
self.handle_premade_packets(msgs, lane).await self.handle_premade_packets(msgs, lane).await
@@ -218,10 +164,10 @@ where
}; };
} }
pub(super) async fn run(&mut self) { pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
debug!("Started InputMessageListener with graceful shutdown support"); debug!("Started InputMessageListener with graceful shutdown support");
while !self.task_client.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
input_msg = self.input_receiver.recv() => match input_msg { input_msg = self.input_receiver.recv() => match input_msg {
Some(input_msg) => { Some(input_msg) => {
@@ -232,12 +178,12 @@ where
break; break;
} }
}, },
_ = self.task_client.recv() => { _ = shutdown.recv_with_delay() => {
log::trace!("InputMessageListener: Received shutdown"); log::trace!("InputMessageListener: Received shutdown");
} }
} }
} }
self.task_client.recv_timeout().await; shutdown.recv_timeout().await;
log::debug!("InputMessageListener: Exiting"); log::debug!("InputMessageListener: Exiting");
} }
} }
@@ -24,7 +24,6 @@ use nym_sphinx::{
Delay as SphinxDelay, Delay as SphinxDelay,
}; };
use nym_statistics_common::clients::ClientStatsSender; use nym_statistics_common::clients::ClientStatsSender;
use nym_task::TaskClient;
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
use std::{ use std::{
sync::{Arc, Weak}, sync::{Arc, Weak},
@@ -67,12 +66,11 @@ pub(crate) enum PacketDestination {
/// 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`
#[derive(Debug)] #[derive(Debug)]
pub struct PendingAcknowledgement { pub(crate) struct PendingAcknowledgement {
message_chunk: Fragment, message_chunk: Fragment,
delay: SphinxDelay, delay: SphinxDelay,
destination: PacketDestination, destination: PacketDestination,
retransmissions: u32, retransmissions: u32,
max_retransmissions: Option<u32>,
} }
impl PendingAcknowledgement { impl PendingAcknowledgement {
@@ -81,14 +79,12 @@ impl PendingAcknowledgement {
message_chunk: Fragment, message_chunk: Fragment,
delay: SphinxDelay, delay: SphinxDelay,
recipient: Recipient, recipient: Recipient,
max_retransmissions: Option<u32>,
) -> Self { ) -> Self {
PendingAcknowledgement { PendingAcknowledgement {
message_chunk, message_chunk,
delay, delay,
destination: PacketDestination::KnownRecipient(recipient.into()), destination: PacketDestination::KnownRecipient(recipient.into()),
retransmissions: 0, retransmissions: 0,
max_retransmissions,
} }
} }
@@ -97,7 +93,6 @@ impl PendingAcknowledgement {
delay: SphinxDelay, delay: SphinxDelay,
recipient_tag: AnonymousSenderTag, recipient_tag: AnonymousSenderTag,
extra_surb_request: bool, extra_surb_request: bool,
max_retransmissions: Option<u32>,
) -> Self { ) -> Self {
PendingAcknowledgement { PendingAcknowledgement {
message_chunk, message_chunk,
@@ -107,7 +102,6 @@ impl PendingAcknowledgement {
extra_surb_request, extra_surb_request,
}, },
retransmissions: 0, retransmissions: 0,
max_retransmissions,
} }
} }
@@ -123,18 +117,6 @@ impl PendingAcknowledgement {
self.delay = new_delay; self.delay = new_delay;
self.retransmissions += 1; self.retransmissions += 1;
} }
pub(crate) fn reached_max_retransmissions(
&self,
global_max_retransmissions: Option<u32>,
) -> bool {
let reached_local_max = self
.max_retransmissions
.is_some_and(|limit| self.retransmissions >= limit);
let reached_global_max =
global_max_retransmissions.is_some_and(|limit| self.retransmissions >= limit);
reached_local_max || reached_global_max
}
} }
/// AcknowledgementControllerConnectors represents set of channels for communication with /// AcknowledgementControllerConnectors represents set of channels for communication with
@@ -234,7 +216,6 @@ where
message_handler: MessageHandler<R>, message_handler: MessageHandler<R>,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
) -> Self { ) -> Self {
let (retransmission_tx, retransmission_rx) = mpsc::unbounded(); let (retransmission_tx, retransmission_rx) = mpsc::unbounded();
@@ -244,7 +225,6 @@ where
action_config, action_config,
retransmission_tx, retransmission_tx,
connectors.ack_action_receiver, connectors.ack_action_receiver,
task_client.fork("action_controller"),
); );
// will listen for any acks coming from the network // will listen for any acks coming from the network
@@ -253,7 +233,6 @@ where
connectors.ack_receiver, connectors.ack_receiver,
connectors.ack_action_sender.clone(), connectors.ack_action_sender.clone(),
stats_tx, stats_tx,
task_client.fork("acknowledgement_listener"),
); );
// will listen for any new messages from the client // will listen for any new messages from the client
@@ -261,7 +240,6 @@ where
connectors.input_receiver, connectors.input_receiver,
message_handler.clone(), message_handler.clone(),
reply_controller_sender.clone(), reply_controller_sender.clone(),
task_client.fork("input_message_listener"),
); );
// will listen for any ack timeouts and trigger retransmission // will listen for any ack timeouts and trigger retransmission
@@ -271,16 +249,12 @@ where
message_handler, message_handler,
retransmission_rx, retransmission_rx,
reply_controller_sender, reply_controller_sender,
task_client.fork("retransmission_request_listener"),
); );
// will listen for events indicating the packet was sent through the network so that // will listen for events indicating the packet was sent through the network so that
// the retransmission timer should be started. // the retransmission timer should be started.
let sent_notification_listener = SentNotificationListener::new( let sent_notification_listener =
connectors.sent_notifier, SentNotificationListener::new(connectors.sent_notifier, connectors.ack_action_sender);
connectors.ack_action_sender,
task_client.with_suffix("sent_notification_listener"),
);
AcknowledgementController { AcknowledgementController {
acknowledgement_listener, acknowledgement_listener,
@@ -291,35 +265,53 @@ where
} }
} }
pub(super) fn start(self, packet_type: PacketType) { pub(super) fn start_with_shutdown(
self,
shutdown: nym_task::TaskClient,
packet_type: PacketType,
) {
let mut acknowledgement_listener = self.acknowledgement_listener; let mut acknowledgement_listener = self.acknowledgement_listener;
let mut input_message_listener = self.input_message_listener; let mut input_message_listener = self.input_message_listener;
let mut retransmission_request_listener = self.retransmission_request_listener; let mut retransmission_request_listener = self.retransmission_request_listener;
let mut sent_notification_listener = self.sent_notification_listener; let mut sent_notification_listener = self.sent_notification_listener;
let mut action_controller = self.action_controller; let mut action_controller = self.action_controller;
let shutdown_handle = shutdown.fork("acknowledgement_listener");
spawn_future(async move { spawn_future(async move {
acknowledgement_listener.run().await; acknowledgement_listener
.run_with_shutdown(shutdown_handle)
.await;
debug!("The acknowledgement listener has finished execution!"); debug!("The acknowledgement listener has finished execution!");
}); });
let shutdown_handle = shutdown.fork("input_message_listener");
spawn_future(async move { spawn_future(async move {
input_message_listener.run().await; input_message_listener
.run_with_shutdown(shutdown_handle)
.await;
debug!("The input listener has finished execution!"); debug!("The input listener has finished execution!");
}); });
let shutdown_handle = shutdown.fork("retransmission_request_listener");
spawn_future(async move { spawn_future(async move {
retransmission_request_listener.run(packet_type).await; retransmission_request_listener
.run_with_shutdown(shutdown_handle, packet_type)
.await;
debug!("The retransmission request listener has finished execution!"); debug!("The retransmission request listener has finished execution!");
}); });
let shutdown_handle = shutdown.fork("sent_notification_listener");
spawn_future(async move { spawn_future(async move {
sent_notification_listener.run().await; sent_notification_listener
.run_with_shutdown(shutdown_handle)
.await;
debug!("The sent notification listener has finished execution!"); debug!("The sent notification listener has finished execution!");
}); });
spawn_future(async move { spawn_future(async move {
action_controller.run().await; action_controller
.run_with_shutdown(shutdown.with_suffix("action_controller"))
.await;
debug!("The controller has finished execution!"); debug!("The controller has finished execution!");
}); });
} }
@@ -14,7 +14,7 @@ use log::*;
use nym_sphinx::chunking::fragment::Fragment; use nym_sphinx::chunking::fragment::Fragment;
use nym_sphinx::preparer::PreparedFragment; use nym_sphinx::preparer::PreparedFragment;
use nym_sphinx::{addressing::clients::Recipient, params::PacketType}; use nym_sphinx::{addressing::clients::Recipient, params::PacketType};
use nym_task::{connections::TransmissionLane, TaskClient}; use nym_task::connections::TransmissionLane;
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
@@ -25,7 +25,6 @@ pub(super) struct RetransmissionRequestListener<R> {
message_handler: MessageHandler<R>, message_handler: MessageHandler<R>,
request_receiver: RetransmissionRequestReceiver, request_receiver: RetransmissionRequestReceiver,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
task_client: TaskClient,
} }
impl<R> RetransmissionRequestListener<R> impl<R> RetransmissionRequestListener<R>
@@ -38,7 +37,6 @@ where
message_handler: MessageHandler<R>, message_handler: MessageHandler<R>,
request_receiver: RetransmissionRequestReceiver, request_receiver: RetransmissionRequestReceiver,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
task_client: TaskClient,
) -> Self { ) -> Self {
RetransmissionRequestListener { RetransmissionRequestListener {
maximum_retransmissions, maximum_retransmissions,
@@ -46,7 +44,6 @@ where
message_handler, message_handler,
request_receiver, request_receiver,
reply_controller_sender, reply_controller_sender,
task_client,
} }
} }
@@ -79,15 +76,14 @@ where
let frag_id = timed_out_ack.message_chunk.fragment_identifier(); let frag_id = timed_out_ack.message_chunk.fragment_identifier();
if timed_out_ack.reached_max_retransmissions(self.maximum_retransmissions) { if let Some(limit) = self.maximum_retransmissions {
debug!("reached maximum number of allowed retransmissions for the packet"); if timed_out_ack.retransmissions >= limit {
if let Err(err) = self warn!("reached maximum number of allowed retransmissions for the packet");
.action_sender self.action_sender
.unbounded_send(Action::new_remove(frag_id)) .unbounded_send(Action::new_remove(frag_id))
{ .unwrap();
error!("Failed to send remove action to the controller: {err}"); return;
} }
return;
} }
let maybe_prepared_fragment = match &timed_out_ack.destination { let maybe_prepared_fragment = match &timed_out_ack.destination {
@@ -97,16 +93,11 @@ where
} => { } => {
// if this is retransmission for reply, offload it to the dedicated task // if this is retransmission for reply, offload it to the dedicated task
// that deals with all the surbs // that deals with all the surbs
if let Err(err) = self.reply_controller_sender.send_retransmission_data( return self.reply_controller_sender.send_retransmission_data(
*recipient_tag, *recipient_tag,
weak_timed_out_ack, weak_timed_out_ack,
*extra_surb_request, *extra_surb_request,
) { );
if !self.task_client.is_shutdown_poll() {
error!("Failed to send retransmission data to the reply controller: {err}");
}
}
return;
} }
PacketDestination::KnownRecipient(recipient) => { PacketDestination::KnownRecipient(recipient) => {
self.prepare_normal_retransmission_chunk( self.prepare_normal_retransmission_chunk(
@@ -123,12 +114,9 @@ where
Err(err) => { Err(err) => {
warn!("Could not retransmit the packet - {err}"); warn!("Could not retransmit the packet - {err}");
// we NEED to start timer here otherwise we will have this guy permanently stuck in memory // we NEED to start timer here otherwise we will have this guy permanently stuck in memory
if let Err(err) = self self.action_sender
.action_sender
.unbounded_send(Action::new_start_timer(frag_id)) .unbounded_send(Action::new_start_timer(frag_id))
{ .unwrap();
error!("Failed to send start timer action to the controller: {err}");
}
return; return;
} }
}; };
@@ -153,14 +141,9 @@ where
// is sent to the `OutQueueControl` and has gone through its internal queue // is sent to the `OutQueueControl` and has gone through its internal queue
// with the additional poisson delay. // with the additional poisson delay.
// And since Actions are executed in order `UpdateTimer` will HAVE TO be executed before `StartTimer` // And since Actions are executed in order `UpdateTimer` will HAVE TO be executed before `StartTimer`
if let Err(err) = self self.action_sender
.action_sender
.unbounded_send(Action::new_update_pending_ack(frag_id, new_delay)) .unbounded_send(Action::new_update_pending_ack(frag_id, new_delay))
{ .unwrap();
if !self.task_client.is_shutdown_poll() {
error!("Failed to send update pending ack action to the controller: {err}");
}
}
// send to `OutQueueControl` to eventually send to the mix network // send to `OutQueueControl` to eventually send to the mix network
self.message_handler self.message_handler
@@ -174,10 +157,14 @@ where
.await .await
} }
pub(super) async fn run(&mut self, packet_type: PacketType) { pub(super) async fn run_with_shutdown(
&mut self,
mut shutdown: nym_task::TaskClient,
packet_type: PacketType,
) {
debug!("Started RetransmissionRequestListener with graceful shutdown support"); debug!("Started RetransmissionRequestListener with graceful shutdown support");
while !self.task_client.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
timed_out_ack = self.request_receiver.next() => match timed_out_ack { timed_out_ack = self.request_receiver.next() => match timed_out_ack {
Some(timed_out_ack) => self.on_retransmission_request(timed_out_ack, packet_type).await, Some(timed_out_ack) => self.on_retransmission_request(timed_out_ack, packet_type).await,
@@ -186,12 +173,12 @@ where
break; break;
} }
}, },
_ = self.task_client.recv() => { _ = shutdown.recv() => {
log::trace!("RetransmissionRequestListener: Received shutdown"); log::trace!("RetransmissionRequestListener: Received shutdown");
} }
} }
} }
self.task_client.recv_timeout().await; shutdown.recv_timeout().await;
log::debug!("RetransmissionRequestListener: Exiting"); log::debug!("RetransmissionRequestListener: Exiting");
} }
} }
@@ -6,7 +6,6 @@ use super::SentPacketNotificationReceiver;
use futures::StreamExt; use futures::StreamExt;
use log::*; use log::*;
use nym_sphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID}; use nym_sphinx::chunking::fragment::{FragmentIdentifier, COVER_FRAG_ID};
use nym_task::TaskClient;
/// Module responsible for starting up retransmission timers. /// Module responsible for starting up retransmission timers.
/// It is required because when we send our packet to the `real traffic stream` controlled /// It is required because when we send our packet to the `real traffic stream` controlled
@@ -15,19 +14,16 @@ use nym_task::TaskClient;
pub(super) struct SentNotificationListener { pub(super) struct SentNotificationListener {
sent_notifier: SentPacketNotificationReceiver, sent_notifier: SentPacketNotificationReceiver,
action_sender: AckActionSender, action_sender: AckActionSender,
task_client: TaskClient,
} }
impl SentNotificationListener { impl SentNotificationListener {
pub(super) fn new( pub(super) fn new(
sent_notifier: SentPacketNotificationReceiver, sent_notifier: SentPacketNotificationReceiver,
action_sender: AckActionSender, action_sender: AckActionSender,
task_client: TaskClient,
) -> Self { ) -> Self {
SentNotificationListener { SentNotificationListener {
sent_notifier, sent_notifier,
action_sender, action_sender,
task_client,
} }
} }
@@ -36,20 +32,15 @@ impl SentNotificationListener {
trace!("sent off a cover message - no need to start retransmission timer!"); trace!("sent off a cover message - no need to start retransmission timer!");
return; return;
} }
if let Err(err) = self self.action_sender
.action_sender
.unbounded_send(Action::new_start_timer(frag_id)) .unbounded_send(Action::new_start_timer(frag_id))
{ .unwrap();
if !self.task_client.is_shutdown_poll() {
error!("Failed to send start timer action to action controller: {err}");
}
}
} }
pub(super) async fn run(&mut self) { pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
debug!("Started SentNotificationListener with graceful shutdown support"); debug!("Started SentNotificationListener with graceful shutdown support");
while !self.task_client.is_shutdown() { loop {
tokio::select! { tokio::select! {
frag_id = self.sent_notifier.next() => match frag_id { frag_id = self.sent_notifier.next() => match frag_id {
Some(frag_id) => { Some(frag_id) => {
@@ -60,13 +51,13 @@ impl SentNotificationListener {
break; break;
} }
}, },
_ = self.task_client.recv() => { _ = shutdown.recv_with_delay() => {
log::trace!("SentNotificationListener: Received shutdown"); log::trace!("SentNotificationListener: Received shutdown");
break; break;
} }
} }
} }
assert!(self.task_client.is_shutdown_poll()); assert!(shutdown.is_shutdown_poll());
log::debug!("SentNotificationListener: Exiting"); log::debug!("SentNotificationListener: Exiting");
} }
} }
@@ -6,7 +6,6 @@ use crate::client::real_messages_control::real_traffic_stream::{
BatchRealMessageSender, RealMessage, BatchRealMessageSender, RealMessage,
}; };
use crate::client::real_messages_control::{AckActionSender, Action}; use crate::client::real_messages_control::{AckActionSender, Action};
use crate::client::replies::reply_controller::MaxRetransmissions;
use crate::client::replies::reply_storage::{ReceivedReplySurbsMap, SentReplyKeys, UsedSenderTags}; use crate::client::replies::reply_storage::{ReceivedReplySurbsMap, SentReplyKeys, UsedSenderTags};
use crate::client::topology_control::{TopologyAccessor, TopologyReadPermit}; use crate::client::topology_control::{TopologyAccessor, TopologyReadPermit};
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
@@ -20,7 +19,6 @@ use nym_sphinx::params::{PacketSize, PacketType};
use nym_sphinx::preparer::{MessagePreparer, PreparedFragment}; use nym_sphinx::preparer::{MessagePreparer, PreparedFragment};
use nym_sphinx::Delay; use nym_sphinx::Delay;
use nym_task::connections::TransmissionLane; use nym_task::connections::TransmissionLane;
use nym_task::TaskClient;
use nym_topology::{NymRouteProvider, NymTopologyError}; use nym_topology::{NymRouteProvider, NymTopologyError};
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
use std::collections::HashMap; use std::collections::HashMap;
@@ -34,12 +32,10 @@ pub enum PreparationError {
#[error(transparent)] #[error(transparent)]
NymTopologyError(#[from] NymTopologyError), NymTopologyError(#[from] NymTopologyError),
#[error("message too long for a single SURB, splitting into {fragments} fragments.")] #[error("The received message cannot be sent using a single reply surb. It ended up getting split into {fragments} fragments.")]
MessageTooLongForSingleSurb { fragments: usize }, MessageTooLongForSingleSurb { fragments: usize },
#[error( #[error("Not enough reply SURBs to send the message. We have {available} available and require at least {required}.")]
"not enough reply SURBs to send the message, available: {available} required: {required}."
)]
NotEnoughSurbs { available: usize, required: usize }, NotEnoughSurbs { available: usize, required: usize },
} }
@@ -143,12 +139,6 @@ impl Config {
} }
} }
#[derive(Clone)]
pub(crate) struct FragmentWithMaxRetransmissions {
pub(crate) fragment: Fragment,
pub(crate) max_retransmissions: MaxRetransmissions,
}
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct MessageHandler<R> { pub(crate) struct MessageHandler<R> {
config: Config, config: Config,
@@ -159,14 +149,12 @@ pub(crate) struct MessageHandler<R> {
topology_access: TopologyAccessor, topology_access: TopologyAccessor,
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
tag_storage: UsedSenderTags, tag_storage: UsedSenderTags,
task_client: TaskClient,
} }
impl<R> MessageHandler<R> impl<R> MessageHandler<R>
where where
R: CryptoRng + Rng, R: CryptoRng + Rng,
{ {
#[allow(clippy::too_many_arguments)]
pub(crate) fn new( pub(crate) fn new(
config: Config, config: Config,
rng: R, rng: R,
@@ -175,7 +163,6 @@ where
topology_access: TopologyAccessor, topology_access: TopologyAccessor,
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
tag_storage: UsedSenderTags, tag_storage: UsedSenderTags,
task_client: TaskClient,
) -> Self ) -> Self
where where
R: Copy, R: Copy,
@@ -196,7 +183,6 @@ where
topology_access, topology_access,
reply_key_storage, reply_key_storage,
tag_storage, tag_storage,
task_client,
} }
} }
@@ -205,10 +191,10 @@ where
trace!("we already had sender tag for {recipient}"); trace!("we already had sender tag for {recipient}");
existing existing
} else { } else {
debug!("creating new sender tag for {recipient}"); info!("creating new sender tag for {recipient}");
let new_tag = AnonymousSenderTag::new_random(&mut self.rng); let new_tag = AnonymousSenderTag::new_random(&mut self.rng);
self.tag_storage.insert_new(recipient, new_tag); self.tag_storage.insert_new(recipient, new_tag);
info!("using {new_tag} for all anonymous messages sent to {recipient}"); info!("we'll be using {new_tag} for all anonymous messages sent to {recipient}");
new_tag new_tag
} }
} }
@@ -301,14 +287,8 @@ where
Some(chunk.fragment_identifier()), Some(chunk.fragment_identifier()),
); );
let delay = prepared_fragment.total_delay; let delay = prepared_fragment.total_delay;
let max_retransmissions = None; let pending_ack =
let pending_ack = PendingAcknowledgement::new_anonymous( PendingAcknowledgement::new_anonymous(chunk, delay, target, is_extra_surb_request);
chunk,
delay,
target,
is_extra_surb_request,
max_retransmissions,
);
let lane = if is_extra_surb_request { let lane = if is_extra_surb_request {
TransmissionLane::ReplySurbRequest TransmissionLane::ReplySurbRequest
@@ -363,7 +343,7 @@ where
pub(crate) async fn try_send_reply_chunks_on_lane( pub(crate) async fn try_send_reply_chunks_on_lane(
&mut self, &mut self,
target: AnonymousSenderTag, target: AnonymousSenderTag,
fragments: Vec<FragmentWithMaxRetransmissions>, fragments: Vec<Fragment>,
reply_surbs: Vec<ReplySurb>, reply_surbs: Vec<ReplySurb>,
lane: TransmissionLane, lane: TransmissionLane,
) -> Result<(), SurbWrappedPreparationError> { ) -> Result<(), SurbWrappedPreparationError> {
@@ -380,12 +360,12 @@ where
pub(crate) async fn try_send_reply_chunks( pub(crate) async fn try_send_reply_chunks(
&mut self, &mut self,
target: AnonymousSenderTag, target: AnonymousSenderTag,
fragments: Vec<(TransmissionLane, FragmentWithMaxRetransmissions)>, fragments: Vec<(TransmissionLane, Fragment)>,
reply_surbs: Vec<ReplySurb>, reply_surbs: Vec<ReplySurb>,
) -> Result<(), SurbWrappedPreparationError> { ) -> Result<(), SurbWrappedPreparationError> {
let prepared_fragments = self let prepared_fragments = self
.prepare_reply_chunks_for_sending( .prepare_reply_chunks_for_sending(
fragments.iter().map(|(_, f)| f.fragment.clone()).collect(), fragments.iter().map(|(_, f)| f.clone()).collect(),
reply_surbs, reply_surbs,
) )
.await?; .await?;
@@ -395,21 +375,12 @@ where
for (raw, prepared) in fragments.into_iter().zip(prepared_fragments.into_iter()) { for (raw, prepared) in fragments.into_iter().zip(prepared_fragments.into_iter()) {
let lane = raw.0; let lane = raw.0;
let FragmentWithMaxRetransmissions { let fragment = raw.1;
fragment,
max_retransmissions,
} = raw.1;
let real_message = let real_message =
RealMessage::new(prepared.mix_packet, Some(prepared.fragment_identifier)); RealMessage::new(prepared.mix_packet, Some(prepared.fragment_identifier));
let delay = prepared.total_delay; let delay = prepared.total_delay;
let pending_ack = PendingAcknowledgement::new_anonymous( let pending_ack = PendingAcknowledgement::new_anonymous(fragment, delay, target, false);
fragment,
delay,
target,
false,
max_retransmissions,
);
let entry = to_forward.entry(lane).or_default(); let entry = to_forward.entry(lane).or_default();
entry.push(real_message); entry.push(real_message);
@@ -438,17 +409,10 @@ where
message: Vec<u8>, message: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType, packet_type: PacketType,
max_retransmissions: Option<u32>,
) -> Result<(), PreparationError> { ) -> Result<(), PreparationError> {
let message = NymMessage::new_plain(message); let message = NymMessage::new_plain(message);
self.try_split_and_send_non_reply_message( self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
message, .await
recipient,
lane,
packet_type,
max_retransmissions,
)
.await
} }
pub(crate) async fn try_split_and_send_non_reply_message( pub(crate) async fn try_split_and_send_non_reply_message(
@@ -457,7 +421,6 @@ where
recipient: Recipient, recipient: Recipient,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType, packet_type: PacketType,
max_retransmissions: Option<u32>,
) -> Result<(), PreparationError> { ) -> Result<(), PreparationError> {
debug!("Sending non-reply message with packet type {packet_type}"); debug!("Sending non-reply message with packet type {packet_type}");
// TODO: I really dislike existence of this assertion, it implies code has to be re-organised // TODO: I really dislike existence of this assertion, it implies code has to be re-organised
@@ -497,8 +460,7 @@ where
Some(fragment.fragment_identifier()), Some(fragment.fragment_identifier()),
); );
let delay = prepared_fragment.total_delay; let delay = prepared_fragment.total_delay;
let pending_ack = let pending_ack = PendingAcknowledgement::new_known(fragment, delay, recipient);
PendingAcknowledgement::new_known(fragment, delay, recipient, max_retransmissions);
real_messages.push(real_message); real_messages.push(real_message);
pending_acks.push(pending_ack); pending_acks.push(pending_ack);
@@ -526,15 +488,11 @@ where
reply_surbs, reply_surbs,
)); ));
// When sending SURBs we want to retransmit
let max_retransmissions = None;
self.try_split_and_send_non_reply_message( self.try_split_and_send_non_reply_message(
message, message,
recipient, recipient,
TransmissionLane::AdditionalReplySurbs, TransmissionLane::AdditionalReplySurbs,
packet_type, packet_type,
max_retransmissions,
) )
.await?; .await?;
@@ -551,7 +509,6 @@ where
num_reply_surbs: u32, num_reply_surbs: u32,
lane: TransmissionLane, lane: TransmissionLane,
packet_type: PacketType, packet_type: PacketType,
max_retransmissions: Option<u32>,
) -> Result<(), SurbWrappedPreparationError> { ) -> Result<(), SurbWrappedPreparationError> {
debug!("Sending message with reply SURBs with packet type {packet_type}"); debug!("Sending message with reply SURBs with packet type {packet_type}");
let sender_tag = self.get_or_create_sender_tag(&recipient); let sender_tag = self.get_or_create_sender_tag(&recipient);
@@ -562,14 +519,8 @@ where
let message = let message =
NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs)); NymMessage::new_repliable(RepliableMessage::new_data(message, sender_tag, reply_surbs));
self.try_split_and_send_non_reply_message( self.try_split_and_send_non_reply_message(message, recipient, lane, packet_type)
message, .await?;
recipient,
lane,
packet_type,
max_retransmissions,
)
.await?;
log::trace!("storing {} reply keys", reply_keys.len()); log::trace!("storing {} reply keys", reply_keys.len());
self.reply_key_storage.insert_multiple(reply_keys); self.reply_key_storage.insert_multiple(reply_keys);
@@ -658,25 +609,15 @@ where
} }
pub(crate) fn update_ack_delay(&self, id: FragmentIdentifier, new_delay: Delay) { pub(crate) fn update_ack_delay(&self, id: FragmentIdentifier, new_delay: Delay) {
if let Err(err) = self self.action_sender
.action_sender
.unbounded_send(Action::UpdatePendingAck(id, new_delay)) .unbounded_send(Action::UpdatePendingAck(id, new_delay))
{ .expect("action control task has died")
if !self.task_client.is_shutdown_poll() {
error!("Failed to send update action to the controller: {err}");
}
}
} }
pub(crate) fn insert_pending_acks(&self, pending_acks: Vec<PendingAcknowledgement>) { pub(crate) fn insert_pending_acks(&self, pending_acks: Vec<PendingAcknowledgement>) {
if let Err(err) = self self.action_sender
.action_sender
.unbounded_send(Action::new_insert(pending_acks)) .unbounded_send(Action::new_insert(pending_acks))
{ .expect("action control task has died")
if !self.task_client.is_shutdown_poll() {
error!("Failed to send insert action to the controller: {err}");
}
}
} }
// tells real message sender (with the poisson timer) to send this to the mix network // tells real message sender (with the poisson timer) to send this to the mix network
@@ -685,14 +626,9 @@ where
messages: Vec<RealMessage>, messages: Vec<RealMessage>,
transmission_lane: TransmissionLane, transmission_lane: TransmissionLane,
) { ) {
if let Err(err) = self self.real_message_sender
.real_message_sender
.send((messages, transmission_lane)) .send((messages, transmission_lane))
.await .await
{ .expect("real message receiver task (OutQueueControl) has died");
if !self.task_client.is_shutdown_poll() {
error!("Failed to forward messages to the real message sender: {err}");
}
}
} }
} }
@@ -9,12 +9,10 @@ use self::{
acknowledgement_control::AcknowledgementController, real_traffic_stream::OutQueueControl, acknowledgement_control::AcknowledgementController, real_traffic_stream::OutQueueControl,
}; };
use crate::client::real_messages_control::message_handler::MessageHandler; use crate::client::real_messages_control::message_handler::MessageHandler;
use crate::client::replies::reply_controller;
use crate::client::replies::reply_controller::{ use crate::client::replies::reply_controller::{
ReplyController, ReplyControllerReceiver, ReplyControllerSender, ReplyController, ReplyControllerReceiver, ReplyControllerSender,
}; };
use crate::client::replies::reply_storage::CombinedReplyStorage; use crate::client::replies::reply_storage::CombinedReplyStorage;
use crate::config;
use crate::{ use crate::{
client::{ client::{
inbound_messages::InputMessageReceiver, mix_traffic::BatchMixMessageSender, inbound_messages::InputMessageReceiver, mix_traffic::BatchMixMessageSender,
@@ -29,14 +27,16 @@ use nym_gateway_client::AcknowledgementReceiver;
use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::acknowledgements::AckKey;
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::params::PacketType; use nym_sphinx::params::PacketType;
use nym_statistics_common::clients::ClientStatsSender;
use nym_task::connections::{ConnectionCommandReceiver, LaneQueueLengths}; use nym_task::connections::{ConnectionCommandReceiver, LaneQueueLengths};
use nym_task::TaskClient;
use rand::{rngs::OsRng, CryptoRng, Rng}; use rand::{rngs::OsRng, CryptoRng, Rng};
use std::sync::Arc; use std::sync::Arc;
use crate::client::replies::reply_controller;
use crate::config;
pub(crate) use acknowledgement_control::{AckActionSender, Action}; pub(crate) use acknowledgement_control::{AckActionSender, Action};
use nym_statistics_common::clients::ClientStatsSender;
pub(crate) mod acknowledgement_control; pub(crate) mod acknowledgement_control;
pub(crate) mod message_handler; pub(crate) mod message_handler;
pub(crate) mod real_traffic_stream; pub(crate) mod real_traffic_stream;
@@ -148,12 +148,11 @@ impl RealMessagesController<OsRng> {
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver, client_connection_rx: ConnectionCommandReceiver,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
) -> Self { ) -> Self {
let rng = OsRng; let rng = OsRng;
// create channels for inter-task communication // create channels for inter-task communication
let (real_message_sender, real_message_receiver) = tokio::sync::mpsc::channel(8); let (real_message_sender, real_message_receiver) = tokio::sync::mpsc::channel(1);
let (sent_notifier_tx, sent_notifier_rx) = mpsc::unbounded(); let (sent_notifier_tx, sent_notifier_rx) = mpsc::unbounded();
let (ack_action_tx, ack_action_rx) = mpsc::unbounded(); let (ack_action_tx, ack_action_rx) = mpsc::unbounded();
let ack_controller_connectors = AcknowledgementControllerConnectors::new( let ack_controller_connectors = AcknowledgementControllerConnectors::new(
@@ -179,7 +178,6 @@ impl RealMessagesController<OsRng> {
topology_access.clone(), topology_access.clone(),
reply_storage.key_storage(), reply_storage.key_storage(),
reply_storage.tags_storage(), reply_storage.tags_storage(),
task_client.fork("message_handler"),
); );
let ack_control = AcknowledgementController::new( let ack_control = AcknowledgementController::new(
@@ -189,7 +187,6 @@ impl RealMessagesController<OsRng> {
message_handler.clone(), message_handler.clone(),
reply_controller_sender, reply_controller_sender,
stats_tx.clone(), stats_tx.clone(),
task_client.fork("ack_control"),
); );
let reply_control = ReplyController::new( let reply_control = ReplyController::new(
@@ -197,7 +194,6 @@ impl RealMessagesController<OsRng> {
message_handler, message_handler,
reply_storage, reply_storage,
reply_controller_receiver, reply_controller_receiver,
task_client.fork("reply_controller"),
); );
let out_queue_control = OutQueueControl::new( let out_queue_control = OutQueueControl::new(
@@ -210,7 +206,6 @@ impl RealMessagesController<OsRng> {
lane_queue_lengths, lane_queue_lengths,
client_connection_rx, client_connection_rx,
stats_tx, stats_tx,
task_client.with_suffix("out_queue_control"),
); );
RealMessagesController { RealMessagesController {
@@ -220,20 +215,22 @@ impl RealMessagesController<OsRng> {
} }
} }
pub fn start(self, packet_type: PacketType) { pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient, packet_type: PacketType) {
let mut out_queue_control = self.out_queue_control; let mut out_queue_control = self.out_queue_control;
let ack_control = self.ack_control; let ack_control = self.ack_control;
let mut reply_control = self.reply_control; let mut reply_control = self.reply_control;
let shutdown_handle = shutdown.fork("out_queue_control");
spawn_future(async move { spawn_future(async move {
out_queue_control.run().await; out_queue_control.run_with_shutdown(shutdown_handle).await;
debug!("The out queue controller has finished execution!"); debug!("The out queue controller has finished execution!");
}); });
let shutdown_handle = shutdown.fork("reply_control");
spawn_future(async move { spawn_future(async move {
reply_control.run().await; reply_control.run_with_shutdown(shutdown_handle).await;
debug!("The reply controller has finished execution!"); debug!("The reply controller has finished execution!");
}); });
ack_control.start(packet_type); ack_control.start_with_shutdown(shutdown.with_suffix("ack_control"), packet_type);
} }
} }
@@ -22,7 +22,6 @@ use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, C
use nym_task::connections::{ use nym_task::connections::{
ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane, ConnectionCommand, ConnectionCommandReceiver, ConnectionId, LaneQueueLengths, TransmissionLane,
}; };
use nym_task::TaskClient;
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
@@ -118,8 +117,6 @@ where
/// Channel used for sending metrics events (specifically `PacketStatistics` events) to the metrics tracker. /// Channel used for sending metrics events (specifically `PacketStatistics` events) to the metrics tracker.
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -179,7 +176,6 @@ where
lane_queue_lengths: LaneQueueLengths, lane_queue_lengths: LaneQueueLengths,
client_connection_rx: ConnectionCommandReceiver, client_connection_rx: ConnectionCommandReceiver,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
) -> Self { ) -> Self {
OutQueueControl { OutQueueControl {
config, config,
@@ -194,7 +190,6 @@ where
client_connection_rx, client_connection_rx,
lane_queue_lengths, lane_queue_lengths,
stats_tx, stats_tx,
task_client,
} }
} }
@@ -203,9 +198,7 @@ where
// queues and client load rather than the required delay. So realistically we can treat // queues and client load rather than the required delay. So realistically we can treat
// whatever is about to happen as negligible additional delay. // whatever is about to happen as negligible additional delay.
trace!("{} is about to get sent to the mixnet", frag_id); trace!("{} is about to get sent to the mixnet", frag_id);
if let Err(err) = self.sent_notifier.unbounded_send(frag_id) { self.sent_notifier.unbounded_send(frag_id).unwrap();
error!("Failed to notify about sent message: {err}");
}
} }
fn loop_cover_message_size(&mut self) -> PacketSize { fn loop_cover_message_size(&mut self) -> PacketSize {
@@ -278,9 +271,7 @@ where
}; };
if let Err(err) = self.mix_tx.send(vec![next_message]).await { if let Err(err) = self.mix_tx.send(vec![next_message]).await {
if !self.task_client.is_shutdown_poll() { log::error!("Failed to send: {err}");
log::error!("Failed to send: {err}");
}
} else { } else {
let event = if fragment_id.is_some() { let event = if fragment_id.is_some() {
PacketStatisticsEvent::RealPacketSent(packet_size) PacketStatisticsEvent::RealPacketSent(packet_size)
@@ -513,29 +504,21 @@ where
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
fn log_status(&self, shutdown: &mut TaskClient) { fn log_status(&self, shutdown: &mut nym_task::TaskClient) {
use crate::error::ClientCoreStatusMessage; use crate::error::ClientCoreStatusMessage;
let packets = self.transmission_buffer.total_size(); let packets = self.transmission_buffer.total_size();
let lanes = self.transmission_buffer.lanes(); let backlog = self.transmission_buffer.total_size_in_bytes() as f64 / 1024.0;
let lanes = self.transmission_buffer.num_lanes();
let mult = self.sending_delay_controller.current_multiplier(); let mult = self.sending_delay_controller.current_multiplier();
let delay = self.current_average_message_sending_delay().as_millis(); let delay = self.current_average_message_sending_delay().as_millis();
let lane_status = lanes
.iter()
.map(|lane_name| {
let lane_length = self.transmission_buffer.lane_length(lane_name).unwrap_or(0);
format!("{lane_name:?}: {lane_length}")
})
.collect::<Vec<String>>()
.join(", ");
let status_str = if self.config.traffic.disable_main_poisson_packet_distribution { let status_str = if self.config.traffic.disable_main_poisson_packet_distribution {
format!("Packet backlog: {lane_status}, no delay") format!("Packet backlog: {backlog:.2} kiB ({packets}), {lanes} lanes, no delay")
} else { } else {
format!("Packet backlog: {lane_status}, avg delay: {delay}ms ({mult})") format!(
"Packet backlog: {backlog:.2} kiB ({packets}), {lanes} lanes, avg delay: {delay}ms ({mult})"
)
}; };
if packets > 1000 { if packets > 1000 {
log::warn!("{status_str}"); log::warn!("{status_str}");
} else if packets > 0 { } else if packets > 0 {
@@ -552,19 +535,17 @@ where
} }
} }
pub(super) async fn run(&mut self) { pub(super) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
debug!("Started OutQueueControl with graceful shutdown support"); debug!("Started OutQueueControl with graceful shutdown support");
let mut shutdown = self.task_client.fork("select");
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
{ {
let mut status_timer = tokio::time::interval(Duration::from_secs(5)); let mut status_timer = tokio::time::interval(Duration::from_secs(5));
while !shutdown.is_shutdown() { loop {
tokio::select! { tokio::select! {
biased; biased;
_ = shutdown.recv() => { _ = shutdown.recv_with_delay() => {
log::trace!("OutQueueControl: Received shutdown"); log::trace!("OutQueueControl: Received shutdown");
break; break;
} }
@@ -70,10 +70,7 @@ impl SendingDelayController {
lower_bound, lower_bound,
multiplier_elevated_counter: 0, multiplier_elevated_counter: 0,
time_when_logged_about_elevated_multiplier: now time_when_logged_about_elevated_multiplier: now
.checked_sub(Duration::from_secs( - Duration::from_secs(INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS),
INTERVAL_BETWEEN_WARNING_ABOUT_ELEVATED_MULTIPLIER_SECS,
))
.unwrap_or(now),
time_when_changed: now, time_when_changed: now,
time_when_backpressure_detected: now, time_when_backpressure_detected: now,
} }
@@ -20,13 +20,8 @@ use nym_sphinx::message::{NymMessage, PlainMessage};
use nym_sphinx::params::ReplySurbKeyDigestAlgorithm; use nym_sphinx::params::ReplySurbKeyDigestAlgorithm;
use nym_sphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage}; use nym_sphinx::receiver::{MessageReceiver, MessageRecoveryError, ReconstructedMessage};
use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender}; use nym_statistics_common::clients::{packet_statistics::PacketStatisticsEvent, ClientStatsSender};
use nym_task::TaskClient;
use std::collections::HashSet; use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant};
// The interval at which we check for stale buffers
const STALE_BUFFER_CHECK_INTERVAL: Duration = Duration::from_secs(10);
// Buffer Requests to say "hey, send any reconstructed messages to this channel" // Buffer Requests to say "hey, send any reconstructed messages to this channel"
// or to say "hey, I'm going offline, don't send anything more to me. Just buffer them instead" // or to say "hey, I'm going offline, don't send anything more to me. Just buffer them instead"
@@ -52,9 +47,6 @@ struct ReceivedMessagesBufferInner<R: MessageReceiver> {
recently_reconstructed: HashSet<i32>, recently_reconstructed: HashSet<i32>,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
// Periodically check for stale buffers to clean up
last_stale_check: Instant,
} }
impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> { impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
@@ -103,10 +95,9 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
} }
None None
} }
_ => { _ => unreachable!(
error!("unexpected error occurred during message reconstruction: {err}"); "no other error kind should have been returned here! If so, it's a bug!"
None ),
}
}, },
Ok(reconstruction_result) => match reconstruction_result { Ok(reconstruction_result) => match reconstruction_result {
Some((reconstructed_message, used_sets)) => { Some((reconstructed_message, used_sets)) => {
@@ -152,16 +143,6 @@ impl<R: MessageReceiver> ReceivedMessagesBufferInner<R> {
self.recover_from_fragment(fragment_data, raw_fragment_size) self.recover_from_fragment(fragment_data, raw_fragment_size)
} }
fn cleanup_stale_buffers(&mut self) {
let now = Instant::now();
if now - self.last_stale_check > STALE_BUFFER_CHECK_INTERVAL {
self.last_stale_check = now;
self.message_receiver
.reconstructor()
.cleanup_stale_buffers();
}
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -171,7 +152,6 @@ struct ReceivedMessagesBuffer<R: MessageReceiver> {
inner: Arc<Mutex<ReceivedMessagesBufferInner<R>>>, inner: Arc<Mutex<ReceivedMessagesBufferInner<R>>>,
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
task_client: TaskClient,
} }
impl<R: MessageReceiver> ReceivedMessagesBuffer<R> { impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
@@ -180,7 +160,6 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
stats_tx: ClientStatsSender, stats_tx: ClientStatsSender,
task_client: TaskClient,
) -> Self { ) -> Self {
ReceivedMessagesBuffer { ReceivedMessagesBuffer {
inner: Arc::new(Mutex::new(ReceivedMessagesBufferInner { inner: Arc::new(Mutex::new(ReceivedMessagesBufferInner {
@@ -190,11 +169,9 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
message_sender: None, message_sender: None,
recently_reconstructed: HashSet::new(), recently_reconstructed: HashSet::new(),
stats_tx, stats_tx,
last_stale_check: Instant::now(),
})), })),
reply_key_storage, reply_key_storage,
reply_controller_sender, reply_controller_sender,
task_client,
} }
} }
@@ -280,15 +257,11 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
} }
}; };
if let Err(err) = self.reply_controller_sender.send_additional_surbs( self.reply_controller_sender.send_additional_surbs(
msg.sender_tag, msg.sender_tag,
reply_surbs, reply_surbs,
from_surb_request, from_surb_request,
) { )
if !self.task_client.is_shutdown_poll() {
error!("{err}");
}
}
} }
reconstructed reconstructed
} }
@@ -303,14 +276,8 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
ReplyMessageContent::Data { message } => reconstructed.push(message.into()), ReplyMessageContent::Data { message } => reconstructed.push(message.into()),
ReplyMessageContent::SurbRequest { recipient, amount } => { ReplyMessageContent::SurbRequest { recipient, amount } => {
debug!("received request for {amount} additional reply SURBs from {recipient}"); debug!("received request for {amount} additional reply SURBs from {recipient}");
if let Err(err) = self self.reply_controller_sender
.reply_controller_sender .send_additional_surbs_request(*recipient, amount);
.send_additional_surbs_request(*recipient, amount)
{
if !self.task_client.is_shutdown_poll() {
error!("{err}");
}
}
} }
} }
} }
@@ -411,11 +378,6 @@ impl<R: MessageReceiver> ReceivedMessagesBuffer<R> {
} }
} }
// Cleanup stale buffers, if there are any fragments that simply never arrived.
// We do this here as part of handling new received fragments so that we can keep the event
// loop focused on processing new messages.
inner_guard.cleanup_stale_buffers();
drop(inner_guard); drop(inner_guard);
if !completed_messages.is_empty() { if !completed_messages.is_empty() {
@@ -437,19 +399,16 @@ pub enum ReceivedBufferMessage {
struct RequestReceiver<R: MessageReceiver> { struct RequestReceiver<R: MessageReceiver> {
received_buffer: ReceivedMessagesBuffer<R>, received_buffer: ReceivedMessagesBuffer<R>,
query_receiver: ReceivedBufferRequestReceiver, query_receiver: ReceivedBufferRequestReceiver,
task_client: TaskClient,
} }
impl<R: MessageReceiver> RequestReceiver<R> { impl<R: MessageReceiver> RequestReceiver<R> {
fn new( fn new(
received_buffer: ReceivedMessagesBuffer<R>, received_buffer: ReceivedMessagesBuffer<R>,
query_receiver: ReceivedBufferRequestReceiver, query_receiver: ReceivedBufferRequestReceiver,
task_client: TaskClient,
) -> Self { ) -> Self {
RequestReceiver { RequestReceiver {
received_buffer, received_buffer,
query_receiver, query_receiver,
task_client,
} }
} }
@@ -464,12 +423,12 @@ impl<R: MessageReceiver> RequestReceiver<R> {
} }
} }
async fn run(&mut self) { async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
debug!("Started RequestReceiver with graceful shutdown support"); debug!("Started RequestReceiver with graceful shutdown support");
while !self.task_client.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
biased; biased;
_ = self.task_client.recv() => { _ = shutdown.recv_with_delay() => {
log::trace!("RequestReceiver: Received shutdown"); log::trace!("RequestReceiver: Received shutdown");
} }
request = self.query_receiver.next() => { request = self.query_receiver.next() => {
@@ -482,7 +441,7 @@ impl<R: MessageReceiver> RequestReceiver<R> {
}, },
} }
} }
self.task_client.recv().await; shutdown.recv_timeout().await;
log::debug!("RequestReceiver: Exiting"); log::debug!("RequestReceiver: Exiting");
} }
} }
@@ -490,25 +449,25 @@ impl<R: MessageReceiver> RequestReceiver<R> {
struct FragmentedMessageReceiver<R: MessageReceiver> { struct FragmentedMessageReceiver<R: MessageReceiver> {
received_buffer: ReceivedMessagesBuffer<R>, received_buffer: ReceivedMessagesBuffer<R>,
mixnet_packet_receiver: MixnetMessageReceiver, mixnet_packet_receiver: MixnetMessageReceiver,
task_client: TaskClient,
} }
impl<R: MessageReceiver> FragmentedMessageReceiver<R> { impl<R: MessageReceiver> FragmentedMessageReceiver<R> {
fn new( fn new(
received_buffer: ReceivedMessagesBuffer<R>, received_buffer: ReceivedMessagesBuffer<R>,
mixnet_packet_receiver: MixnetMessageReceiver, mixnet_packet_receiver: MixnetMessageReceiver,
task_client: TaskClient,
) -> Self { ) -> Self {
FragmentedMessageReceiver { FragmentedMessageReceiver {
received_buffer, received_buffer,
mixnet_packet_receiver, mixnet_packet_receiver,
task_client,
} }
} }
async fn run(&mut self) -> Result<(), MessageRecoveryError> { async fn run_with_shutdown(
&mut self,
mut shutdown: nym_task::TaskClient,
) -> Result<(), MessageRecoveryError> {
debug!("Started FragmentedMessageReceiver with graceful shutdown support"); debug!("Started FragmentedMessageReceiver with graceful shutdown support");
while !self.task_client.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
new_messages = self.mixnet_packet_receiver.next() => { new_messages = self.mixnet_packet_receiver.next() => {
if let Some(new_messages) = new_messages { if let Some(new_messages) = new_messages {
@@ -518,12 +477,12 @@ impl<R: MessageReceiver> FragmentedMessageReceiver<R> {
break; break;
} }
}, },
_ = self.task_client.recv_with_delay() => { _ = shutdown.recv_with_delay() => {
log::trace!("FragmentedMessageReceiver: Received shutdown"); log::trace!("FragmentedMessageReceiver: Received shutdown");
} }
} }
} }
self.task_client.recv_timeout().await; shutdown.recv_timeout().await;
log::debug!("FragmentedMessageReceiver: Exiting"); log::debug!("FragmentedMessageReceiver: Exiting");
Ok(()) Ok(())
} }
@@ -542,42 +501,41 @@ impl<R: MessageReceiver + Clone + Send + 'static> ReceivedMessagesBufferControll
reply_key_storage: SentReplyKeys, reply_key_storage: SentReplyKeys,
reply_controller_sender: ReplyControllerSender, reply_controller_sender: ReplyControllerSender,
metrics_reporter: ClientStatsSender, metrics_reporter: ClientStatsSender,
task_client: TaskClient,
) -> Self { ) -> Self {
let received_buffer = ReceivedMessagesBuffer::new( let received_buffer = ReceivedMessagesBuffer::new(
local_encryption_keypair, local_encryption_keypair,
reply_key_storage, reply_key_storage,
reply_controller_sender, reply_controller_sender,
metrics_reporter, metrics_reporter,
task_client.fork("received_messages_buffer"),
); );
ReceivedMessagesBufferController { ReceivedMessagesBufferController {
fragmented_message_receiver: FragmentedMessageReceiver::new( fragmented_message_receiver: FragmentedMessageReceiver::new(
received_buffer.clone(), received_buffer.clone(),
mixnet_packet_receiver, mixnet_packet_receiver,
task_client.fork("fragmented_message_receiver"),
),
request_receiver: RequestReceiver::new(
received_buffer,
query_receiver,
task_client.with_suffix("request_receiver"),
), ),
request_receiver: RequestReceiver::new(received_buffer, query_receiver),
} }
} }
pub fn start(self) { pub fn start_with_shutdown(self, shutdown: nym_task::TaskClient) {
let mut fragmented_message_receiver = self.fragmented_message_receiver; let mut fragmented_message_receiver = self.fragmented_message_receiver;
let mut request_receiver = self.request_receiver; let mut request_receiver = self.request_receiver;
let shutdown_handle = shutdown.fork("fragmented_message_receiver");
spawn_future(async move { spawn_future(async move {
match fragmented_message_receiver.run().await { match fragmented_message_receiver
.run_with_shutdown(shutdown_handle)
.await
{
Ok(_) => {} Ok(_) => {}
Err(e) => error!("{e}"), Err(e) => error!("{e}"),
} }
}); });
spawn_future(async move { spawn_future(async move {
request_receiver.run().await; request_receiver
.run_with_shutdown(shutdown.with_suffix("request_receiver"))
.await;
}); });
} }
} }
@@ -2,9 +2,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::client::real_messages_control::acknowledgement_control::PendingAcknowledgement; use crate::client::real_messages_control::acknowledgement_control::PendingAcknowledgement;
use crate::client::real_messages_control::message_handler::{ use crate::client::real_messages_control::message_handler::{MessageHandler, PreparationError};
FragmentWithMaxRetransmissions, MessageHandler, PreparationError,
};
use crate::client::replies::reply_storage::CombinedReplyStorage; use crate::client::replies::reply_storage::CombinedReplyStorage;
use futures::channel::oneshot; use futures::channel::oneshot;
use futures::StreamExt; use futures::StreamExt;
@@ -12,9 +10,8 @@ use log::{debug, error, info, trace, warn};
use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag; use nym_sphinx::anonymous_replies::requests::AnonymousSenderTag;
use nym_sphinx::anonymous_replies::ReplySurb; use nym_sphinx::anonymous_replies::ReplySurb;
use nym_sphinx::chunking::fragment::FragmentIdentifier; use nym_sphinx::chunking::fragment::{Fragment, FragmentIdentifier};
use nym_task::connections::{ConnectionId, TransmissionLane}; use nym_task::connections::{ConnectionId, TransmissionLane};
use nym_task::TaskClient;
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::collections::btree_map::Entry; use std::collections::btree_map::Entry;
@@ -51,8 +48,6 @@ impl Config {
// - replies to "give additional surbs" requests // - replies to "give additional surbs" requests
// - will reply to future heartbeats // - will reply to future heartbeats
pub type MaxRetransmissions = Option<u32>;
// TODO: this should be split into ingress and egress controllers // TODO: this should be split into ingress and egress controllers
// because currently its trying to perform two distinct jobs // because currently its trying to perform two distinct jobs
pub struct ReplyController<R> { pub struct ReplyController<R> {
@@ -63,8 +58,7 @@ pub struct ReplyController<R> {
// of surbs required to send the message through // of surbs required to send the message through
// expected_reliability: f32, // expected_reliability: f32,
request_receiver: ReplyControllerReceiver, request_receiver: ReplyControllerReceiver,
pending_replies: pending_replies: HashMap<AnonymousSenderTag, TransmissionBuffer<Fragment>>,
HashMap<AnonymousSenderTag, TransmissionBuffer<FragmentWithMaxRetransmissions>>,
/// Retransmission packets that have already timed out and are waiting for additional reply SURBs /// Retransmission packets that have already timed out and are waiting for additional reply SURBs
/// so that they could be sent back to the network. Once we receive more SURBs, we should send them ASAP. /// so that they could be sent back to the network. Once we receive more SURBs, we should send them ASAP.
@@ -74,9 +68,6 @@ pub struct ReplyController<R> {
message_handler: MessageHandler<R>, message_handler: MessageHandler<R>,
full_reply_storage: CombinedReplyStorage, full_reply_storage: CombinedReplyStorage,
// Listen for shutdown signals
task_client: TaskClient,
} }
impl<R> ReplyController<R> impl<R> ReplyController<R>
@@ -88,7 +79,6 @@ where
message_handler: MessageHandler<R>, message_handler: MessageHandler<R>,
full_reply_storage: CombinedReplyStorage, full_reply_storage: CombinedReplyStorage,
request_receiver: ReplyControllerReceiver, request_receiver: ReplyControllerReceiver,
task_client: TaskClient,
) -> Self { ) -> Self {
ReplyController { ReplyController {
config, config,
@@ -97,17 +87,15 @@ where
pending_retransmissions: HashMap::new(), pending_retransmissions: HashMap::new(),
message_handler, message_handler,
full_reply_storage, full_reply_storage,
task_client,
} }
} }
fn insert_pending_replies<I: IntoIterator<Item = FragmentWithMaxRetransmissions>>( fn insert_pending_replies<I: IntoIterator<Item = Fragment>>(
&mut self, &mut self,
recipient: &AnonymousSenderTag, recipient: &AnonymousSenderTag,
fragments: I, fragments: I,
lane: TransmissionLane, lane: TransmissionLane,
) { ) {
trace!("buffering pending replies for {recipient}");
self.pending_replies self.pending_replies
.entry(*recipient) .entry(*recipient)
.or_insert_with(TransmissionBuffer::new) .or_insert_with(TransmissionBuffer::new)
@@ -117,9 +105,8 @@ where
fn re_insert_pending_replies( fn re_insert_pending_replies(
&mut self, &mut self,
recipient: &AnonymousSenderTag, recipient: &AnonymousSenderTag,
fragments: Vec<(TransmissionLane, FragmentWithMaxRetransmissions)>, fragments: Vec<(TransmissionLane, Fragment)>,
) { ) {
trace!("re-inserting pending replies for {recipient}");
// the buffer should ALWAYS exist at this point, if it doesn't, it's a bug... // the buffer should ALWAYS exist at this point, if it doesn't, it's a bug...
self.pending_replies self.pending_replies
.entry(*recipient) .entry(*recipient)
@@ -132,7 +119,6 @@ where
recipient: &AnonymousSenderTag, recipient: &AnonymousSenderTag,
data: Vec<Arc<PendingAcknowledgement>>, data: Vec<Arc<PendingAcknowledgement>>,
) { ) {
trace!("re-inserting pending retransmissions for {recipient}");
// the underlying entry MUST exist as we've just got data from there // the underlying entry MUST exist as we've just got data from there
let map_entry = self let map_entry = self
.pending_retransmissions .pending_retransmissions
@@ -150,7 +136,7 @@ where
} }
fn should_request_more_surbs(&self, target: &AnonymousSenderTag) -> bool { fn should_request_more_surbs(&self, target: &AnonymousSenderTag) -> bool {
trace!("checking if we should request more surbs from {target}"); trace!("checking if we should request more surbs from {:?}", target);
let pending_queue_size = self let pending_queue_size = self
.pending_replies .pending_replies
@@ -166,6 +152,11 @@ where
let total_queue = pending_queue_size + retransmission_queue; let total_queue = pending_queue_size + retransmission_queue;
// simple as that - there's absolutely nothing to retransmit
if total_queue == 0 {
return false;
}
let available_surbs = self let available_surbs = self
.full_reply_storage .full_reply_storage
.surbs_storage_ref() .surbs_storage_ref()
@@ -182,27 +173,11 @@ where
.full_reply_storage .full_reply_storage
.surbs_storage_ref() .surbs_storage_ref()
.max_surb_threshold(); .max_surb_threshold();
let min_surbs_threshold_buffer =
self.config.reply_surbs.minimum_reply_surb_threshold_buffer;
// After clearing the queue, we want to have at least `min_surbs_threshold` surbs available debug!("total queue size: {total_queue} = pending data {pending_queue_size} + pending retransmission {retransmission_queue}, available surbs: {available_surbs} pending surbs: {pending_surbs} threshold range: {min_surbs_threshold}..{max_surbs_threshold}");
// and reserved for requesting additional surbs, and in addition to that we also want to
// have `min_surbs_threshold_buffer` surbs available proactively.
let target_surbs_after_clearing_queue = min_surbs_threshold + min_surbs_threshold_buffer;
// Check if we have enough surbs to handle the total queue and maintain minimum thresholds (pending_surbs + available_surbs) < max_surbs_threshold
let total_required_surbs = total_queue + target_surbs_after_clearing_queue; && (pending_surbs + available_surbs) < (total_queue + min_surbs_threshold)
let total_available_surbs = pending_surbs + available_surbs;
debug!("total queue size: {total_queue} = pending data {pending_queue_size} + pending retransmission {retransmission_queue}, available surbs: {available_surbs} pending surbs: {pending_surbs} threshold range: {min_surbs_threshold}..+{min_surbs_threshold_buffer}..{max_surbs_threshold}");
// We should request more surbs if:
// 1. We haven't hit the maximum surb threshold, and
// 2. We don't have enough surbs to handle the queue plus minimum thresholds
let is_below_max_threshold = total_available_surbs < max_surbs_threshold;
let is_below_required_surbs = total_available_surbs < total_required_surbs;
is_below_max_threshold && is_below_required_surbs
} }
async fn handle_send_reply( async fn handle_send_reply(
@@ -210,7 +185,6 @@ where
recipient_tag: AnonymousSenderTag, recipient_tag: AnonymousSenderTag,
data: Vec<u8>, data: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
max_retransmissions: Option<u32>,
) { ) {
if !self if !self
.full_reply_storage .full_reply_storage
@@ -248,14 +222,7 @@ where
.get_reply_surbs(&recipient_tag, max_to_send); .get_reply_surbs(&recipient_tag, max_to_send);
if let Some(reply_surbs) = surbs { if let Some(reply_surbs) = surbs {
let to_send = fragments let to_send = fragments.drain(..max_to_send).collect::<Vec<_>>();
.drain(..max_to_send)
.map(|f| FragmentWithMaxRetransmissions {
fragment: f,
max_retransmissions,
})
.collect::<Vec<_>>();
if let Err(err) = self if let Err(err) = self
.message_handler .message_handler
.try_send_reply_chunks_on_lane( .try_send_reply_chunks_on_lane(
@@ -271,10 +238,6 @@ where
&recipient_tag, &recipient_tag,
); );
warn!("failed to send reply to {recipient_tag}: {err}"); warn!("failed to send reply to {recipient_tag}: {err}");
info!(
"buffering {no_fragments} fragments for {recipient_tag}",
no_fragments = to_send.len()
);
self.insert_pending_replies(&recipient_tag, to_send, lane); self.insert_pending_replies(&recipient_tag, to_send, lane);
} }
} }
@@ -282,20 +245,6 @@ where
// if there's leftover data we didn't send because we didn't have enough (or any) surbs - buffer it // if there's leftover data we didn't send because we didn't have enough (or any) surbs - buffer it
if !fragments.is_empty() { if !fragments.is_empty() {
// Ideally we should have enough surbs above the minimum threshold to handle sending
// new replies without having to first request more surbs. That's why I'd like to log
// these cases as they might indicate a problem with the surb management.
debug!(
"buffering {no_fragments} fragments for {recipient_tag}",
no_fragments = fragments.len()
);
let fragments: Vec<_> = fragments
.into_iter()
.map(|fragment| FragmentWithMaxRetransmissions {
fragment,
max_retransmissions,
})
.collect();
self.insert_pending_replies(&recipient_tag, fragments, lane); self.insert_pending_replies(&recipient_tag, fragments, lane);
} }
@@ -310,7 +259,6 @@ where
target: AnonymousSenderTag, target: AnonymousSenderTag,
amount: u32, amount: u32,
) -> Result<(), PreparationError> { ) -> Result<(), PreparationError> {
debug!("requesting {amount} additional reply surbs for {target}");
let reply_surb = self let reply_surb = self
.full_reply_storage .full_reply_storage
.surbs_storage_ref() .surbs_storage_ref()
@@ -429,7 +377,7 @@ where
&mut self, &mut self,
from: &AnonymousSenderTag, from: &AnonymousSenderTag,
amount: usize, amount: usize,
) -> Option<Vec<(TransmissionLane, FragmentWithMaxRetransmissions)>> { ) -> Option<Vec<(TransmissionLane, Fragment)>> {
// if possible, pop all pending replies, if not, pop only entries for which we'd have a reply surb // if possible, pop all pending replies, if not, pop only entries for which we'd have a reply surb
let total = self.pending_replies.get(from)?.total_size(); let total = self.pending_replies.get(from)?.total_size();
trace!("pending queue has {total} elements"); trace!("pending queue has {total} elements");
@@ -709,11 +657,7 @@ where
recipient, recipient,
message, message,
lane, lane,
max_retransmissions, } => self.handle_send_reply(recipient, message, lane).await,
} => {
self.handle_send_reply(recipient, message, lane, max_retransmissions)
.await
}
ReplyControllerMessage::AdditionalSurbs { ReplyControllerMessage::AdditionalSurbs {
sender_tag, sender_tag,
reply_surbs, reply_surbs,
@@ -736,7 +680,7 @@ where
// it should take into consideration the average latency, sending rate and queue size. // it should take into consideration the average latency, sending rate and queue size.
// it should request as many surbs as it takes to saturate its sending rate before next batch arrives // it should request as many surbs as it takes to saturate its sending rate before next batch arrives
async fn request_reply_surbs_for_queue_clearing(&mut self, target: AnonymousSenderTag) { async fn request_reply_surbs_for_queue_clearing(&mut self, target: AnonymousSenderTag) {
trace!("requesting surbs for queue clearing"); trace!("requesting surbs for queues clearing");
let pending_queue_size = self let pending_queue_size = self
.pending_replies .pending_replies
@@ -750,18 +694,17 @@ where
.map(|pending_queue| pending_queue.len()) .map(|pending_queue| pending_queue.len())
.unwrap_or_default(); .unwrap_or_default();
let min_surbs_buffer = self.config.reply_surbs.minimum_reply_surb_threshold_buffer as u32;
let total_queue = (pending_queue_size + retransmission_queue) as u32; let total_queue = (pending_queue_size + retransmission_queue) as u32;
// To proactively request additional surbs, we aim to have a buffer of extra surbs in our if total_queue == 0 {
// storage. trace!("the pending queues for {:?} are already empty", target);
let total_queue_with_buffer = total_queue + min_surbs_buffer; return;
}
let request_size = min( let request_size = min(
self.config.reply_surbs.maximum_reply_surb_request_size, self.config.reply_surbs.maximum_reply_surb_request_size,
max( max(
total_queue_with_buffer, total_queue,
self.config.reply_surbs.minimum_reply_surb_request_size, self.config.reply_surbs.minimum_reply_surb_request_size,
), ),
); );
@@ -770,7 +713,7 @@ where
.request_additional_reply_surbs(target, request_size) .request_additional_reply_surbs(target, request_size)
.await .await
{ {
info!("{err}") warn!("failed to request additional surbs... - {err}")
} }
} }
@@ -903,11 +846,9 @@ where
// todo!() // todo!()
// } // }
pub(crate) async fn run(&mut self) { pub(crate) async fn run_with_shutdown(&mut self, mut shutdown: nym_task::TaskClient) {
debug!("Started ReplyController with graceful shutdown support"); debug!("Started ReplyController with graceful shutdown support");
let mut shutdown = self.task_client.fork("select");
let polling_rate = Duration::from_secs(5); let polling_rate = Duration::from_secs(5);
let mut stale_inspection = new_interval_stream(polling_rate); let mut stale_inspection = new_interval_stream(polling_rate);
@@ -919,7 +860,7 @@ where
while !shutdown.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
biased; biased;
_ = shutdown.recv() => { _ = shutdown.recv_with_delay() => {
log::trace!("ReplyController: Received shutdown"); log::trace!("ReplyController: Received shutdown");
}, },
req = self.request_receiver.next() => match req { req = self.request_receiver.next() => match req {
@@ -15,27 +15,6 @@ pub(crate) fn new_control_channels() -> (ReplyControllerSender, ReplyControllerR
(tx.into(), rx) (tx.into(), rx)
} }
#[derive(Debug, thiserror::Error)]
pub enum ReplyControllerSenderError {
#[error("failed to send retransmission data to reply controller")]
SendRetransmissionData(#[source] mpsc::TrySendError<ReplyControllerMessage>),
#[error("failed to send reply to reply controller")]
SendReply(#[source] mpsc::TrySendError<ReplyControllerMessage>),
#[error("failed to send additional surbs to reply controller")]
AdditionalSurbs(#[source] mpsc::TrySendError<ReplyControllerMessage>),
#[error("failed to send additional surbs request to reply controller")]
AdditionalSurbsRequest(#[source] mpsc::TrySendError<ReplyControllerMessage>),
#[error("failed to request lane queue length from reply controller")]
LaneQueueLength(#[source] mpsc::TrySendError<ReplyControllerMessage>),
#[error("response channel was dropped before we could receive the response")]
ResponseChannelDropped(#[source] oneshot::Canceled),
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ReplyControllerSender(mpsc::UnboundedSender<ReplyControllerMessage>); pub struct ReplyControllerSender(mpsc::UnboundedSender<ReplyControllerMessage>);
@@ -51,14 +30,14 @@ impl ReplyControllerSender {
recipient: AnonymousSenderTag, recipient: AnonymousSenderTag,
timed_out_ack: Weak<PendingAcknowledgement>, timed_out_ack: Weak<PendingAcknowledgement>,
extra_surb_request: bool, extra_surb_request: bool,
) -> Result<(), ReplyControllerSenderError> { ) {
self.0 self.0
.unbounded_send(ReplyControllerMessage::RetransmitReply { .unbounded_send(ReplyControllerMessage::RetransmitReply {
recipient, recipient,
timed_out_ack, timed_out_ack,
extra_surb_request, extra_surb_request,
}) })
.map_err(ReplyControllerSenderError::SendRetransmissionData) .expect("ReplyControllerReceiver has died!")
} }
pub(crate) fn send_reply( pub(crate) fn send_reply(
@@ -66,16 +45,14 @@ impl ReplyControllerSender {
recipient: AnonymousSenderTag, recipient: AnonymousSenderTag,
message: Vec<u8>, message: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
max_retransmissions: Option<u32>, ) {
) -> Result<(), ReplyControllerSenderError> {
self.0 self.0
.unbounded_send(ReplyControllerMessage::SendReply { .unbounded_send(ReplyControllerMessage::SendReply {
recipient, recipient,
message, message,
lane, lane,
max_retransmissions,
}) })
.map_err(ReplyControllerSenderError::SendReply) .expect("ReplyControllerReceiver has died!")
} }
pub(crate) fn send_additional_surbs( pub(crate) fn send_additional_surbs(
@@ -83,47 +60,42 @@ impl ReplyControllerSender {
sender_tag: AnonymousSenderTag, sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>, reply_surbs: Vec<ReplySurb>,
from_surb_request: bool, from_surb_request: bool,
) -> Result<(), ReplyControllerSenderError> { ) {
self.0 self.0
.unbounded_send(ReplyControllerMessage::AdditionalSurbs { .unbounded_send(ReplyControllerMessage::AdditionalSurbs {
sender_tag, sender_tag,
reply_surbs, reply_surbs,
from_surb_request, from_surb_request,
}) })
.map_err(ReplyControllerSenderError::AdditionalSurbs) .expect("ReplyControllerReceiver has died!")
} }
pub(crate) fn send_additional_surbs_request( pub(crate) fn send_additional_surbs_request(&self, recipient: Recipient, amount: u32) {
&self,
recipient: Recipient,
amount: u32,
) -> Result<(), ReplyControllerSenderError> {
self.0 self.0
.unbounded_send(ReplyControllerMessage::AdditionalSurbsRequest { .unbounded_send(ReplyControllerMessage::AdditionalSurbsRequest {
recipient: Box::new(recipient), recipient: Box::new(recipient),
amount, amount,
}) })
.map_err(ReplyControllerSenderError::AdditionalSurbsRequest) .expect("ReplyControllerReceiver has died!")
} }
pub async fn get_lane_queue_length( pub async fn get_lane_queue_length(&self, connection_id: ConnectionId) -> usize {
&self,
connection_id: ConnectionId,
) -> Result<usize, ReplyControllerSenderError> {
let (response_tx, response_rx) = oneshot::channel(); let (response_tx, response_rx) = oneshot::channel();
if let Err(err) = self self.0
.0
.unbounded_send(ReplyControllerMessage::LaneQueueLength { .unbounded_send(ReplyControllerMessage::LaneQueueLength {
connection_id, connection_id,
response_channel: response_tx, response_channel: response_tx,
}) })
{ .expect("ReplyControllerReceiver has died!");
return Err(ReplyControllerSenderError::LaneQueueLength(err));
}
response_rx match response_rx.await {
.await Ok(length) => length,
.map_err(ReplyControllerSenderError::ResponseChannelDropped) Err(_) => {
error!("The reply controller has dropped our response channel!");
// TODO: should we panic here instead? this message implies something weird and unrecoverable has happened
0
}
}
} }
} }
@@ -138,10 +110,7 @@ impl ReplyQueueLengths {
} }
} }
pub async fn get_lane_queue_length( pub async fn get_lane_queue_length(&self, connection_id: ConnectionId) -> usize {
&self,
connection_id: ConnectionId,
) -> Result<usize, ReplyControllerSenderError> {
self.reply_controller_sender self.reply_controller_sender
.get_lane_queue_length(connection_id) .get_lane_queue_length(connection_id)
.await .await
@@ -151,7 +120,7 @@ impl ReplyQueueLengths {
pub(crate) type ReplyControllerReceiver = mpsc::UnboundedReceiver<ReplyControllerMessage>; pub(crate) type ReplyControllerReceiver = mpsc::UnboundedReceiver<ReplyControllerMessage>;
#[derive(Debug)] #[derive(Debug)]
pub enum ReplyControllerMessage { pub(crate) enum ReplyControllerMessage {
RetransmitReply { RetransmitReply {
recipient: AnonymousSenderTag, recipient: AnonymousSenderTag,
timed_out_ack: Weak<PendingAcknowledgement>, timed_out_ack: Weak<PendingAcknowledgement>,
@@ -162,7 +131,6 @@ pub enum ReplyControllerMessage {
recipient: AnonymousSenderTag, recipient: AnonymousSenderTag,
message: Vec<u8>, message: Vec<u8>,
lane: TransmissionLane, lane: TransmissionLane,
max_retransmissions: Option<u32>,
}, },
AdditionalSurbs { AdditionalSurbs {
@@ -16,14 +16,14 @@
#![warn(clippy::todo)] #![warn(clippy::todo)]
#![warn(clippy::dbg_macro)] #![warn(clippy::dbg_macro)]
use futures::StreamExt; use std::time::Duration;
use nym_client_core_config_types::StatsReporting; use nym_client_core_config_types::StatsReporting;
use nym_sphinx::addressing::Recipient; use nym_sphinx::addressing::Recipient;
use nym_statistics_common::clients::{ use nym_statistics_common::clients::{
ClientStatsController, ClientStatsReceiver, ClientStatsSender, ClientStatsController, ClientStatsReceiver, ClientStatsSender,
}; };
use nym_task::{connections::TransmissionLane, TaskClient}; use nym_task::connections::TransmissionLane;
use std::time::Duration;
use crate::{ use crate::{
client::inbound_messages::{InputMessage, InputMessageSender}, client::inbound_messages::{InputMessage, InputMessageSender},
@@ -51,9 +51,6 @@ pub(crate) struct StatisticsControl {
/// Config for stats reporting (enabled, address, interval) /// Config for stats reporting (enabled, address, interval)
reporting_config: StatsReporting, reporting_config: StatsReporting,
/// Task client for listening for shutdown
task_client: TaskClient,
} }
impl StatisticsControl { impl StatisticsControl {
@@ -62,24 +59,19 @@ impl StatisticsControl {
client_type: String, client_type: String,
client_stats_id: String, client_stats_id: String,
report_tx: InputMessageSender, report_tx: InputMessageSender,
task_client: TaskClient,
) -> (Self, ClientStatsSender) { ) -> (Self, ClientStatsSender) {
let (stats_tx, stats_rx) = tokio::sync::mpsc::unbounded_channel(); let (stats_tx, stats_rx) = tokio::sync::mpsc::unbounded_channel();
let stats = ClientStatsController::new(client_stats_id, client_type); let stats = ClientStatsController::new(client_stats_id, client_type);
let mut task_client_stats_sender = task_client.fork("stats_sender");
task_client_stats_sender.disarm();
( (
StatisticsControl { StatisticsControl {
stats, stats,
stats_rx, stats_rx,
report_tx, report_tx,
reporting_config, reporting_config,
task_client,
}, },
ClientStatsSender::new(Some(stats_tx), task_client_stats_sender), ClientStatsSender::new(Some(stats_tx)),
) )
} }
@@ -99,43 +91,16 @@ impl StatisticsControl {
} }
} }
async fn run(&mut self) { async fn run_with_shutdown(&mut self, mut task_client: nym_task::TaskClient) {
log::debug!("Started StatisticsControl with graceful shutdown support"); log::debug!("Started StatisticsControl with graceful shutdown support");
#[cfg(not(target_arch = "wasm32"))] let mut stats_report_interval =
let mut stats_report_interval = tokio_stream::wrappers::IntervalStream::new( tokio::time::interval(self.reporting_config.reporting_interval);
tokio::time::interval(self.reporting_config.reporting_interval), let mut local_report_interval = tokio::time::interval(LOCAL_REPORT_INTERVAL);
); let mut snapshot_interval = tokio::time::interval(SNAPSHOT_INTERVAL);
#[cfg(not(target_arch = "wasm32"))] loop {
let mut local_report_interval = tokio_stream::wrappers::IntervalStream::new(
tokio::time::interval(LOCAL_REPORT_INTERVAL),
);
#[cfg(not(target_arch = "wasm32"))]
let mut snapshot_interval =
tokio_stream::wrappers::IntervalStream::new(tokio::time::interval(SNAPSHOT_INTERVAL));
#[cfg(target_arch = "wasm32")]
let mut stats_report_interval = gloo_timers::future::IntervalStream::new(
self.reporting_config.reporting_interval.as_millis() as u32,
);
#[cfg(target_arch = "wasm32")]
let mut local_report_interval =
gloo_timers::future::IntervalStream::new(LOCAL_REPORT_INTERVAL.as_millis() as u32);
#[cfg(target_arch = "wasm32")]
let mut snapshot_interval =
gloo_timers::future::IntervalStream::new(SNAPSHOT_INTERVAL.as_millis() as u32);
while !self.task_client.is_shutdown() {
tokio::select! { tokio::select! {
biased;
_ = self.task_client.recv() => {
log::trace!("StatisticsControl: Received shutdown");
break;
},
stats_event = self.stats_rx.recv() => match stats_event { stats_event = self.stats_rx.recv() => match stats_event {
Some(stats_event) => self.stats.handle_event(stats_event), Some(stats_event) => self.stats.handle_event(stats_event),
None => { None => {
@@ -143,48 +108,44 @@ impl StatisticsControl {
break; break;
} }
}, },
_ = snapshot_interval.next() => { _ = snapshot_interval.tick() => {
self.stats.snapshot(); self.stats.snapshot();
} }
_ = stats_report_interval.next() => { _ = stats_report_interval.tick(), if self.reporting_config.enabled && self.reporting_config.provider_address.is_some() => {
let Some(recipient) = self.reporting_config.provider_address else { // SAFTEY : this branch executes only if reporting is not none, so unwrapp is fine
continue #[allow(clippy::unwrap_used)]
}; self.report_stats(self.reporting_config.provider_address.unwrap()).await;
if self.reporting_config.enabled {
self.report_stats(recipient).await;
}
} }
_ = local_report_interval.next() => { _ = local_report_interval.tick() => {
self.stats.local_report(&mut self.task_client); self.stats.local_report(&mut task_client);
} }
_ = task_client.recv_with_delay() => {
log::trace!("StatisticsControl: Received shutdown");
break;
},
} }
} }
task_client.recv_timeout().await;
log::debug!("StatisticsControl: Exiting"); log::debug!("StatisticsControl: Exiting");
} }
pub(crate) fn start(mut self) { pub(crate) fn start_with_shutdown(mut self, task_client: nym_task::TaskClient) {
spawn_future(async move { spawn_future(async move {
self.run().await; self.run_with_shutdown(task_client).await;
}) })
} }
pub(crate) fn create_and_start( pub(crate) fn create_and_start_with_shutdown(
reporting_config: StatsReporting, reporting_config: StatsReporting,
client_type: String, client_type: String,
client_stats_id: String, client_stats_id: String,
report_tx: InputMessageSender, report_tx: InputMessageSender,
task_client: TaskClient, task_client: nym_task::TaskClient,
) -> ClientStatsSender { ) -> ClientStatsSender {
let (controller, sender) = Self::create( let (controller, sender) =
reporting_config, Self::create(reporting_config, client_type, client_stats_id, report_tx);
client_type, controller.start_with_shutdown(task_client);
client_stats_id,
report_tx,
task_client,
);
controller.start();
sender sender
} }
} }
@@ -6,7 +6,6 @@ pub(crate) use accessor::{TopologyAccessor, TopologyReadPermit};
use futures::StreamExt; use futures::StreamExt;
use log::*; use log::*;
use nym_sphinx::addressing::nodes::NodeIdentity; use nym_sphinx::addressing::nodes::NodeIdentity;
use nym_task::TaskClient;
use nym_topology::NymTopologyError; use nym_topology::NymTopologyError;
use std::time::Duration; use std::time::Duration;
@@ -44,8 +43,6 @@ pub struct TopologyRefresher {
refresh_rate: Duration, refresh_rate: Duration,
consecutive_failure_count: usize, consecutive_failure_count: usize,
task_client: TaskClient,
} }
impl TopologyRefresher { impl TopologyRefresher {
@@ -53,14 +50,12 @@ impl TopologyRefresher {
cfg: TopologyRefresherConfig, cfg: TopologyRefresherConfig,
topology_accessor: TopologyAccessor, topology_accessor: TopologyAccessor,
topology_provider: Box<dyn TopologyProvider + Send + Sync>, topology_provider: Box<dyn TopologyProvider + Send + Sync>,
task_client: TaskClient,
) -> Self { ) -> Self {
TopologyRefresher { TopologyRefresher {
topology_provider, topology_provider,
topology_accessor, topology_accessor,
refresh_rate: cfg.refresh_rate, refresh_rate: cfg.refresh_rate,
consecutive_failure_count: 0, consecutive_failure_count: 0,
task_client,
} }
} }
@@ -147,7 +142,7 @@ impl TopologyRefresher {
} }
} }
pub fn start(mut self) { pub fn start_with_shutdown(mut self, mut shutdown: nym_task::TaskClient) {
spawn_future(async move { spawn_future(async move {
debug!("Started TopologyRefresher with graceful shutdown support"); debug!("Started TopologyRefresher with graceful shutdown support");
@@ -160,17 +155,17 @@ impl TopologyRefresher {
let mut interval = let mut interval =
gloo_timers::future::IntervalStream::new(self.refresh_rate.as_millis() as u32); gloo_timers::future::IntervalStream::new(self.refresh_rate.as_millis() as u32);
while !self.task_client.is_shutdown() { while !shutdown.is_shutdown() {
tokio::select! { tokio::select! {
_ = interval.next() => { _ = interval.next() => {
self.try_refresh().await; self.try_refresh().await;
}, },
_ = self.task_client.recv() => { _ = shutdown.recv() => {
log::trace!("TopologyRefresher: Received shutdown"); log::trace!("TopologyRefresher: Received shutdown");
}, },
} }
} }
self.task_client.recv_timeout().await; shutdown.recv_timeout().await;
log::debug!("TopologyRefresher: Exiting"); log::debug!("TopologyRefresher: Exiting");
}) })
} }
@@ -58,8 +58,8 @@ impl<T> TransmissionBuffer<T> {
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub(crate) fn lanes(&self) -> Vec<TransmissionLane> { pub(crate) fn num_lanes(&self) -> usize {
self.buffer.keys().cloned().collect() self.buffer.keys().count()
} }
pub(crate) fn lane_length(&self, lane: &TransmissionLane) -> Option<usize> { pub(crate) fn lane_length(&self, lane: &TransmissionLane) -> Option<usize> {
@@ -83,7 +83,6 @@ impl<T> TransmissionBuffer<T> {
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
#[allow(unused)]
pub(crate) fn total_size_in_bytes(&self) -> usize pub(crate) fn total_size_in_bytes(&self) -> usize
where where
T: SizedData, T: SizedData,
-13
View File
@@ -36,13 +36,6 @@ pub enum ClientCoreError {
#[error("no gateway with id: {0}")] #[error("no gateway with id: {0}")]
NoGatewayWithId(String), NoGatewayWithId(String),
#[error("Invalid URL: {0}")]
InvalidUrl(String),
#[cfg(not(target_arch = "wasm32"))]
#[error("resolution failed: {0}")]
ResolutionFailed(#[from] nym_http_api_client::HickoryDnsError),
#[error("no gateways on network")] #[error("no gateways on network")]
NoGatewaysOnNetwork, NoGatewaysOnNetwork,
@@ -103,9 +96,6 @@ pub enum ClientCoreError {
#[error("timed out while trying to establish gateway connection")] #[error("timed out while trying to establish gateway connection")]
GatewayConnectionTimeout, GatewayConnectionTimeout,
#[error("failed to forward mix messages to gateway")]
GatewayFailedToForwardMessages,
#[error("no ping measurements for the gateway ({identity}) performed")] #[error("no ping measurements for the gateway ({identity}) performed")]
NoGatewayMeasurements { identity: String }, NoGatewayMeasurements { identity: String },
@@ -222,9 +212,6 @@ pub enum ClientCoreError {
"fresh registration with gateway {gateway_id} somehow requires an additional key upgrade!" "fresh registration with gateway {gateway_id} somehow requires an additional key upgrade!"
)] )]
UnexpectedKeyUpgrade { gateway_id: String }, UnexpectedKeyUpgrade { gateway_id: String },
#[error("failed to derive keys from master key")]
HkdfDerivationError {},
} }
/// Set of messages that the client can send to listeners via the task manager /// Set of messages that the client can send to listeners via the task manager
+6 -19
View File
@@ -11,15 +11,10 @@ use nym_topology::node::RoutingNode;
use nym_validator_client::client::IdentityKeyRef; use nym_validator_client::client::IdentityKeyRef;
use nym_validator_client::UserAgent; use nym_validator_client::UserAgent;
use rand::{seq::SliceRandom, Rng}; use rand::{seq::SliceRandom, Rng};
#[cfg(unix)]
use std::os::fd::RawFd;
use std::{sync::Arc, time::Duration}; use std::{sync::Arc, time::Duration};
use tungstenite::Message; use tungstenite::Message;
use url::Url; use url::Url;
#[cfg(not(target_arch = "wasm32"))]
use crate::init::websockets::connect_async;
use nym_topology::NodeId; use nym_topology::NodeId;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio::net::TcpStream; use tokio::net::TcpStream;
@@ -28,6 +23,8 @@ use tokio::time::sleep;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio::time::Instant; use tokio::time::Instant;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use tokio_tungstenite::connect_async;
#[cfg(not(target_arch = "wasm32"))]
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
use wasm_utils::websocket::JSWebsocket; use wasm_utils::websocket::JSWebsocket;
@@ -89,12 +86,11 @@ impl<'a, G: ConnectableGateway> GatewayWithLatency<'a, G> {
} }
} }
pub async fn gateways_for_init<R: Rng>( pub async fn current_gateways<R: Rng>(
rng: &mut R, rng: &mut R,
nym_apis: &[Url], nym_apis: &[Url],
user_agent: Option<UserAgent>, user_agent: Option<UserAgent>,
minimum_performance: u8, minimum_performance: u8,
ignore_epoch_roles: bool,
) -> Result<Vec<RoutingNode>, ClientCoreError> { ) -> Result<Vec<RoutingNode>, ClientCoreError> {
let nym_api = nym_apis let nym_api = nym_apis
.choose(rng) .choose(rng)
@@ -112,11 +108,8 @@ pub async fn gateways_for_init<R: Rng>(
log::trace!("Gateways: {:#?}", gateways); log::trace!("Gateways: {:#?}", gateways);
// filter out gateways below minimum performance and ones that could operate as a mixnode
// (we don't want instability)
let valid_gateways = gateways let valid_gateways = gateways
.iter() .iter()
.filter(|g| ignore_epoch_roles || !g.supported_roles.mixnode)
.filter(|g| g.performance.round_to_integer() >= minimum_performance) .filter(|g| g.performance.round_to_integer() >= minimum_performance)
.filter_map(|gateway| gateway.try_into().ok()) .filter_map(|gateway| gateway.try_into().ok())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@@ -135,7 +128,7 @@ pub async fn gateways_for_init<R: Rng>(
async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> { async fn connect(endpoint: &str) -> Result<WsConn, ClientCoreError> {
match tokio::time::timeout(CONN_TIMEOUT, connect_async(endpoint)).await { match tokio::time::timeout(CONN_TIMEOUT, connect_async(endpoint)).await {
Err(_elapsed) => Err(ClientCoreError::GatewayConnectionTimeout), Err(_elapsed) => Err(ClientCoreError::GatewayConnectionTimeout),
Ok(Err(conn_failure)) => Err(conn_failure), Ok(Err(conn_failure)) => Err(conn_failure.into()),
Ok(Ok((stream, _))) => Ok(stream), Ok(Ok((stream, _))) => Ok(stream),
} }
} }
@@ -315,15 +308,9 @@ pub(super) async fn register_with_gateway(
gateway_id: identity::PublicKey, gateway_id: identity::PublicKey,
gateway_listener: Url, gateway_listener: Url,
our_identity: Arc<identity::KeyPair>, our_identity: Arc<identity::KeyPair>,
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
) -> Result<RegistrationResult, ClientCoreError> { ) -> Result<RegistrationResult, ClientCoreError> {
let mut gateway_client = GatewayClient::new_init( let mut gateway_client =
gateway_listener, GatewayClient::new_init(gateway_listener, gateway_id, our_identity.clone());
gateway_id,
our_identity.clone(),
#[cfg(unix)]
connection_fd_callback,
);
gateway_client.establish_connection().await.map_err(|err| { gateway_client.establish_connection().await.map_err(|err| {
log::warn!("Failed to establish connection with gateway!"); log::warn!("Failed to establish connection with gateway!");
+4 -24
View File
@@ -23,13 +23,9 @@ use nym_topology::node::RoutingNode;
use rand::rngs::OsRng; use rand::rngs::OsRng;
use rand::{CryptoRng, RngCore}; use rand::{CryptoRng, RngCore};
use serde::Serialize; use serde::Serialize;
#[cfg(unix)]
use std::{os::fd::RawFd, sync::Arc};
pub mod helpers; pub mod helpers;
pub mod types; pub mod types;
#[cfg(not(target_arch = "wasm32"))]
pub(crate) mod websockets;
// helpers for error wrapping // helpers for error wrapping
@@ -55,7 +51,6 @@ async fn setup_new_gateway<K, D>(
details_store: &D, details_store: &D,
selection_specification: GatewaySelectionSpecification, selection_specification: GatewaySelectionSpecification,
available_gateways: Vec<RoutingNode>, available_gateways: Vec<RoutingNode>,
#[cfg(unix)] connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
) -> Result<InitialisationResult, ClientCoreError> ) -> Result<InitialisationResult, ClientCoreError>
where where
K: KeyStore, K: KeyStore,
@@ -111,14 +106,9 @@ where
// if we're using a 'normal' gateway setup, do register // if we're using a 'normal' gateway setup, do register
let our_identity = client_keys.identity_keypair(); let our_identity = client_keys.identity_keypair();
let registration = helpers::register_with_gateway( let registration =
gateway_id, helpers::register_with_gateway(gateway_id, gateway_listener.clone(), our_identity)
gateway_listener.clone(), .await?;
our_identity,
#[cfg(unix)]
connection_fd_callback,
)
.await?;
( (
GatewayDetails::new_remote( GatewayDetails::new_remote(
gateway_id, gateway_id,
@@ -211,19 +201,9 @@ where
GatewaySetup::New { GatewaySetup::New {
specification, specification,
available_gateways, available_gateways,
#[cfg(unix)]
connection_fd_callback,
} => { } => {
log::debug!("GatewaySetup::New with spec: {specification:?}"); log::debug!("GatewaySetup::New with spec: {specification:?}");
setup_new_gateway( setup_new_gateway(key_store, details_store, specification, available_gateways).await
key_store,
details_store,
specification,
available_gateways,
#[cfg(unix)]
connection_fd_callback,
)
.await
} }
GatewaySetup::ReuseConnection { GatewaySetup::ReuseConnection {
authenticated_ephemeral_client, authenticated_ephemeral_client,
+1 -39
View File
@@ -17,9 +17,7 @@ use nym_topology::node::RoutingNode;
use nym_validator_client::client::IdentityKey; use nym_validator_client::client::IdentityKey;
use nym_validator_client::nyxd::AccountId; use nym_validator_client::nyxd::AccountId;
use serde::Serialize; use serde::Serialize;
use std::fmt::{Debug, Display}; use std::fmt::Display;
#[cfg(unix)]
use std::os::fd::RawFd;
use std::sync::Arc; use std::sync::Arc;
use time::OffsetDateTime; use time::OffsetDateTime;
use url::Url; use url::Url;
@@ -210,10 +208,6 @@ pub enum GatewaySetup {
// TODO: seems to be a bit inefficient to pass them by value // TODO: seems to be a bit inefficient to pass them by value
available_gateways: Vec<RoutingNode>, available_gateways: Vec<RoutingNode>,
/// Callback useful for allowing initial connection to gateway
#[cfg(unix)]
connection_fd_callback: Option<Arc<dyn Fn(RawFd) + Send + Sync>>,
}, },
ReuseConnection { ReuseConnection {
@@ -227,36 +221,6 @@ pub enum GatewaySetup {
}, },
} }
impl Debug for GatewaySetup {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GatewaySetup::MustLoad { gateway_id } => f
.debug_struct("GatewaySetup::MustLoad")
.field("gateway_id", gateway_id)
.finish(),
GatewaySetup::New {
specification,
available_gateways,
#[cfg(unix)]
connection_fd_callback: _,
} => f
.debug_struct("GatewaySetup::New")
.field("specification", specification)
.field("available_gateways", available_gateways)
.field("gateways", specification)
.finish(),
GatewaySetup::ReuseConnection {
gateway_details, ..
} => f
.debug_struct("GatewaySetup::ReuseConnection")
.field("authenticated_ephemeral_client", &"***")
.field("gateway_details", gateway_details)
.field("client_keys", &"***")
.finish(),
}
}
}
impl GatewaySetup { impl GatewaySetup {
pub fn try_reuse_connection(init_res: InitialisationResult) -> Result<Self, ClientCoreError> { pub fn try_reuse_connection(init_res: InitialisationResult) -> Result<Self, ClientCoreError> {
if let Some(authenticated_ephemeral_client) = init_res.authenticated_ephemeral_client { if let Some(authenticated_ephemeral_client) = init_res.authenticated_ephemeral_client {
@@ -278,8 +242,6 @@ impl GatewaySetup {
additional_data: None, additional_data: None,
}, },
available_gateways: vec![], available_gateways: vec![],
#[cfg(unix)]
connection_fd_callback: None,
} }
} }
-44
View File
@@ -1,44 +0,0 @@
use crate::error::ClientCoreError;
use nym_http_api_client::HickoryDnsResolver;
use tokio::net::TcpStream;
use tokio_tungstenite::{MaybeTlsStream, WebSocketStream};
use tungstenite::handshake::client::Response;
use url::{Host, Url};
use std::net::SocketAddr;
#[cfg(not(target_arch = "wasm32"))]
pub(crate) async fn connect_async(
endpoint: &str,
) -> Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response), ClientCoreError> {
let resolver = HickoryDnsResolver::default();
let uri = Url::parse(endpoint).map_err(|_| ClientCoreError::InvalidUrl(endpoint.to_owned()))?;
let port: u16 = uri.port_or_known_default().unwrap_or(443);
let host = uri
.host()
.ok_or(ClientCoreError::InvalidUrl(endpoint.to_owned()))?;
// Get address for tcp connection, if a domain is provided use our preferred resolver rather than
// the default std resolve
let sock_addrs: Vec<SocketAddr> = match host {
Host::Ipv4(addr) => vec![SocketAddr::new(addr.into(), port)],
Host::Ipv6(addr) => vec![SocketAddr::new(addr.into(), port)],
Host::Domain(domain) => {
// Do a DNS lookup for the domain using our custom DNS resolver
resolver
.resolve_str(domain)
.await?
.into_iter()
.map(|a| SocketAddr::new(a, port))
.collect()
}
};
let stream = TcpStream::connect(&sock_addrs[..]).await?;
tokio_tungstenite::client_async_tls(endpoint, stream)
.await
.map_err(Into::into)
}
+45
View File
@@ -33,3 +33,48 @@ where
{ {
tokio::spawn(future); tokio::spawn(future);
} }
#[derive(Clone, Default, Debug)]
pub struct ForgetMe {
client: bool,
stats: bool,
}
impl ForgetMe {
pub fn new_all() -> Self {
Self {
client: true,
stats: true,
}
}
pub fn new_client() -> Self {
Self {
client: true,
stats: false,
}
}
pub fn new_stats() -> Self {
Self {
client: false,
stats: true,
}
}
pub fn new(client: bool, stats: bool) -> Self {
Self { client, stats }
}
pub fn any(&self) -> bool {
self.client || self.stats
}
pub fn client(&self) -> bool {
self.client
}
pub fn stats(&self) -> bool {
self.stats
}
}

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