Files
nym/common/nymsphinx/anonymous-replies/src/requests.rs
T
Jędrzej Stuczyński a7d8613c9d Multi-surbs (#2667)
* Feature/multi surbs (#1796)

* bunch of wip with focus on serialization

* Being able to send normal data (NO SURBS yet) to yourself again

* Fixed RepliableMessage deserialization

* Recovering data from surb messages

* Extracted common code in sphinx payload construction

* Cleanup within received buffer

* requesting, sending and using additional reply surbs

* Following discussion with @simonwicky, removing sender proof and decreasing size of sender tag

* Made sender tag more easily configurable

* Refactoring of message creation

* Propagating reply surb acks but not retransmitting them yet

* Surb retransmissions

* requesting additional surbs from the retransmission flow

* correctly determining the point of requesting additional surbs

* Ability to use socks5 (and network requester) with surbs

* Improved surbs retranmsission reliability

* naive way of not over-requesting surbs

* wip on tag storage

* Improved error propagation for message construction

* Requesting more surbs for stale entries

* Better controlling the point of having to request additional surbs

* Using pseudorandom sender tag instead of a hardcoded one

* First cleanup round in MessageHandler

* Error cleanup and if simplification

* Assigned a more permanent name to the ReplyController

* Removed PendingReply redundant type

* Made socks5 client less eager to over-send reply surbs

* 'anonymous' field on socks5 client to decide whether to use surbs or attach address

* Dead code and import removal in client-core

* Updating ClientRequest variants

* Adjusted decision threshold for requesting more surbs

* Native client cleanup

* Made socks5 client usage of surbs configurable

* Restored statistics in network requester

* Validator-api compiles once again

* Further improved surb request logic

* boxing the recipient in controller requests

* Removal of hardcoded values in favour of propagating them from the config

* more validation during surb requests

* Fixed ClientRequest::Send deserialization

* Added length checks for request deserialization

* post-merge formatting

* Unit tests once again compile and pass

* controlling retransmission_reply_surb_request_size from config

* More Recipient boxing action

* Requesting additional reply surbs for retransmission BEFORE dipping below the threshold

* Making clippy generally happier

* Wasm client compiles (but might not yet work correctly)

* Feature/use expect instead of panicking (#1797)

* Implementation of 'Debug' on 'RealMessage'

* expect with failed channel name instead of throwing empty panics

* Introduced Debug trait constraint in ProxyRunner

* Derive Debug for socks5_requests::Message

* Fix decrypting stored received msg (#1786)

* Fix decrypting stored received msg

* rustfmt

* Moving binary message recovery to separate function

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>

* real_traffic_stream: reduce frequency of status print (#1794)

* Properly defined unnamed errors

* Dealing with previously ignored errors

* logging improvements

* Removed old example code

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>

* Missing changelog entry for multi-surbs (#1802)

* Making anonymous sender tag human readable (#1801)

* Created wrapper with string serialization for AnonymousSenderTag

* Using Display implementation of AnonymousSenderTag for logs

* Using Display implementation of MessageRecoveryError when logging (#1803)

* Using Display implementation of MessageRecoveryError when logging

* Updated changelog

* Defined socks5 client startup flag to enable reply-surb communication (#1804)

* Feature/persistent surbs data (#1835)

* prototyping wip

* Implemented ReplyStorageBackend trait for the sql-backed storage

* Storing correct surb threshold

* using correct database path

* Starting surb persistent storage in native and socks5 clients

* loading or creating fresh surb storage in socks5 and native clients

* making clippy happier + fixing config templates

* Creating status table on database rotation

* Completed the 'Empty' ReplyStorageBackend

* feature locking wasm-incompatible bits and pieces

* Feature/develop resync (#1844)

* Network-requester: throttle inbound connections (#1789)

* Return and handle ClientRequest::LaneQueueLenghts

* Pass lane queue lengths to inbound future

* Remove unused self reference

* Request lane queue lengths periodically for all open connections

* Add timeouts

* Rename to ConnectionCommandSender and Receiver

* Rename to client_connection_tx/rx

* Fix wasm build

* Replace bool with enum

* rust: bump required version to 1.65 in some crates that need it

* Add step to release GH actions (#1792)

* feat: add a release step to nym contracts GH action

* feat: add shrinking the size of wasm

* Possibilty to change gateway ws listener (#1779)

* add: set gatewayListener

* Update types.ts

* Update worker.ts

* Update contracts-build.yml

* real_traffic_stream: reduce frequency of status print (#1794)

* Update wallet and connect lock files (#1793)

* client-core: add warning when delay multiplier is larger than 1

* Fix decrypting stored received msg (#1786)

* Fix decrypting stored received msg

* rustfmt

* Moving binary message recovery to separate function

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>

* Feature/use expect instead of panicking (#1797)

* Implementation of 'Debug' on 'RealMessage'

* expect with failed channel name instead of throwing empty panics

* Introduced Debug trait constraint in ProxyRunner

* Derive Debug for socks5_requests::Message

* Make connection_id optional in ClientRequest::Send (#1798)

* changelog: add missing entry for fixing message decrypt in gateway-client

* websocket-requests: fix length check before deserialize (#1799)

* Fix export dkg contract addr (#1800)

* Export dkg contract for mainnet when no config file present

* Remove redundant env files

* nym-cli: improve error reporting/handling and changed `vesting-schedule` queries to use query client instead of signing client

* Feature/gateway client protocol version (#1795)

* Introducing concept of gateway protocol version

* Remove version-based gateway filtering

* Fixed the unit test

* grammar

* Set build on latest release on schedule event

* Added nightly build workflow on second latest release

* socks5: if any task panics, signal all other tasks to shutdown (#1805)

* socks5: signal shutdown on error

* Mark as success

* Tidy

* Reduce wait to 5 sec

* Replace unwrap with expect

* Two more unwraps

* Update changelog

* client-core: less frequent status logging (#1806)

* Feature/nym connect UI updates (#1784)

* create custom titlebar

* create help page

* create generic modal component

* create separate connection time component

* link to shipyard docs

* move timer to separate component and update connection status component usage

* use separate component for copying ip and port details

* only show infomodal once after connection

* set service provider on tauri side

* Emit events when stopped

* listen and unlisten for tauri events

* connect: add trace log to get_services

* Add back CI notifications

* Update README

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>
Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>

* Use default serde value for upgrade (#1807)

* fix ui overflow bug (#1808)

* update nym connect error text (#1809)

* set flag to false

* Fix wait_for_signal_and_error on win (#1811)

* Add socks5-client changes to nym-connect changelog

* Fix links in nym-connect changelog

* More entries in nym-connect CHANGELOG

* Fix typo in changelog

* Update CHANGELOG.md

* Experiment/client refactoring (#1814)

* experimenting with extracting more common client code

* drying up the wasm client

* allowing some dead code for the time being

* fixed formatting in nym-connect

* made socks5 client inside nym-connect immutable

* made clippy a bit happier

* hidden away target locking for recv timeout

* New transactions for increasing amount of pledged tokens

* unit tests

* Added an option to pledge extra tokens through the vesting contract

* Introduced wallet endpoints for new operations

* Using updated pledge cap in the vesting contract

* Bumping version numbers

* Changelog for v1.1.1

* Bumping final version numbers for 1.1.1

* Bumping nym-cli version, missed it last time

* socks5-client: SOCKS4a support (#1822)

* socks5-client: SOCKS4a support

* Tidy

* Fix a few errors in socks5 client and network-requester (#1823)

* Fix two unwraps in socks5 and network-requester

* Make sure client task never sends shutdown signal

* Fix panic on getting socks version

* wip

* connecting to the back and making the requests work

* display details modal

* logs removal

* Feature/pledge more (#1679)

* New transactions for increasing amount of pledged tokens

* unit tests

* Added an option to pledge extra tokens through the vesting contract

* Introduced wallet endpoints for new operations

* Using updated pledge cap in the vesting contract

* Changelog update

* nym-connect: update lock file

* avoid mix tokens pools

* amount error

* envs/mainnet: update to latest mixnet contract and nymd validator url

* validator-api: add missing shortform for --config-env-file (#1830)

* gateway-client: handle shutdown listener (#1829)

* WIP

* WIP: try another approach

* WIP

* Reworked

* Tidy

* fix

* validator-api: remove storage dependency in contract cache (#1685)

* validator-api: remove storage dependency in contract cache

* validator-client: update detailed routes

* contract_cache: forward to new endpoints for compat

* Move reward_estimate

* client: add --no-cover and update --fastmode (#1831)

* adding a oversaturaded bonding more modal

* common/task: extract out spawn_with_report_error (#1837)

* stop panic on failed buffer request

* Compilable wasm client

* Enabled hard error on lack of gateway-client protocol version

* Missing generic parameter for ClientCoreError in BackendError

* Removed unused imports

* Additional wasm feature locking

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>
Co-authored-by: Fran Arbanas <arbanasfran@gmail.com>
Co-authored-by: cgi-bin/ <6095048+sven-hash@users.noreply.github.com>
Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>
Co-authored-by: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
Co-authored-by: Raphaël Walther <raphael@nymtech.net>
Co-authored-by: Fouad <fmtabbara@hotmail.co.uk>
Co-authored-by: Gala <calero.vg@gmail.com>
Co-authored-by: Dave Hrycyszyn <futurechimp@users.noreply.github.com>

* Making native client wait for shutdown

* Marking dead test code

* Feature/multi surbs invalidation (#1858)

* Cleaned up RealMessagesController constructor

* introduced config field for maximum_reply_surb_age

* Handling edge-case reply-surb failures

* invalidating old reply surbs

* Removing old reply keys from cache

* Invalidating old reply keys

* missing config changes

* logging created tag details

* Fixed clippy warning in test code

* Saving reply key timestamp on data flush (#1867)

* Remove panic if ReconstructedMessagesReceiver is closed (#1868)

Instead log error and return because presumably the shutdown procedure has started

* Feature/multi surbs basic wasm interface (#1846)

* Added builder to wasm client

* missing wasm_bindgen macros

* Added constructor macro on GatewayEndpointConfig

* Attempting to use updated wasm client api

* Removing dead code

* Exposed other messages types in wasm client

* cleanup in js-example

* Changed 'self_address' to be a method call

* Removed needless borrow when cloning an Arc

* Improving arguments in 'on_message' callback

* fixed wasm-client dependency/features

* Reverted hard requirement for gateway protocol presence (#1875)

* Feature/prioritise surb retransmission (#1883)

* Improved error messages + removed redundant variants

* Improved estimation of 'expected_forward_delay'

* Removed old wasm-specific startup code

* Removed old unused reply-related code

* hacky and temporary way of buffering retransmission data

* offloading retransmission reply handling to ReplyController

* fixed linter errors + rebuffering retransmission data on failure

* Removed unused fields from wasm client debug config

* Chore/v1.2.0 update (#2666)

* Network-requester: throttle inbound connections (#1789)

* Return and handle ClientRequest::LaneQueueLenghts

* Pass lane queue lengths to inbound future

* Remove unused self reference

* Request lane queue lengths periodically for all open connections

* Add timeouts

* Rename to ConnectionCommandSender and Receiver

* Rename to client_connection_tx/rx

* Fix wasm build

* Replace bool with enum

* rust: bump required version to 1.65 in some crates that need it

* Add step to release GH actions (#1792)

* feat: add a release step to nym contracts GH action

* feat: add shrinking the size of wasm

* Possibilty to change gateway ws listener (#1779)

* add: set gatewayListener

* Update types.ts

* Update worker.ts

* Update contracts-build.yml

* real_traffic_stream: reduce frequency of status print (#1794)

* Update wallet and connect lock files (#1793)

* client-core: add warning when delay multiplier is larger than 1

* Fix decrypting stored received msg (#1786)

* Fix decrypting stored received msg

* rustfmt

* Moving binary message recovery to separate function

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>

* Feature/use expect instead of panicking (#1797)

* Implementation of 'Debug' on 'RealMessage'

* expect with failed channel name instead of throwing empty panics

* Introduced Debug trait constraint in ProxyRunner

* Derive Debug for socks5_requests::Message

* Make connection_id optional in ClientRequest::Send (#1798)

* changelog: add missing entry for fixing message decrypt in gateway-client

* websocket-requests: fix length check before deserialize (#1799)

* Fix export dkg contract addr (#1800)

* Export dkg contract for mainnet when no config file present

* Remove redundant env files

* nym-cli: improve error reporting/handling and changed `vesting-schedule` queries to use query client instead of signing client

* Feature/gateway client protocol version (#1795)

* Introducing concept of gateway protocol version

* Remove version-based gateway filtering

* Fixed the unit test

* grammar

* Set build on latest release on schedule event

* feat(wallet): buy page bootstrap

* feat(wallet-buy): tutorial

* feat(explorer-api): add route to fetch nym terms&cdts

* Revert "feat(explorer-api): add route to fetch nym terms&cdts"

This reverts commit 876f752697d89061b1904e1ddd1d5bcb7045dc5c.

* feat(wallet-buy-nym): buy page new ui

* fix(wallet-buy-nym): signature output

* feat(wallet-buy-nym): update signature modal ui

* Added nightly build workflow on second latest release

* socks5: if any task panics, signal all other tasks to shutdown (#1805)

* socks5: signal shutdown on error

* Mark as success

* Tidy

* Reduce wait to 5 sec

* Replace unwrap with expect

* Two more unwraps

* Update changelog

* client-core: less frequent status logging (#1806)

* Feature/nym connect UI updates (#1784)

* create custom titlebar

* create help page

* create generic modal component

* create separate connection time component

* link to shipyard docs

* move timer to separate component and update connection status component usage

* use separate component for copying ip and port details

* only show infomodal once after connection

* set service provider on tauri side

* Emit events when stopped

* listen and unlisten for tauri events

* connect: add trace log to get_services

* Add back CI notifications

* Update README

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>
Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>

* Use default serde value for upgrade (#1807)

* fix ui overflow bug (#1808)

* feat(wallet): add link to nym exchange interface

* update nym connect error text (#1809)

* refactor(wallet): clean code

* set flag to false

* Fix wait_for_signal_and_error on win (#1811)

* Use config URLs in clients before the env values (#1813)

* Add socks5-client changes to nym-connect changelog

* Fix links in nym-connect changelog

* More entries in nym-connect CHANGELOG

* Fix typo in changelog

* Update CHANGELOG.md

* Experiment/client refactoring (#1814)

* experimenting with extracting more common client code

* drying up the wasm client

* allowing some dead code for the time being

* fixed formatting in nym-connect

* made socks5 client inside nym-connect immutable

* made clippy a bit happier

* hidden away target locking for recv timeout

* New transactions for increasing amount of pledged tokens

* unit tests

* Added an option to pledge extra tokens through the vesting contract

* Introduced wallet endpoints for new operations

* Using updated pledge cap in the vesting contract

* Feature/dkg integration tests (#1815)

* DKG contract e2e test

* Refactor to the same format as other contracts

* Vk share tests

* State tests

* Dealings tests

* Dealer tests

* Api dkg tests

* Fix path to contract after refactor

* Fix test target clippy

* Bumping version numbers

* Changelog for v1.1.1

* Bumping final version numbers for 1.1.1

* Bumping nym-cli version, missed it last time

* socks5-client: SOCKS4a support (#1822)

* socks5-client: SOCKS4a support

* Tidy

* Fix a few errors in socks5 client and network-requester (#1823)

* Fix two unwraps in socks5 and network-requester

* Make sure client task never sends shutdown signal

* Fix panic on getting socks version

* wip

* connecting to the back and making the requests work

* display details modal

* logs removal

* Feature/pledge more (#1679)

* New transactions for increasing amount of pledged tokens

* unit tests

* Added an option to pledge extra tokens through the vesting contract

* Introduced wallet endpoints for new operations

* Using updated pledge cap in the vesting contract

* Changelog update

* Feature/pledge more (#1679)

* New transactions for increasing amount of pledged tokens

* unit tests

* Added an option to pledge extra tokens through the vesting contract

* Introduced wallet endpoints for new operations

* Using updated pledge cap in the vesting contract

* Changelog update

* Fix a few errors in socks5 client and network-requester (backport) (#1824)

* Fix two unwraps in socks5 and network-requester

* Make sure client task never sends shutdown signal

* nym-connect: update lock file

* fix(wallet): typo

* avoid mix tokens pools

* fix(wallet): typo

* fix(wallet): buy tutorial ui responsivness

* amount error

* envs/mainnet: update to latest mixnet contract and nymd validator url

* validator-api: add missing shortform for --config-env-file (#1830)

* gateway-client: handle shutdown listener (#1829)

* WIP

* WIP: try another approach

* WIP

* Reworked

* Tidy

* fix

* validator-api: remove storage dependency in contract cache (#1685)

* validator-api: remove storage dependency in contract cache

* validator-client: update detailed routes

* contract_cache: forward to new endpoints for compat

* Move reward_estimate

* Node family management (#1670)

* Family management messages

* Add family queries

* Add queries to client

* Layer assignment message

* Paged family queries, annotate mixnodes with family

* Add layer assignments to epoch operations

* Remove family layer peristence

* Add NotImplemented error for kick

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>

* Fixed layer distribution skewness check (#1766)

* client: add --no-cover and update --fastmode (#1831)

* adding a oversaturaded bonding more modal

* Use better naming on gateway credential handling (#1834)

* Fix comment in configuration file (#1836)

* common/task: extract out spawn_with_report_error (#1837)

* nym-connect/changelog: add note about disconnect fix

* Feature/simplify credential binary (#1841)

* Expose name of standard directories

* Use one command instead of two

* nym-connect: append error to failed message (#1839)

* nym-connect: append error to failed message

* changelog: add note

* Fix clippy

* remove extra checks to display vesting schedule(#1826)

* Set explorer to use rpc.nymtech.net

* update versions for platfrom, nym-connect and nym-wallet to v1.1.2

* changed nym-connect version to 1.1.1

* Modifying changelog for v1.1.2

* changed nym-connect version to 1.1.2

* update nym-connect CHANGELOG

* Updated changelog for wallet

* Feature/wallet content updates (#1825)

* fix up balance screen

* fix up app bar and nym logo alignment

* fix up delegation action icon font weight

* fix up bond page

* Corrected env variable name in workflows

* Use config URLs in clients before the env values (#1813)

* Feature/dkg integration tests (#1815)

* DKG contract e2e test

* Refactor to the same format as other contracts

* Vk share tests

* State tests

* Dealings tests

* Dealer tests

* Api dkg tests

* Fix path to contract after refactor

* Fix test target clippy

* Node family management (#1670)

* Family management messages

* Add family queries

* Add queries to client

* Layer assignment message

* Paged family queries, annotate mixnodes with family

* Add layer assignments to epoch operations

* Remove family layer peristence

* Add NotImplemented error for kick

Co-authored-by: Jędrzej Stuczyński <jedrzej.stuczynski@gmail.com>

* Fixed layer distribution skewness check (#1766)

* Use better naming on gateway credential handling (#1834)

* Fix comment in configuration file (#1836)

* nym-connect/changelog: add note about disconnect fix

* Feature/simplify credential binary (#1841)

* Expose name of standard directories

* Use one command instead of two

* Fix clippy

* feat(wallet): buy page bootstrap

* feat(wallet-buy): tutorial

* feat(explorer-api): add route to fetch nym terms&cdts

* Revert "feat(explorer-api): add route to fetch nym terms&cdts"

This reverts commit 876f752697d89061b1904e1ddd1d5bcb7045dc5c.

* feat(wallet-buy-nym): buy page new ui

* fix(wallet-buy-nym): signature output

* feat(wallet-buy-nym): update signature modal ui

* feat(wallet): add link to nym exchange interface

* refactor(wallet): clean code

* fix(wallet): typo

* fix(wallet): typo

* fix(wallet): buy tutorial ui responsivness

* update versions for platfrom, nym-connect and nym-wallet to v1.1.2

* changed nym-connect version to 1.1.1

* Modifying changelog for v1.1.2

* changed nym-connect version to 1.1.2

* update nym-connect CHANGELOG

* Updated changelog for wallet

* Resolve merge conflicts

* Update qa-qwerty.env

* Fixed URL to branch

* changed ubuntu-latest on GH actions to ubuntu-20.04

* docs: updated changelog for contracts release v1.1.2 and updated versions of mixnet and vesting contracts as well

* Add ignore to dkg expensive tests (#1856)

* introduce minimize button in custom title bar (#1843)

* refresh balance after sending tokens (#1857)

* Feature/fix client multi cred consume (#1859)

* Mark consumed credentials in the db

* Add signature log

* Fix wasm mock Storage trait

* Fix clippy

* Feature/verify bte proof (#1866)

* Update lock file

* Include bte public key verification

* Wallet - Buy, copy changes (#1855)

* use mix_id for account to get correct pending cost event (#1869)

* use mix_id for account to get correct pending cost event

* Properly add consumed to table (#1870)

* nym-connect: update Cargo.lock to 1.1.2

* Clients: save init results to JSON (#1865)

* clients: output results of init to json

* Remove leftover dbg

* Tidy

* Fix nym-connect

* Client: dedup setup gateway during init (#1871)

* clients: dedup gateway setup logic

* nym-connect: extract out print_save_config

* Feature/dkg state to disk (#1872)

* Add PersistentState

* Save and load state to/from disk

* If in progress, don't continually write the same state

* Fix tests and add serde one

* Update changelog

* Fix clippy

* network-requester: return error on socket close (#1876)

* network-requester: return error when the socket closes

* changelog: add note

* clients: further deduplicate init code (#1873)

* client-core: move init helpers to module

* WIP

* socks5: return error instead of terminate in init

* Extract out reuse_existing_gateway_config

* rustfmt

* Remove comment out code

* nym-connect: use setup_gateway

* Linebreak

* changelog: update

* Tweak log

* rustfmt

* client: pick from old lanes probabilisticlly (#1877)

* Pick from old lanes probabilisticly

* changelog: update

* clients: dont panic in base client gateway client handling (#1878)

* client-core: fix some panics related to gateway-client

* changelog: update

* fix

* changelog: fix wording

* Use default mainnet values when nothing is specified (#1884)

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>
Co-authored-by: Fran Arbanas <arbanasfran@gmail.com>
Co-authored-by: cgi-bin/ <6095048+sven-hash@users.noreply.github.com>
Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>
Co-authored-by: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
Co-authored-by: Raphaël Walther <raphael@nymtech.net>
Co-authored-by: pierre <dommerc.pierre@gmail.com>
Co-authored-by: Fouad <fmtabbara@hotmail.co.uk>
Co-authored-by: Gala <calero.vg@gmail.com>
Co-authored-by: Dave Hrycyszyn <futurechimp@users.noreply.github.com>
Co-authored-by: Drazen Urch <drazen@urch.eu>
Co-authored-by: durch <durch@users.noreply.github.com>
Co-authored-by: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com>

Co-authored-by: Jon Häggblad <jon.haggblad@gmail.com>
Co-authored-by: Fran Arbanas <arbanasfran@gmail.com>
Co-authored-by: cgi-bin/ <6095048+sven-hash@users.noreply.github.com>
Co-authored-by: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com>
Co-authored-by: Bogdan-Ștefan Neacşu <bogdan@nymtech.net>
Co-authored-by: Mark Sinclair <mmsinclair@users.noreply.github.com>
Co-authored-by: Raphaël Walther <raphael@nymtech.net>
Co-authored-by: Fouad <fmtabbara@hotmail.co.uk>
Co-authored-by: Gala <calero.vg@gmail.com>
Co-authored-by: Dave Hrycyszyn <futurechimp@users.noreply.github.com>
Co-authored-by: pierre <dommerc.pierre@gmail.com>
Co-authored-by: Drazen Urch <drazen@urch.eu>
Co-authored-by: durch <durch@users.noreply.github.com>
Co-authored-by: Tommy Verrall <60836166+tommyv1987@users.noreply.github.com>
2022-12-13 12:11:30 +00:00

477 lines
15 KiB
Rust

// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::{ReplySurb, ReplySurbError};
use nymsphinx_addressing::clients::{Recipient, RecipientFormattingError};
use rand::{CryptoRng, RngCore};
use std::fmt::{Display, Formatter};
use std::mem;
use thiserror::Error;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
pub const SENDER_TAG_SIZE: usize = 16;
#[derive(Debug, Error)]
pub enum InvalidAnonymousSenderTagRepresentation {
#[error("Failed to decode the base58-encoded string - {0}")]
MalformedString(#[from] bs58::decode::Error),
#[error(
"Decoded AnonymousSenderTag has invalid length. Expected {expected}, but got {received}"
)]
InvalidLength { received: usize, expected: usize },
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
pub struct AnonymousSenderTag([u8; SENDER_TAG_SIZE]);
impl From<[u8; SENDER_TAG_SIZE]> for AnonymousSenderTag {
fn from(bytes: [u8; SENDER_TAG_SIZE]) -> Self {
AnonymousSenderTag(bytes)
}
}
impl Display for AnonymousSenderTag {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_base58_string())
}
}
impl AnonymousSenderTag {
pub fn new_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let mut bytes = [0u8; SENDER_TAG_SIZE];
rng.fill_bytes(&mut bytes);
AnonymousSenderTag(bytes)
}
pub fn to_bytes(&self) -> [u8; SENDER_TAG_SIZE] {
self.0
}
pub fn from_bytes(bytes: [u8; SENDER_TAG_SIZE]) -> Self {
AnonymousSenderTag(bytes)
}
pub fn to_base58_string(self) -> String {
bs58::encode(self.to_bytes()).into_string()
}
pub fn try_from_base58_string<I: AsRef<[u8]>>(
val: I,
) -> Result<Self, InvalidAnonymousSenderTagRepresentation> {
let bytes = bs58::decode(val).into_vec()?;
if bytes.len() != SENDER_TAG_SIZE {
return Err(InvalidAnonymousSenderTagRepresentation::InvalidLength {
received: bytes.len(),
expected: SENDER_TAG_SIZE,
});
}
// the unwrap here is fine as we just asserted the bytes are of exactly SENDER_TAG_SIZE length
let byte_array: [u8; SENDER_TAG_SIZE] = bytes.try_into().unwrap();
Ok(AnonymousSenderTag::from_bytes(byte_array))
}
}
#[derive(Debug, Error)]
pub enum InvalidReplyRequestError {
#[error("Did not provide sufficient number of bytes to deserialize a valid request")]
RequestTooShortToDeserialize,
#[error("{received} is not a valid content tag for a repliable message")]
InvalidRepliableContentTag { received: u8 },
#[error("{received} is not a valid content tag for a reply message")]
InvalidReplyContentTag { received: u8 },
#[error("failed to deserialize recipient information - {0}")]
MalformedRecipient(#[from] RecipientFormattingError),
#[error("failed to deserialize replySURB - {0}")]
MalformedReplySurb(#[from] ReplySurbError),
}
#[derive(Debug)]
pub struct RepliableMessage {
pub sender_tag: AnonymousSenderTag,
pub content: RepliableMessageContent,
}
impl Display for RepliableMessage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.content {
RepliableMessageContent::Data {
message,
reply_surbs,
} => write!(
f,
"repliable {:.2} kiB data message with {} reply surbs attached from {}",
message.len() as f64 / 1024.0,
reply_surbs.len(),
self.sender_tag,
),
RepliableMessageContent::AdditionalSurbs { reply_surbs } => write!(
f,
"repliable additional surbs message ({} reply surbs attached) from {}",
reply_surbs.len(),
self.sender_tag,
),
RepliableMessageContent::Heartbeat {
additional_reply_surbs,
} => {
write!(
f,
"repliable heartbeat message ({} reply surbs attached) from {}",
additional_reply_surbs.len(),
self.sender_tag,
)
}
}
}
}
impl RepliableMessage {
pub fn new_data(
data: Vec<u8>,
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>,
) -> Self {
RepliableMessage {
sender_tag,
content: RepliableMessageContent::Data {
message: data,
reply_surbs,
},
}
}
pub fn new_additional_surbs(
sender_tag: AnonymousSenderTag,
reply_surbs: Vec<ReplySurb>,
) -> Self {
RepliableMessage {
sender_tag,
content: RepliableMessageContent::AdditionalSurbs { reply_surbs },
}
}
pub fn into_bytes(self) -> Vec<u8> {
let content_tag = self.content.tag();
self.sender_tag
.to_bytes()
.into_iter()
.chain(std::iter::once(content_tag as u8))
.chain(self.content.into_bytes())
.collect()
}
pub fn try_from_bytes(
bytes: &[u8],
num_mix_hops: u8,
) -> Result<Self, InvalidReplyRequestError> {
if bytes.len() < SENDER_TAG_SIZE + 1 {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let sender_tag =
AnonymousSenderTag::from_bytes(bytes[..SENDER_TAG_SIZE].try_into().unwrap());
let content_tag = RepliableMessageContentTag::try_from(bytes[SENDER_TAG_SIZE])?;
let content = RepliableMessageContent::try_from_bytes(
&bytes[SENDER_TAG_SIZE + 1..],
num_mix_hops,
content_tag,
)?;
Ok(RepliableMessage {
sender_tag,
content,
})
}
}
// this recovery code is shared between all variants containing reply surbs
fn recover_reply_surbs(
bytes: &[u8],
num_mix_hops: u8,
) -> Result<(Vec<ReplySurb>, usize), InvalidReplyRequestError> {
let mut consumed = mem::size_of::<u32>();
if bytes.len() < consumed {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let num_surbs = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
let surb_size = ReplySurb::serialized_len(num_mix_hops);
if bytes[consumed..].len() < num_surbs as usize * surb_size {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let mut reply_surbs = Vec::with_capacity(num_surbs as usize);
for _ in 0..num_surbs as usize {
let surb_bytes = &bytes[consumed..consumed + surb_size];
let reply_surb = ReplySurb::from_bytes(surb_bytes)?;
reply_surbs.push(reply_surb);
consumed += surb_size;
}
Ok((reply_surbs, consumed))
}
#[repr(u8)]
enum RepliableMessageContentTag {
Data = 0,
AdditionalSurbs = 1,
Heartbeat = 2,
}
impl TryFrom<u8> for RepliableMessageContentTag {
type Error = InvalidReplyRequestError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
_ if value == (RepliableMessageContentTag::Data as u8) => Ok(Self::Data),
_ if value == (RepliableMessageContentTag::AdditionalSurbs as u8) => {
Ok(Self::AdditionalSurbs)
}
_ if value == (RepliableMessageContentTag::Heartbeat as u8) => Ok(Self::Heartbeat),
val => Err(InvalidReplyRequestError::InvalidRepliableContentTag { received: val }),
}
}
}
// sent by original sender that initialised the communication that knows address of the remote
#[derive(Debug)]
pub enum RepliableMessageContent {
Data {
message: Vec<u8>,
reply_surbs: Vec<ReplySurb>,
},
AdditionalSurbs {
reply_surbs: Vec<ReplySurb>,
},
Heartbeat {
additional_reply_surbs: Vec<ReplySurb>,
},
}
impl RepliableMessageContent {
pub fn into_bytes(self) -> Vec<u8> {
match self {
RepliableMessageContent::Data {
message,
reply_surbs,
} => {
let num_surbs = reply_surbs.len() as u32;
num_surbs
.to_be_bytes()
.into_iter()
.chain(reply_surbs.into_iter().flat_map(|s| s.to_bytes()))
.chain(message.into_iter())
.collect()
}
RepliableMessageContent::AdditionalSurbs { reply_surbs } => {
let num_surbs = reply_surbs.len() as u32;
num_surbs
.to_be_bytes()
.into_iter()
.chain(reply_surbs.into_iter().flat_map(|s| s.to_bytes()))
.collect()
}
RepliableMessageContent::Heartbeat {
additional_reply_surbs,
} => {
let num_surbs = additional_reply_surbs.len() as u32;
num_surbs
.to_be_bytes()
.into_iter()
.chain(
additional_reply_surbs
.into_iter()
.flat_map(|s| s.to_bytes()),
)
.collect()
}
}
}
fn try_from_bytes(
bytes: &[u8],
num_mix_hops: u8,
tag: RepliableMessageContentTag,
) -> Result<Self, InvalidReplyRequestError> {
if bytes.is_empty() {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let (reply_surbs, n) = recover_reply_surbs(bytes, num_mix_hops)?;
match tag {
RepliableMessageContentTag::Data => Ok(RepliableMessageContent::Data {
message: bytes[n..].to_vec(),
reply_surbs,
}),
RepliableMessageContentTag::AdditionalSurbs => {
Ok(RepliableMessageContent::AdditionalSurbs { reply_surbs })
}
RepliableMessageContentTag::Heartbeat => Ok(RepliableMessageContent::Heartbeat {
additional_reply_surbs: reply_surbs,
}),
}
}
fn tag(&self) -> RepliableMessageContentTag {
match self {
RepliableMessageContent::Data { .. } => RepliableMessageContentTag::Data,
RepliableMessageContent::AdditionalSurbs { .. } => {
RepliableMessageContentTag::AdditionalSurbs
}
RepliableMessageContent::Heartbeat { .. } => RepliableMessageContentTag::Heartbeat,
}
}
}
// sent by the remote party who does **NOT** know the original sender's identity
#[derive(Debug)]
pub struct ReplyMessage {
pub content: ReplyMessageContent,
}
impl Display for ReplyMessage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self.content {
ReplyMessageContent::Data { message } => write!(
f,
"{:.2} kiB reply data message",
message.len() as f64 / 1024.0
),
ReplyMessageContent::SurbRequest { recipient, amount } => write!(
f,
"request for {amount} additional reply SURBs from {recipient}",
),
}
}
}
impl ReplyMessage {
pub fn new_data_message(message: Vec<u8>) -> Self {
ReplyMessage {
content: ReplyMessageContent::Data { message },
}
}
pub fn new_surb_request_message(recipient: Recipient, amount: u32) -> Self {
ReplyMessage {
content: ReplyMessageContent::SurbRequest {
recipient: Box::new(recipient),
amount,
},
}
}
pub fn into_bytes(self) -> Vec<u8> {
let content_tag = self.content.tag();
std::iter::once(content_tag as u8)
.chain(self.content.into_bytes())
.collect()
}
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, InvalidReplyRequestError> {
if bytes.is_empty() {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let tag = ReplyMessageContentTag::try_from(bytes[0])?;
let content = ReplyMessageContent::try_from_bytes(&bytes[1..], tag)?;
Ok(ReplyMessage { content })
}
}
#[repr(u8)]
enum ReplyMessageContentTag {
Data = 0,
SurbRequest = 1,
}
impl TryFrom<u8> for ReplyMessageContentTag {
type Error = InvalidReplyRequestError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
_ if value == (ReplyMessageContentTag::Data as u8) => Ok(Self::Data),
_ if value == (ReplyMessageContentTag::SurbRequest as u8) => Ok(Self::SurbRequest),
val => Err(InvalidReplyRequestError::InvalidReplyContentTag { received: val }),
}
}
}
#[derive(Debug)]
pub enum ReplyMessageContent {
// TODO: later allow to request surbs whilst sending data
Data {
message: Vec<u8>,
},
SurbRequest {
recipient: Box<Recipient>,
amount: u32,
},
}
impl ReplyMessageContent {
pub fn into_bytes(self) -> Vec<u8> {
match self {
ReplyMessageContent::Data { message } => message,
ReplyMessageContent::SurbRequest { recipient, amount } => recipient
.to_bytes()
.into_iter()
.chain(amount.to_be_bytes().into_iter())
.collect(),
}
}
fn try_from_bytes(
bytes: &[u8],
tag: ReplyMessageContentTag,
) -> Result<Self, InvalidReplyRequestError> {
if bytes.is_empty() {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
match tag {
ReplyMessageContentTag::Data => Ok(ReplyMessageContent::Data {
message: bytes.to_vec(),
}),
ReplyMessageContentTag::SurbRequest => {
if bytes.len() != Recipient::LEN + std::mem::size_of::<u32>() {
return Err(InvalidReplyRequestError::RequestTooShortToDeserialize);
}
let mut recipient_bytes = [0u8; Recipient::LEN];
recipient_bytes.copy_from_slice(&bytes[..Recipient::LEN]);
Ok(ReplyMessageContent::SurbRequest {
recipient: Box::new(Recipient::try_from_bytes(recipient_bytes)?),
amount: u32::from_be_bytes([
bytes[Recipient::LEN],
bytes[Recipient::LEN + 1],
bytes[Recipient::LEN + 2],
bytes[Recipient::LEN + 3],
]),
})
}
}
}
fn tag(&self) -> ReplyMessageContentTag {
match self {
ReplyMessageContent::Data { .. } => ReplyMessageContentTag::Data,
ReplyMessageContent::SurbRequest { .. } => ReplyMessageContentTag::SurbRequest,
}
}
}