Max/dev portal update (#4696)
* updated tutorials with archive + stub * removed out of date faq pages * added binary build instructions section * removed clients from docs * added clients to devportal * moved nym-vs-others to docs from devportal * removed ood quickstart stuff * tweaked integration options page * summary changes for new structure * moved sdk to devportal * removed sdk from docs * changed summary file for new structure * added intro client overview page * added wallet gif * fixed now broken links * removed old comm pages * added references to newer apps (oreowallet + zcash demo) * updated darkfi irc socks5 * fixed broken link --------- Co-authored-by: mfahampshire <mfahampshire@pm.me>
This commit is contained in:
@@ -4,15 +4,14 @@
|
||||
|
||||
# Architecture
|
||||
- [Network Overview](architecture/network-overview.md)
|
||||
- [Nym vs Other Systems](architecture/nym-vs-others.md)
|
||||
- [Mixnet Traffic Flow](architecture/traffic-flow.md)
|
||||
<!-- TODO reintroduce this with themed images -->
|
||||
<!-- - [Network Rewards](architecture/network-rewards.md) -->
|
||||
- [Addressing System](architecture/addressing-system.md)
|
||||
|
||||
# Binaries
|
||||
- [Pre-built Binaries](binaries/pre-built-binaries.md)
|
||||
- [Binary Initialisation and Configuration](binaries/init-and-config.md)
|
||||
- [Building from Source](binaries/building-nym.md)
|
||||
<!-- - [Version Compatibility Table](binaries/version-compatiblity.md) -->
|
||||
|
||||
# Nodes
|
||||
- [Node Types (Previously Setup Guides)](nodes/overview.md)
|
||||
@@ -21,34 +20,6 @@
|
||||
- [Network Requester](nodes/network-requester.md)
|
||||
- [Validator](nodes/validator.md)
|
||||
|
||||
# Clients
|
||||
- [Clients Overview](clients/overview.md)
|
||||
- [Websocket Client](clients/websocket-client.md)
|
||||
- [Setup & Run](clients/websocket/setup.md)
|
||||
- [Configuration](clients/websocket/config.md)
|
||||
- [Using Your Client](clients/websocket/usage.md)
|
||||
- [Examples](clients/websocket/examples.md)
|
||||
- [Socks5 Client](clients/socks5-client.md)
|
||||
- [Webassembly Client](clients/webassembly-client.md)
|
||||
- [Addressing System](clients/addressing-system.md)
|
||||
|
||||
# SDK
|
||||
- [Typescript SDK](sdk/typescript.md)
|
||||
- [Rust SDK](sdk/rust/rust.md)
|
||||
- [Message Types](sdk/rust/message-types.md)
|
||||
- [Message Helpers](sdk/rust/message-helpers.md)
|
||||
- [Troubleshooting](sdk/rust/troubleshooting.md)
|
||||
- [Examples](sdk/rust/examples.md)
|
||||
- [Simple Send](sdk/rust/examples/simple.md)
|
||||
- [Create and Store Keys](sdk/rust/examples/keys.md)
|
||||
- [Manual Storage](sdk/rust/examples/storage.md)
|
||||
- [Anonymous Replies](sdk/rust/examples/surbs.md)
|
||||
- [Use Custom Network Topology](sdk/rust/examples/custom-network.md)
|
||||
- [Socks Proxy](sdk/rust/examples/socks.md)
|
||||
- [Split Send and Receive](sdk/rust/examples/split-send.md)
|
||||
- [Testnet Bandwidth Cred](sdk/rust/examples/credential.md)
|
||||
- [Example Cargo file](sdk/rust/examples/cargo.md)
|
||||
|
||||
# Wallet
|
||||
- [Desktop Wallet](wallet/desktop-wallet.md)
|
||||
- [CLI Wallet](wallet/cli-wallet.md)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Nym vs Other Systems
|
||||
|
||||
### Why use Nym: Understanding the Significance of Nym
|
||||
|
||||
Nym is the first system we're aware of which provides integrated protection on both the network and transaction level at once. This seamless approach gives the best possible privacy protections, ensuring that nothing falls through the cracks between systems.
|
||||
|
||||
The diagram and brief explainer texts below give a high level overview of the difference between Nym and other comparable systems.
|
||||
|
||||
> If you want to dig more deeply into the way traffic is packetised and moved through the mixnet, check out the [Mixnet Traffic Flow](https://nymtech.net/docs/architecture/traffic-flow.html) page of the docs.
|
||||
|
||||
<img src="../images/nym-vs-animation.gif"/>
|
||||
|
||||
### Nym vs VPNs
|
||||
|
||||
The most popular network-level privacy solution currently is the VPN (virtual private network), which provides network-level protection via an encrypted tunnel between a user’s computer and one run by a VPN provider. VPNs are often misconfigured, however, and even when configured correctly, don’t offer real privacy or adequate resistance to censorship.
|
||||
|
||||
VPN providers can also fully observe all network traffic between users and the public internet, knowing exactly what services its users are accessing at a given time. The user must trust that the VPN provider is not using their information in a malicious manner or keeping logs.
|
||||
|
||||
The Nym mixnet is an anonymous overlay network that provides strong network-level anonymity, even in the face of powerful systems capable of passively monitoring the entire network. The mixnet is decentralized, with no trusted third parties, and so does not require a trusted provider like a VPN. More importantly, Nym provides superior privacy to VPNs and can support high-quality of service and low latency through incentives.
|
||||
|
||||
### Nym vs Tor
|
||||
|
||||
Tor is the best-known anonymous overlay network today. Unlike VPNs, Tor provides a ‘circuit’ of three hops that provides better privacy than single-node VPNs, so any single node in Tor can’t deanonymize traffic. Tor’s onion-routing encrypts traffic between each hop so that only the final hop, the Tor ‘exit node’, can decrypt the package.
|
||||
|
||||
However, Tor’s anonymity properties can be defeated by an entity that is capable of monitoring the entire network’s ‘entry’ and ‘exit’ nodes, because while onion-routing encrypts traffic, Tor does not add timing obfuscation or use decoy traffic to obfuscate the traffic patterns which can be used to deanonymize users. Although these kinds of attacks were thought to be unrealistic when Tor was invented, in the era of powerful government agencies and private companies, these kinds of attacks are a real threat. Tor’s design is also based on a centralized directory authority for routing.
|
||||
|
||||
While Tor may be the best existing solution for general-purpose web-browsing that accesses the entire internet, it is inarguable that mixnets are better than Tor for message-passing systems such as cryptocurrency transactions and secure messaging, and we believe well designed incentives can also enable the use of Nym as a general purpose decentralized VPN. The Nym mixnet provides superior privacy by making packets indistinguishable from each other, adding cover traffic, and providing timing obfuscation. Unlike both previous mixnet designs and Tor, the Nym mixnet decentralizes its shared operations using blockchain technology and uses incentives to both scale and provide censorship-resistance.
|
||||
|
||||
### Nym vs I2P
|
||||
|
||||
I2P (‘Invisible Internet Project’) replaces Tor’s directory authority with a distributed hash table for routing. How to design a secure and private distributed hash table is still an open research question, and I2P is open to a number of attacks that isolate, misdirect, or deanonymize users. Like Tor, I2P is based on ‘security by obscurity’, where it is assumed that no adversary can watch the entire network. While security by obscurity may have been cutting-edge at the turn of the millennium, such an approach is rapidly showing its age.
|
||||
|
||||
Nym’s cutting-edge mixnet design guarantees network anonymity and resistance to surveillance even in the face of powerful deanonymizing attacks. Unlike I2P, Nym adds decoy traffic and timing obfuscation. Rather than a centralized directory authority or distributed hash table, Nym uses blockchain technology and economic incentives to decentralize its network.The Nym mixnet can anonymize metadata even against government agencies or private companies who can monitor network links and observe the incoming and outgoing traffic of all clients and servers.
|
||||
|
||||
### Nym vs Facebook Connect
|
||||
|
||||
The Nym credential system decentralizes the functions of systems like Facebook Connect while adding privacy. Personal data has become a toxic asset, even to companies who base their entire business around it, as evidenced by the hack of Facebook’s OAuth identity system in 2018 and the subsequent release of the data of 50 million users.
|
||||
|
||||
Unlike Facebook Connect and similar OAuth-based services like Sign in with Google, traditional usernames and passwords, or even public/private key pairs, Nym credentials allow users to authenticate and authorize data sharing without unwillingly revealing any information to a third party. There is no central third party in charge of the credentials, and users remain totally in control of their own data, disclosing it only to those who they want to. A user can store their data wherever they want (including on their own devices), and unlike alternatives like W3C’s DIDs, a user does not store anything on the blockchain, offering better privacy.
|
||||
@@ -56,8 +56,8 @@ Quite a bit of stuff gets built. The key working parts are:
|
||||
|
||||
* [mix node](../nodes/mixnode.md): `nym-mixnode`
|
||||
* [gateway node](../nodes/gateway.md): `nym-gateway`
|
||||
* [websocket client](../clients/websocket-client.md): `nym-client`
|
||||
* [socks5 client](../clients/socks5-client.md): `nym-socks5-client`
|
||||
* [websocket client](https://nymtech.net/developers/clients/websocket-client.md): `nym-client`
|
||||
* [socks5 client](https://nymtech.net/developers/clients/socks5-client.md): `nym-socks5-client`
|
||||
* [network requester](../nodes/network-requester.md): `nym-network-requester`
|
||||
* [nym-cli tool](../tools/nym-cli.md): `nym-cli`
|
||||
* [nym-api](https://nymtech.net/operators/nodes/nym-api.html): `nym-api`
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
# Clients Overview
|
||||
|
||||
A large proportion of the Nym mixnet's functionality is implemented client-side.
|
||||
|
||||
Clients perform the following actions on behalf of users:
|
||||
|
||||
* determine network topology - what mixnodes exist, what their keys are, etc.
|
||||
* register with a gateway
|
||||
* authenticate with a gateway
|
||||
* receive and decrypt messages from the gateway
|
||||
* create layer-encrypted Sphinx packets
|
||||
* send Sphinx packets with real messages
|
||||
* send Sphinx packet _cover traffic_ when no real messages are being sent
|
||||
* retransmit un-acknowledged packet sends - if a client sends 100 packets to a gateway, but only receives an acknowledgement ('ack') for 95 of them, it will resend those 5 packets to the gateway again, to make sure that all packets are received.
|
||||
|
||||
## Types of Nym clients
|
||||
At present, there are three Nym clients:
|
||||
|
||||
- the websocket (native) client
|
||||
- the SOCKS5 client
|
||||
- the wasm (webassembly) client
|
||||
|
||||
You need to choose which one you want incorporate into your app. Which one you use will depend largely on your preferred programming style and the purpose of your app.
|
||||
|
||||
### The websocket client
|
||||
Your first option is the native websocket client (`nym-client`). This is a compiled program that can run on Linux, Mac OS X, and Windows machines. It can be run as a persistent process on a desktop or server machine. You can connect to it with **any language that supports websockets**.
|
||||
|
||||
_Rust developers can import websocket client functionality into their code via the [Rust SDK](../sdk/rust/rust.md)_.
|
||||
|
||||
### The webassembly client
|
||||
If you're working in JavaScript or Typescript in the browser, or building an [edge computing](https://en.wikipedia.org/wiki/Edge_computing) app, you'll likely want to choose the webassembly client.
|
||||
|
||||
It's packaged and [available on the npm registry](https://www.npmjs.com/package/@nymproject/nym-client-wasm), so you can `npm install` it into your JavaScript or TypeScript application.
|
||||
|
||||
_The webassembly client is most easily used via the [Typescript SDK](../sdk/typescript.md)_.
|
||||
|
||||
### The SOCKS5 client
|
||||
The `nym-socks5-client` is useful for allowing existing applications to use the Nym mixnet without any code changes. All that's necessary is that they can use one of the SOCKS5, SOCKS4a, or SOCKS4 proxy protocols (which many applications can - crypto wallets, browsers, chat applications etc).
|
||||
|
||||
When used as a standalone client, it's less flexible as a way of writing custom applications than the other clients, but able to be used to proxy application traffic through the mixnet without having to make any code changes.
|
||||
|
||||
_Rust developers can import socks client functionality into their code via the [Rust SDK](../sdk/rust/rust.md)_.
|
||||
|
||||
## Commonalities between clients
|
||||
All Nym client packages present basically the same capabilities to the privacy application developer. They need to run as a persistent process in order to stay connected and ready to receive any incoming messages from their gateway nodes. They register and authenticate to gateways, and encrypt Sphinx packets.
|
||||
@@ -1,212 +0,0 @@
|
||||
# Socks5 Client
|
||||
|
||||
> The Nym socks5 client was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code on this page, go there first.
|
||||
|
||||
## Current version
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-socks5-client --version | grep "Build Version" | cut -b 21-26 -->
|
||||
```
|
||||
|
||||
## What is this client for?
|
||||
Many existing applications are able to use either the SOCKS4, SOCKS4A, or SOCKS5 proxy protocols. If you want to send such an application's traffic through the mixnet, you can use the `nym-socks5-client` to bounce network traffic through the Nym network, like this:
|
||||
|
||||
```
|
||||
External Systems:
|
||||
+--------------------+
|
||||
|------>| Monero blockchain |
|
||||
| +--------------------+
|
||||
| +--------------------+
|
||||
|------>| Email server |
|
||||
| +--------------------+
|
||||
| +--------------------+
|
||||
|------>| RPC endpoint |
|
||||
| +--------------------+
|
||||
| +--------------------+
|
||||
|------>| Website |
|
||||
| +--------------------+
|
||||
| +--------------------+
|
||||
+----------------------------------+ |------>| etc... |
|
||||
| Mixnet: | | +--------------------+
|
||||
| * Gateway your client is | |
|
||||
| connected to | +--------------------+ |
|
||||
| * Mix nodes 1 -> 3 |<-------->| Network requester |<------+
|
||||
| * Gateway that network | +--------------------+
|
||||
| requester is connected to |
|
||||
+----------------------------------+
|
||||
^
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
v
|
||||
+-------------------+
|
||||
| +---------------+ |
|
||||
| | Nym client | |
|
||||
| +---------------+ |
|
||||
| ^ |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| v |
|
||||
| +---------------+ |
|
||||
| | Your app code | |
|
||||
| +---------------+ |
|
||||
+-------------------+
|
||||
Your Local Machine
|
||||
```
|
||||
|
||||
There are 2 pieces of software that work together to send SOCKS traffic through the mixnet: the `nym-socks5-client`, and the `nym-network-requester`.
|
||||
|
||||
The `nym-socks5-client` allows you to do the following from your local machine:
|
||||
* Take a TCP data stream from a application that can send traffic via SOCKS5.
|
||||
* Chop up the TCP stream into multiple Sphinx packets, assigning sequence numbers to them, while leaving the TCP connection open for more data
|
||||
* Send the Sphinx packets through the mixnet to a [network requester](../nodes/network-requester.md). Packets are shuffled and mixed as they transit the mixnet.
|
||||
|
||||
The `nym-network-requester` then reassembles the original TCP stream using the packets' sequence numbers, and make the intended request. It will then chop up the response into Sphinx packets and send them back through the mixnet to your `nym-socks5-client`. The application will then receive its data, without even noticing that it wasn't talking to a "normal" SOCKS5 proxy!
|
||||
|
||||
## Client setup
|
||||
### Viewing command help
|
||||
|
||||
You can check that your binaries are properly compiled with:
|
||||
|
||||
```
|
||||
./nym-socks5-client --help
|
||||
```
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-socks5-client --help -->
|
||||
```
|
||||
~~~
|
||||
|
||||
You can check the necessary parameters for the available commands by running:
|
||||
|
||||
```
|
||||
./nym-client <COMMAND> --help
|
||||
```
|
||||
|
||||
### Initialising a new client instance
|
||||
Before you can use the client, you need to initalise a new instance of it, which can be done with the following command:
|
||||
|
||||
```
|
||||
./nym-socks5-client init --id docs-example --use-reply-surbs true --provider Entztfv6Uaz2hpYHQJ6JKoaCTpDL5dja18SuQWVJAmmx.Cvhn9rBJw5Ay9wgHcbgCnVg89MPSV5s2muPV2YF1BXYu@Fo4f4SQLdoyoGkFae5TpVhRVoXCF8UiypLVGtGjujVPf
|
||||
```
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-socks5-client init --id docs-example --provider Entztfv6Uaz2hpYHQJ6JKoaCTpDL5dja18SuQWVJAmmx.Cvhn9rBJw5Ay9wgHcbgCnVg89MPSV5s2muPV2YF1BXYu@Fo4f4SQLdoyoGkFae5TpVhRVoXCF8UiypLVGtGjujVPf -->
|
||||
```
|
||||
~~~
|
||||
|
||||
The `--id` in the example above is a local identifier so that you can name your clients and keep track of them on your local system; it is **never** transmitted over the network.
|
||||
|
||||
The `--use-reply-surbs` field denotes whether you wish to send [SURBs](../architecture/traffic-flow.md#private-replies-using-surbs) along with your request. It defaults to `false`, we are explicitly setting it as `true`. It defaults to `false` for compatibility with older versions of the [Network Requester](../nodes/network-requester.md).
|
||||
|
||||
The `--provider` field needs to be filled with the Nym address of a Network Requester that can make network requests on your behalf. If you don't want to [run your own](../nodes/network-requester.md) you can select one from the [mixnet explorer](https://explorer.nymtech.net/network-components/service-providers) by copying its `Client ID` and using this as the value of the `--provider` flag. Alternatively, you could use [this list](https://harbourmaster.nymtech.net/).
|
||||
|
||||
Since the nodes on this list are the infrastructure for [Nymconnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html) they will support all apps on the [default whitelist](../nodes/network-requester.md#network-requester-whitelist): Keybase, Telegram, Electrum, Blockstream Green, and Helios.
|
||||
|
||||
#### Choosing a Gateway
|
||||
By default - as in the example above - your client will choose a random gateway to connect to.
|
||||
|
||||
However, there are several options for choosing a gateway, if you do not want one that is randomly assigned to your client:
|
||||
* If you wish to connect to a specific gateway, you can specify this with the `--gateway` flag when running `init`.
|
||||
* You can also choose a gateway based on its location relative to your client. This can be done by appending the `--latency-based-selection` flag to your `init` command. This command means that to select a gateway, your client will:
|
||||
* fetch a list of all availiable gateways
|
||||
* send few ping messages to all of them, and measure response times.
|
||||
* create a weighted distribution to randomly choose one, favouring ones with lower latency.
|
||||
|
||||
> Note this doesn't mean that your client will pick the closest gateway to you, but it will be far more likely to connect to gateway with a 20ms ping rather than 200ms
|
||||
|
||||
### Configuring your client
|
||||
When you initalise a client instance, a configuration directory will be generated and stored in `$HOME_DIR/.nym/socks5-clients/<client-name>/`.
|
||||
|
||||
```
|
||||
tree $HOME/<user>/.nym/socks5-clients/docs-example
|
||||
├── config
|
||||
│ └── config.toml
|
||||
└── data
|
||||
├── ack_key.pem
|
||||
├── credentials_database.db
|
||||
├── gateway_shared.pem
|
||||
├── persistent_reply_store.sqlite
|
||||
├── private_encryption.pem
|
||||
├── private_identity.pem
|
||||
├── public_encryption.pem
|
||||
└── public_identity.pem
|
||||
|
||||
```
|
||||
|
||||
The `config.toml` file contains client configuration options, while the two `pem` files contain client key information.
|
||||
|
||||
The generated files contain the client name, public/private keypairs, and gateway address. The name `<client_id>` in the example above is just a local identifier so that you can name your clients.
|
||||
|
||||
#### Configuring your client for Docker
|
||||
By default, the native client listens to host `127.0.0.1`. However this can be an issue if you wish to run a client in a Dockerized environment, where it can be convenenient to listen on a different host such as `0.0.0.0`.
|
||||
|
||||
You can set this via the `--host` flag during either the `init` or `run` commands.
|
||||
|
||||
Alternatively, a custom host can be set in the `config.toml` file under the `socket` section. If you do this, remember to restart your client process.
|
||||
|
||||
### Running the socks5 client
|
||||
|
||||
You can run the initialised client by doing this:
|
||||
|
||||
```
|
||||
./nym-socks5-client run --id docs-example
|
||||
```
|
||||
|
||||
## Automating your socks5 client with systemd
|
||||
|
||||
Create a service file for the socks5 client at `/etc/systemd/system/nym-socks5-client.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Nym Socks5 Client
|
||||
StartLimitInterval=350
|
||||
StartLimitBurst=10
|
||||
|
||||
[Service]
|
||||
User=nym # replace this with whatever user you wish
|
||||
LimitNOFILE=65536
|
||||
ExecStart=/home/nym/nym-socks5-client run --id <your_id>
|
||||
KillSignal=SIGINT
|
||||
Restart=on-failure
|
||||
RestartSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
Now enable and start your socks5 client:
|
||||
|
||||
```
|
||||
systemctl enable nym-socks5-client.service
|
||||
systemctl start nym-socks5-client.service
|
||||
# you can always check your socks5 client has succesfully started with:
|
||||
systemctl status nym-socks5-client.service
|
||||
```
|
||||
|
||||
## Using your Socks5 Client
|
||||
|
||||
After completing the steps above, your local Socks5 Client will be listening on `localhost:1080` ready to proxy traffic to the Network Requester set as the `--provider` when initialising.
|
||||
|
||||
When trying to connect your app, generally the proxy settings are found in `settings->advanced` or `settings->connection`.
|
||||
|
||||
Here is an example of setting the proxy connecting in Blockstream Green:
|
||||
|
||||

|
||||
|
||||
Most wallets and other applications will work basically the same way: find the network proxy settings, enter the proxy url (host: **localhost**, port: **1080**).
|
||||
|
||||
In some other applications, this might be written as **localhost:1080** if there's only one proxy entry field.
|
||||
|
||||
## Useful Commands
|
||||
|
||||
**no-banner**
|
||||
|
||||
Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment.
|
||||
|
||||
**build-info**
|
||||
|
||||
A `build-info` command prints the build information like commit hash, rust version, binary version just like what command `--version` does. However, you can also specify an `--output=json` flag that will format the whole output as a json, making it an order of magnitude easier to parse.
|
||||
@@ -1,22 +0,0 @@
|
||||
# Webassembly Client
|
||||
|
||||
The Nym webassembly client allows any webassembly-capable runtime to build and send Sphinx packets to the Nym network, for uses in edge computing and browser-based applications.
|
||||
|
||||
This is currently packaged and distributed for ease of use via the [Nym Typescript SDK library](../sdk/typescript.md). **We imagine most developers will use this client via the SDK for ease.**
|
||||
|
||||
The webassembly client allows for the easy creation of Sphinx packets from within mobile apps and browser-based client-side apps (including Electron or similar).
|
||||
|
||||
## Building apps with Webassembly Client
|
||||
|
||||
Check out the [Typescript SDK docs](https://sdk.nymtech.net) for examples of usage.
|
||||
|
||||
There are also example applications located in the `clients/webassembly` directory in the main Nym platform codebase.
|
||||
|
||||
## Think about what you're sending!
|
||||
```admonish caution
|
||||
Think about what information your app sends. That goes for whatever you put into your Sphinx packet messages as well as what your app's environment may leak.
|
||||
```
|
||||
|
||||
Whenever you write client PEAPPs using HTML/JavaScript, we recommend that you do not load external resources from CDNs. Webapp developers do this all the time, to save load time for common resources, or just for convenience. But when you're writing privacy apps it's better not to make these kinds of requests. Pack everything locally.
|
||||
|
||||
If you use only local resources within your Electron app or your browser extensions, explicitly encoding request data in a Sphinx packet does protect you from the normal leakage that gets sent in a browser HTTP request. [There's a lot of stuff that leaks when you make an HTTP request from a browser window](https://panopticlick.eff.org/). Luckily, all that metadata and request leakage doesn't happen in Nym, because you're choosing very explicitly what to encode into Sphinx packets, instead of sending a whole browser environment by default.
|
||||
@@ -1,13 +0,0 @@
|
||||
# Websocket Client
|
||||
|
||||
> The Nym Websocket Client was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code on this page, go there first.
|
||||
|
||||
## Current version
|
||||
```
|
||||
<!-- cmdrun ../../../../target/release/nym-client --version | grep "Build Version" | cut -b 21-26 -->
|
||||
```
|
||||
|
||||
You can run this client as a standalone process and pipe traffic into it to be sent through the mixnet. This is useful if you're building an application in a language other than Typescript or Rust and cannot utilise one of the SDKs.
|
||||
|
||||
You can find the code for this client [here](https://github.com/nymtech/nym/tree/develop/clients/native).
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
# Configuration
|
||||
|
||||
## Default listening port
|
||||
The Nym native client exposes a websocket interface that your code connects to. To program your app, choose a websocket library for whatever language you're using. The **default** websocket port is `1977`, you can override that in the client config if you want.
|
||||
|
||||
You can either set this via the `--port` flag at `init` or `run`, or you can manually edit `~/.nym/clients/<CLIENT-ID>/config/config.toml`.
|
||||
|
||||
> Remember to restart your client if you change your listening port via editing your config file.
|
||||
|
||||
## Choosing a Gateway
|
||||
By default your client will choose a random gateway to connect to.
|
||||
|
||||
However, there are several options for choosing a gateway, if you do not want one that is randomly assigned to your client:
|
||||
* If you wish to connect to a specific gateway, you can specify this with the `--gateway` flag when running `init`.
|
||||
* You can also choose a gateway based on its location relative to your client. This can be done by appending the `--latency-based-routing` flag to your `init` command. This command means that to select a gateway, your client will:
|
||||
* fetch a list of all available gateways
|
||||
* send few ping messages to all of them, and measure response times.
|
||||
* create a weighted distribution to randomly choose one, favouring ones with lower latency.
|
||||
|
||||
> Note this doesn't mean that your client will pick the closest gateway to you, but it will be far more likely to connect to gateway with a 20ms ping rather than 200ms
|
||||
|
||||
## Configuring your client
|
||||
When you initalise a client instance, a configuration directory will be generated and stored in `$HOME_DIR/.nym/clients/<client-name>/`.
|
||||
|
||||
```
|
||||
tree $HOME/<user>/.nym/clients/example-client
|
||||
├── config
|
||||
│ └── config.toml
|
||||
└── data
|
||||
├── ack_key.pem
|
||||
├── gateway_shared.pem
|
||||
├── private_encryption.pem
|
||||
├── private_identity.pem
|
||||
├── public_encryption.pem
|
||||
└── public_identity.pem
|
||||
```
|
||||
|
||||
The `config.toml` file contains client configuration options, while the two `pem` files contain client key information.
|
||||
|
||||
The generated files contain the client name, public/private keypairs, and gateway address. The name `<client_id>` in the example above is just a local identifier so that you can name your clients.
|
||||
|
||||
### Configuring your client for Docker
|
||||
By default, the native client listens to host `127.0.0.1`. However this can be an issue if you wish to run a client in a Dockerized environment, where it can be convenenient to listen on a different host such as `0.0.0.0`.
|
||||
|
||||
You can set this via the `--host` flag during either the `init` or `run` commands.
|
||||
|
||||
Alternatively, a custom host can be set in the `config.toml` file under the `socket` section. If you do this, remember to restart your client process.
|
||||
@@ -1,15 +0,0 @@
|
||||
# Examples
|
||||
The Nym monorepo includes websocket client example code for Rust, Go, Javacript, and Python, all of which can be found [here](https://github.com/nymtech/nym/tree/master/clients/native/examples).
|
||||
|
||||
> Rust users can run the examples with `cargo run --example <rust_file>.rs`, as the examples are not organised in the same way as the other examples, due to already being inside a Cargo project.
|
||||
|
||||
All of these code examples will do the following:
|
||||
* connect to a running websocket client on port `1977`
|
||||
* format a message to send in either JSON or Binary format. Nym messages have defined JSON formats.
|
||||
* send the message into the websocket. The native client packages the message into a Sphinx packet and sends it to the mixnet
|
||||
* wait for confirmation that the message hit the native client
|
||||
* wait to receive messages from other Nym apps
|
||||
|
||||
By varying the message content, you can easily build sophisticated service provider apps. For example, instead of printing the response received from the mixnet, your service provider might take some action on behalf of the user - perhaps initiating a network request, a blockchain transaction, or writing to a local data store.
|
||||
|
||||
> You can find an example of building both frontend and service provider code with the websocket client in the [Simple Service Provider Tutorial](https://nymtech.net/developers/tutorials/simple-service-provider/simple-service-provider.html) in the Developer Portal.
|
||||
@@ -1,59 +0,0 @@
|
||||
# Setup & Run
|
||||
|
||||
## Viewing command help
|
||||
|
||||
You can check that your binaries are properly compiled with:
|
||||
|
||||
```
|
||||
./nym-client --help
|
||||
```
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../../target/release/nym-client --help -->
|
||||
```
|
||||
~~~
|
||||
|
||||
The two most important commands you will issue to the client are:
|
||||
|
||||
* `init` - initalise a new client instance.
|
||||
* `run` - run a mixnet client process.
|
||||
|
||||
You can check the necessary parameters for the available commands by running:
|
||||
|
||||
```
|
||||
./nym-client <command> --help
|
||||
```
|
||||
|
||||
## Initialising your client
|
||||
|
||||
Before you can use the client, you need to initalise a new instance of it. Each instance of the client has its own public/private keypair, and connects to its own gateway node. Taken together, these 3 things (public/private keypair + gateway node identity key) make up an app's identity.
|
||||
|
||||
Initialising a new client instance can be done with the following command:
|
||||
|
||||
```
|
||||
./nym-client init --id example-client
|
||||
```
|
||||
|
||||
~~~admonish example collapsible=true title="Console output"
|
||||
```
|
||||
<!-- cmdrun ../../../../../target/release/nym-client init --id example-client -->
|
||||
```
|
||||
~~~
|
||||
|
||||
The `--id` in the example above is a local identifier so that you can name your clients; it is **never** transmitted over the network.
|
||||
|
||||
There is an optional `--gateway` flag that you can use if you want to use a specific gateway. The supplied argument is the `Identity Key` of the gateway you wish to use, which can be found on the [mainnet Network Explorer](https://explorer.nymtech.net/network-components/gateways) or [Sandbox Testnet Explorer](https://sandbox-explorer.nymtech.net/network-components/gateways) depending on which network you are on.
|
||||
|
||||
Not passing this argument will randomly select a gateway for your client.
|
||||
|
||||
## Running your client
|
||||
You can run the initalised client by doing this:
|
||||
|
||||
```
|
||||
./nym-client run --id example-client
|
||||
```
|
||||
|
||||
When you run the client, it immediately starts generating (fake) cover traffic and sending it to the mixnet.
|
||||
|
||||
When the client is first started, it will reach out to the Nym network's validators, and get a list of available Nym nodes (gateways, mixnodes, and validators). We call this list of nodes the network _topology_. The client does this so that it knows how to connect, register itself with the network, and know which mixnodes it can route Sphinx packets through.
|
||||
@@ -1,117 +0,0 @@
|
||||
# Using Your Client
|
||||
The Nym native client exposes a websocket interface that your code connects to. The **default** websocket port is `1977`, you can override that in the client config if you want.
|
||||
|
||||
Once you have a websocket connection, interacting with the client involves piping messages down the socket and listening for incoming messages.
|
||||
|
||||
# Message Requests
|
||||
There are a number of message types that you can send up the websocket as defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs):
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../clients/native/websocket-requests/src/requests.rs:55:97}}
|
||||
```
|
||||
|
||||
## Getting your own address
|
||||
When you start your app, it is best practice to ask the native client to tell you what your own address is (from the generated configuration files - see [here](../addressing-system.md) for more on Nym's addressing scheme). If you are running a service, you need to do this in order to know what address to give others. In a client-side piece of code you can also use this as a test to make sure your websocket connection is running smoothly. To do this, send:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "selfAddress"
|
||||
}
|
||||
```
|
||||
|
||||
You'll receive a response of the format:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "selfAddress",
|
||||
"address": "your address" // e.g. "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
|
||||
}
|
||||
```
|
||||
|
||||
See [here](https://github.com/nymtech/nym/blob/93cc281abc2cc951023b51746fa6f2ead1f56c46/clients/native/examples/python-examples/websocket/textsend.py#L16C9-L16C9) for an example of this being used.
|
||||
|
||||
> Note that all the pieces of native client example code begin with printing the selfAddress. Examples exist for Rust, Go, Javascript, and Python.
|
||||
|
||||
## Sending text
|
||||
If you want to send text information through the mixnet, format a message like this one and poke it into the websocket:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "send",
|
||||
"message": "the message",
|
||||
"recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
|
||||
}
|
||||
```
|
||||
|
||||
In some applications, e.g. where people are chatting with friends who they know, you might want to include unencrypted reply information in the message field. This provides an easy way for the receiving chat to then turn around and send a reply message:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "send",
|
||||
"message": {
|
||||
"sender": "198427b63ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm",
|
||||
"chatMessage": "hi julia!"
|
||||
},
|
||||
"recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm"
|
||||
}
|
||||
```
|
||||
|
||||
**If that fits your security model, good. However, will probably be the case that you want to send anonymous replies using Single Use Reply Blocks (SURBs)**.
|
||||
|
||||
You can read more about SURBs [here](../../architecture/traffic-flow.md#private-replies-using-surbs) but in short they are ways for the receiver of this message to anonymously reply to you - the sender - **without them having to know your client address**.
|
||||
|
||||
Your client will send along a number of `replySurbs` to the recipient of the message. These are pre-addressed Sphinx packets that the recipient can write to the payload of (i.e. write response data to), but not view the final destination of. If the recipient is unable to fit the response data into the bucket of SURBs sent to it, it will use a SURB to request more SURBs be sent to it from your client.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "sendAnonymous",
|
||||
"message": "something you want to keep secret",
|
||||
"recipient": "71od3ZAupdCdxeFNg8sdonqfZTnZZy1E86WYKEjxD4kj@FWYoUrnKuXryysptnCZgUYRTauHq4FnEFu2QGn5LZWbm",
|
||||
"replySurbs": 20 // however many reply SURBs to send along with your message
|
||||
}
|
||||
```
|
||||
|
||||
See ['Replying to SURB Messages'](#replying-to-surb-messages) below for an example of how to deal with incoming messages that have SURBs attached.
|
||||
|
||||
Deciding on the amount of SURBs to generate and send along with outgoing messages depends on the expected size of the reply. You might want to send a lot of SURBs in order to make sure you get your response as quickly as possible (but accept the minor additional latency when sending, as your client has to generate and encrypt the packets), or you might just send a few (e.g. 20) and then if your response requires more SURBs, send them along, accepting the additional latency in getting your response.
|
||||
|
||||
## Sending binary data
|
||||
You can also send bytes instead of JSON. For that you have to send a binary websocket frame containing a binary encoded
|
||||
Nym [`ClientRequest`](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/requests.rs#L25) containing the same information.
|
||||
|
||||
> As a response the `native-client` will send a `ServerResponse` to be decoded. See [Message Responses](#message-responses) below for more.
|
||||
|
||||
You can find examples of sending and receiving binary data in the [code examples](https://github.com/nymtech/nym/tree/master/clients/native/examples), and an example project from the Nym community [BTC-BC](https://github.com/sgeisler/btcbc-rs/): Bitcoin transaction transmission via Nym, a client and service provider written in Rust.
|
||||
|
||||
## Replying to SURB messages
|
||||
Each bucket of `replySURBs`, when received as part of an incoming message, has a unique session identifier, which **only identifies the bucket of pre-addressed packets**. This is necessary to make sure that your app is replying to the correct people with the information meant for them in a situation where multiple clients are sending requests to a single service.
|
||||
|
||||
Constructing a reply with SURBs looks something like this (where `senderTag` was parsed from the incoming message)
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "reply",
|
||||
"message": "reply you also want to keep secret",
|
||||
"senderTag": "the sender tag you parsed from the incoming message"
|
||||
}
|
||||
```
|
||||
|
||||
## Error messages
|
||||
Errors from the app's client, or from the gateway, will be sent down the websocket to your code in the following format:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "error",
|
||||
"message": "string message"
|
||||
}
|
||||
```
|
||||
|
||||
## LaneQueueLength
|
||||
This is currently only used in the [Socks Client](../socks5-client.md) to keep track of the number of Sphinx packets waiting to be sent to the mixnet via being slotted amongst cover traffic. As this value becomes larger, the client signals to the application it should slow down the speed with which it writes to the proxy. This is to stop situations arising whereby an app connected to the client appears as if it has sent (e.g.) a bunch of messages and is awaiting a reply, when they in fact have not been sent through the mixnet yet.
|
||||
|
||||
# Message Responses
|
||||
Responses to your messages are defined [here](https://github.com/nymtech/nym/blob/develop/clients/native/websocket-requests/src/responses.rs):
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../clients/native/websocket-requests/src/responses.rs:48:53}}
|
||||
```
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
Gateways are key to both the usability of the mixnet, and the operation of the mixnet's tokenomics. They serve two main functions:
|
||||
* In the future (when the mixnet is no longer running in 'free to use' mode), to check for zkNym credentials (previously referred to as [Coconut Credentials](../bandwidth-credentials.md)) with which users can anonymously prove they have paid to send traffic through the mixnet. A % of the worth of these credentials will be distributed to the operator of the gateway periodically as payment for providing their service. The more credentials user clients 'spend' with them, the higher the rewards for the gateway operator and their delegators will be. The rest of this value will be sent to the Mixmining Pool, a pool of tokens from which `NYM` rewards are distributed to mix node operators.
|
||||
* Act as a mailbox for connected clients. Clients create a lasting relationship with a gateway on initialisation, binding themselves to always use a particular gateway as their ingress point for mixnet traffic (this also means that this gateway is the egress point for any traffic sent _to_ this client - see the [mixnet traffic flow page](../architecture/traffic-flow.md) and the [addressing scheme](../clients/addressing-system.md) for further details). If a client is offline and the Gateway can't deliver packets addressed to it, they will hold these packets until the client comes back online.
|
||||
* Act as a mailbox for connected clients. Clients create a lasting relationship with a gateway on initialisation, binding themselves to always use a particular gateway as their ingress point for mixnet traffic (this also means that this gateway is the egress point for any traffic sent _to_ this client - see the [mixnet traffic flow page](../architecture/traffic-flow.md) and the [addressing scheme](../architecture/addressing-system.md) for further details). If a client is offline and the Gateway can't deliver packets addressed to it, they will hold these packets until the client comes back online.
|
||||
|
||||
## Further Reading
|
||||
* [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 4.2
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
# Examples
|
||||
|
||||
All the following examples can be found in the `nym-sdk` [examples directory](https://github.com/nymtech/nym/tree/master/sdk/rust/nym-sdk/examples) in the monorepo. Just navigate to `nym/sdk/rust/nym-sdk/examples/` and run the files from there with:
|
||||
|
||||
```sh
|
||||
cargo run --example <NAME_OF_FILE>
|
||||
```
|
||||
|
||||
If you wish to run these outside of the workspace - such as if you want to use one as the basis for your own project - then make sure to import the `sdk`, `tokio`, and `nym_bin_common` crates.
|
||||
|
||||
An example `Cargo.toml` file can be found [here](examples/cargo.md).
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
# Example Cargo File
|
||||
This file imports the basic requirements for running these pieces of example code, and can be used as the basis for your own cargo project.
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "your_app"
|
||||
version = "x.y.z"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
# Async runtime
|
||||
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
|
||||
# Used for (de)serialising incoming and outgoing messages
|
||||
serde = "1.0.152"
|
||||
serde_json = "1.0.91"
|
||||
# Nym clients, addressing, etc
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-sphinx-addressing = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-bin-common = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
nym-sphinx-anonymous-replies = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
# Additional dependencies if you're interacting with Nyx or another Cosmos SDK blockchain
|
||||
cosmrs = "=0.14.0"
|
||||
nym-validator-client = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
|
||||
# If you're building an app with a client and server / serivce this might be a useful structure for your repo
|
||||
[[bin]]
|
||||
name = "client"
|
||||
path = "bin/client.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "service"
|
||||
path = "bin/service.rs"
|
||||
```
|
||||
@@ -1,9 +0,0 @@
|
||||
# Coconut credential generation
|
||||
The following code shows how you can use the SDK to create and use a [credential](../../../bandwidth-credentials.md) representing paid bandwidth on the Sandbox testnet.
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/bandwidth.rs}}
|
||||
```
|
||||
|
||||
You can read more about Coconut credentials (also referred to as `zk-Nym`) [here](../../../coconut.md).
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# Importing and using a custom network topology
|
||||
If you want to send traffic through a sub-set of nodes (for instance, ones you control, or a small test setup) when developing, debugging, or performing research, you will need to import these nodes as a custom network topology, instead of grabbing it from the [`Mainnet Nym-API`](https://validator.nymtech.net/api/swagger/index.html) (`examples/custom_topology_provider.rs`).
|
||||
|
||||
There are two ways to do this:
|
||||
|
||||
## Import a custom Nym API endpoint
|
||||
If you are also running a Validator and Nym API for your network, you can specify that endpoint as such and interact with it as clients usually do (under the hood):
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/custom_topology_provider.rs}}
|
||||
```
|
||||
|
||||
## Import a specific topology manually
|
||||
If you aren't running a Validator and Nym API, and just want to import a specific sub-set of mix nodes, you can simply overwrite the grabbed topology manually:
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/manually_overwrite_topology.rs}}
|
||||
```
|
||||
@@ -1,28 +0,0 @@
|
||||
# Key Creation and Use
|
||||
The previous example involves ephemeral keys - if we want to create and then maintain a client identity over time, our code becomes a little more complex as we need to create, store, and conditionally load these keys (`examples/builder_with_storage`):
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/builder_with_storage.rs}}
|
||||
```
|
||||
|
||||
As seen in the example above, the `mixnet::MixnetClientBuilder::new()` function handles checking for keys in a storage location, loading them if present, or creating them and storing them if not, making client key management very simple.
|
||||
|
||||
Assuming our client config is stored in `/tmp/mixnet-client`, the following files are generated:
|
||||
```
|
||||
$ tree /tmp/mixnet-client
|
||||
|
||||
mixnet-client
|
||||
├── ack_key.pem
|
||||
├── db.sqlite
|
||||
├── db.sqlite-shm
|
||||
├── db.sqlite-wal
|
||||
├── gateway_details.json
|
||||
├── gateway_shared.pem
|
||||
├── persistent_reply_store.sqlite
|
||||
├── private_encryption.pem
|
||||
├── private_identity.pem
|
||||
├── public_encryption.pem
|
||||
└── public_identity.pem
|
||||
|
||||
1 directory, 11 files
|
||||
```
|
||||
@@ -1,8 +0,0 @@
|
||||
# Simple Send
|
||||
Lets look at a very simple example of how you can import and use the websocket client in a piece of Rust code (`examples/simple.rs`).
|
||||
|
||||
Simply importing the `nym_sdk` crate into your project allows you to create a client and send traffic through the mixnet.
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/simple.rs}}
|
||||
```
|
||||
@@ -1,10 +0,0 @@
|
||||
# Socks Proxy
|
||||
There is also the option to embed the [`socks5-client`](../../../clients/socks5-client.md) into your app code (`examples/socks5.rs`):
|
||||
|
||||
```admonish info
|
||||
If you are looking at implementing Nym as a transport layer for a crypto wallet or desktop app, this is probably the best place to start if they can speak SOCKS5, 4a, or 4.
|
||||
```
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/socks5.rs}}
|
||||
```
|
||||
@@ -1,6 +0,0 @@
|
||||
# Send and Receive in Different Tasks
|
||||
If you need to split the different actions of your client across different tasks, you can do so like this:
|
||||
|
||||
```rust, noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/parallel_sending_and_receiving.rs}}
|
||||
```
|
||||
@@ -1,6 +0,0 @@
|
||||
# Manually Handled Storage
|
||||
If you're integrating mixnet functionality into an existing app and want to integrate saving client configs and keys into your existing storage logic, you can manually perform the actions taken automatically above (`examples/manually_handle_keys_and_config.rs`)
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/manually_handle_storage.rs}}
|
||||
```
|
||||
@@ -1,16 +0,0 @@
|
||||
# Anonymous Replies with SURBs (Single Use Reply Blocks)
|
||||
Both functions used to send messages through the mixnet (`send_message` and `send_plain_message`) send a pre-determined number of SURBs along with their messages by default.
|
||||
|
||||
The number of SURBs is set [here](https://github.com/nymtech/nym/blob/master/sdk/rust/nym-sdk/src/mixnet/client.rs#L33).
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/src/mixnet/client.rs:33}}
|
||||
```
|
||||
|
||||
You can read more about how SURBs function under the hood [here](../../../architecture/traffic-flow.md#private-replies-using-surbs).
|
||||
|
||||
In order to reply to an incoming message using SURBs, you can construct a `recipient` from the `sender_tag` sent along with the message you wish to reply to:
|
||||
|
||||
```rust,noplayground
|
||||
{{#include ../../../../../../sdk/rust/nym-sdk/examples/surb_reply.rs}}
|
||||
```
|
||||
@@ -1,70 +0,0 @@
|
||||
# Message Helpers
|
||||
|
||||
## Handling incoming messages
|
||||
As seen in the [Chain querier tutorial](https://github.com/nymtech/developer-tutorials/blob/0130ee5a61cd6801bdcfc84608b2a520b5392714/rust/chain-query-service/) when listening out for a response to a sent message (e.g. if you have sent a request to a service, and are awaiting the response) you will want to await [non-empty messages (if you don't know why, read the info on this here)](troubleshooting.md#client-receives-empty-messages-when-listening-for-response). This can be done with something like the helper functions [here](https://github.com/nymtech/developer-tutorials/blob/0130ee5a61cd6801bdcfc84608b2a520b5392714/rust/chain-query-service/src/lib.rs#L71):
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::ReconstructedMessage;
|
||||
|
||||
pub async fn wait_for_non_empty_message(
|
||||
client: &mut MixnetClient,
|
||||
) -> anyhow::Result<ReconstructedMessage> {
|
||||
while let Some(mut new_message) = client.wait_for_messages().await {
|
||||
if !new_message.is_empty() {
|
||||
return Ok(new_message.pop().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
bail!("did not receive any non-empty message")
|
||||
}
|
||||
|
||||
pub fn handle_response(message: ReconstructedMessage) -> anyhow::Result<ResponseTypes> {
|
||||
ResponseTypes::try_deserialize(message.message)
|
||||
}
|
||||
|
||||
// Note here that the only difference between handling a request and a response
|
||||
// is that a request will have a sender_tag to parse.
|
||||
//
|
||||
// This is used for anonymous replies with SURBs.
|
||||
pub fn handle_request(
|
||||
message: ReconstructedMessage,
|
||||
) -> anyhow::Result<(RequestTypes, Option<AnonymousSenderTag>)> {
|
||||
let request = RequestTypes::try_deserialize(message.message)?;
|
||||
Ok((request, message.sender_tag))
|
||||
}
|
||||
```
|
||||
|
||||
The above helper functions are used as such by the client in tutorial example: it sends a message to the service (what the message is isn't important - just that your client has sent a message _somewhere_ and you are awaiting a response), waits for a _non_empty_ message, then handles it (then logs it - but you can do whatever you want, parse it, etc):
|
||||
|
||||
```rust
|
||||
// [snip]
|
||||
|
||||
// Send serialised request to service via mixnet what is await-ed here is
|
||||
// placing the message in the client's message queue, NOT the sending itself.
|
||||
let _ = client
|
||||
.send_message(sp_address, message.serialize(), Default::default())
|
||||
.await;
|
||||
|
||||
// Await a non-empty message
|
||||
let received = wait_for_non_empty_message(client).await?;
|
||||
|
||||
// Handle the response received (the non-empty message awaited above)
|
||||
let sp_response = handle_response(received)?;
|
||||
|
||||
// Match JSON -> ResponseType
|
||||
let res = match sp_response {
|
||||
crate::ResponseTypes::Balance(response) => {
|
||||
println!("{:#?}", response);
|
||||
response.balance
|
||||
}
|
||||
};
|
||||
|
||||
// [snip]
|
||||
```
|
||||
([repo code on Github here](https://github.com/nymtech/developer-tutorials/blob/0130ee5a61cd6801bdcfc84608b2a520b5392714/rust/chain-query-service/src/client.rs#L19))
|
||||
|
||||
## Iterating over incoming messages
|
||||
It is recommended to use `nym_client.next().await` over `nym_client.wait_for_messages().await` as the latter will return one message at a time which will probably be easier to deal with. See the [parallel send and receive example](https://github.com/nymtech/nym/blob/2993e85c7a17bd5b68171751a48b731b2394ee03/sdk/rust/nym-sdk/examples/parallel_sending_and_receiving.rs#L23-L25) for an example.
|
||||
|
||||
## Remember to disconnect your client
|
||||
You should always **manually disconnect your client** with `client.disconnect().await` as seen in the code examples. This is important as your client is writing to a local DB and dealing with SURB storage.
|
||||
@@ -1,5 +0,0 @@
|
||||
# Message Types
|
||||
[//]: # (TODO expand! )
|
||||
There are two methods for sending messages through the mixnet using your client:
|
||||
* `send_plain_message()` is the most simple: pass the recipient address and the message you wish to send as a string (this was previously `send_str()`). This is a nicer-to-use wrapper around `send_message()`.
|
||||
* `send_message()` allows you to also define the amount of SURBs to send along with your message (which is sent as bytes).
|
||||
@@ -1,48 +0,0 @@
|
||||
# Rust SDK
|
||||
The Rust SDK allows developers building applications in Rust to import and interact with Nym clients as they would any other dependency, instead of running the client as a separate process on their machine. This makes both developing and running applications much easier, reducing complexity in the development process (not having to restart another client in a separate console window/tab) and being able to have a single binary for other people to use.
|
||||
|
||||
Currently developers can use the Rust SDK to import either websocket client ([`nym-client`](../../clients/websocket-client.md)) or [`socks-client`](../../clients/socks5-client.md) functionality into their Rust code.
|
||||
|
||||
In the future the SDK will be made up of several components, each of which will allow developers to interact with different parts of Nym infrastructure.
|
||||
|
||||
| Component | Functionality | Released |
|
||||
|-----------|---------------------------------------------------------------------------------------|----------|
|
||||
| Mixnet | Create / load clients & keypairs, subscribe to Mixnet events, send & receive messages | ✔️ |
|
||||
| Coconut | Create & verify Coconut credentials | 🛠️ |
|
||||
| Validator | Sign & broadcast Nyx blockchain transactions, query the blockchain | ❌ |
|
||||
|
||||
The `mixnet` component currently exposes the logic of two clients: the [websocket client](../../clients/websocket-client.md), and the [socks](../../clients/socks5-client.md) client.
|
||||
|
||||
The `coconut` component is currently being worked on. Right now it exposes logic allowing for the creation of coconut credentials on the Sandbox testnet.
|
||||
|
||||
### Development status
|
||||
The SDK is still somewhat a work in progress: interfaces are fairly stable but still may change in subsequent releases.
|
||||
|
||||
### Installation
|
||||
The `nym-sdk` crate is **not yet available via [crates.io](https://crates.io)**. As such, in order to import the crate you must specify the Nym monorepo in your `Cargo.toml` file:
|
||||
|
||||
```toml
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym" }
|
||||
```
|
||||
|
||||
By default the above command will import the current `HEAD` of the default branch, which in our case is `develop`. Assuming instead you wish to pull in another branch (e.g. `master` or a particular release) you can specify this like so:
|
||||
|
||||
```toml
|
||||
# importing HEAD of master branch
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "master" }
|
||||
# importing HEAD of the third release of 2023, codename 'kinder'
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", branch = "release/2023.3-kinder" }
|
||||
```
|
||||
|
||||
You can also define a particular git commit to use as your import like so:
|
||||
|
||||
```toml
|
||||
nym-sdk = { git = "https://github.com/nymtech/nym", rev = "85a7ec9f02ca8262d47eebb6c3b19d832341b55d" }
|
||||
```
|
||||
|
||||
Since the `HEAD` of `master` is always the most recent release, we recommend developers use that for their imports, unless they have a reason to pull in a specific historic version of the code.
|
||||
|
||||
### Generate Crate Docs
|
||||
In order to generate the crate docs run `cargo doc --open` from `nym/sdk/rust/nym-sdk/`
|
||||
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
# Troubleshooting
|
||||
Below are several common issues or questions you may have.
|
||||
|
||||
If you come across something that isn't explained here, [PRs are welcome](https://github.com/nymtech/nym/issues/new/choose).
|
||||
|
||||
## Verbose `task client is being dropped` logging
|
||||
### On client shutdown (expected)
|
||||
If this is happening at the end of your code when disconnecting your client, this is fine; we just have a verbose client! When calling `client.disconnect().await` this is simply informing you that the client is shutting down.
|
||||
|
||||
On client shutdown / disconnect this is to be expected - this can be seen in many of the code examples as well. We use the [`nym_bin_common::logging`](https://github.com/nymtech/nym/blob/develop/common/bin-common/src/logging/mod.rs) import to set logging in our example code. This defaults to `INFO` level.
|
||||
|
||||
If you wish to quickly lower the verbosity of your client process logs when developing you can prepend your command with `RUST_LOG=<LOGGING_LEVEL>`.
|
||||
|
||||
If you want to run the `builder.rs` example with only `WARN` level logging and below:
|
||||
|
||||
```sh
|
||||
cargo run --example builder
|
||||
```
|
||||
|
||||
Becomes:
|
||||
|
||||
```sh
|
||||
RUST_LOG=warn cargo run --example builder
|
||||
```
|
||||
|
||||
You can also make the logging _more_ verbose with:
|
||||
|
||||
```sh
|
||||
RUST_LOG=debug cargo run --example builder
|
||||
```
|
||||
|
||||
### Not on client shutdown (unexpected)
|
||||
If this is happening unexpectedly then you might be shutting your client process down too early. See the [accidentally killing your client process](#accidentally-killing-your-client-process-too-early) below for possible explanations and how to fix this issue.
|
||||
|
||||
[//]: # (TODO note on poisson dance and not immediately killing client process)
|
||||
## Accidentally killing your client process too early
|
||||
If you are seeing either of the following errors when trying to run a client, specifically sending a message, then you may be accidentally killing your client process.
|
||||
|
||||
```sh
|
||||
2023-11-02T10:31:03.930Z INFO TaskClient-BaseNymClient-real_traffic_controller-ack_control-action_controller > the task client is getting dropped
|
||||
2023-11-02T10:31:04.625Z INFO TaskClient-BaseNymClient-received_messages_buffer-request_receiver > the task client is getting dropped
|
||||
2023-11-02T10:31:04.626Z DEBUG nym_client_core::client::real_messages_control::acknowledgement_control::input_message_listener > InputMessageListener: Exiting
|
||||
2023-11-02T10:31:04.626Z INFO TaskClient-BaseNymClient-real_traffic_controller-ack_control-input_message_listener > the task client is getting dropped
|
||||
2023-11-02T10:31:04.626Z INFO TaskClient-BaseNymClient-real_traffic_controller-reply_control > the task client is getting dropped
|
||||
2023-11-02T10:31:04.626Z DEBUG nym_client_core::client::real_messages_control > The reply controller has finished execution!
|
||||
2023-11-02T10:31:04.626Z DEBUG nym_client_core::client::real_messages_control::acknowledgement_control > The input listener has finished execution!
|
||||
2023-11-02T10:31:04.626Z INFO nym_task::manager > All registered tasks succesfully shutdown
|
||||
```
|
||||
|
||||
```sh
|
||||
2023-11-02T11:22:08.408Z ERROR TaskClient-BaseNymClient-topology_refresher > Assuming this means we should shutdown...
|
||||
2023-11-02T11:22:08.408Z ERROR TaskClient-BaseNymClient-mix_traffic_controller > Polling shutdown failed: channel closed
|
||||
2023-11-02T11:22:08.408Z INFO TaskClient-BaseNymClient-gateway_transceiver-child > the task client is getting dropped
|
||||
2023-11-02T11:22:08.408Z ERROR TaskClient-BaseNymClient-mix_traffic_controller > Assuming this means we should shutdown...
|
||||
thread 'tokio-runtime-worker' panicked at 'action control task has died: TrySendError { kind: Disconnected }', /home/.local/share/cargo/git/checkouts/nym-fbd2f6ea2e760da9/a800cba/common/client-core/src/client/real_messages_control/message_handler.rs:634:14
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
2023-11-02T11:22:08.477Z INFO TaskClient-BaseNymClient-real_traffic_controller-ack_control-input_message_listener > the task client is getting dropped
|
||||
2023-11-02T11:22:08.477Z ERROR TaskClient-BaseNymClient-real_traffic_controller-ack_control-input_message_listener > Polling shutdown failed: channel closed
|
||||
2023-11-02T11:22:08.477Z ERROR TaskClient-BaseNymClient-real_traffic_controller-ack_control-input_message_listener > Assuming this means we should shutdown...
|
||||
```
|
||||
|
||||
Using the following piece of code as an example:
|
||||
|
||||
```rust
|
||||
use nym_sdk::mixnet::{MixnetClient, MixnetMessageSender, Recipient};
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
enum Opts {
|
||||
Client {
|
||||
recipient: Recipient
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let opts: Opts = Parser::parse();
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
let mut nym_client = MixnetClient::connect_new().await.expect("Could not build Nym client");
|
||||
|
||||
match opts {
|
||||
Opts::Client { recipient } => {
|
||||
nym_client.send_plain_message(recipient, "some message string").await.expect("send failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is a simplified snippet of code for sending a simple hardcoded message with the following command:
|
||||
|
||||
```sh
|
||||
cargo run client <RECIPIENT_NYM_ADDRESS>
|
||||
```
|
||||
|
||||
You might assume that `send`-ing your message would _just work_ as `nym_client.send_plain_message()` is an async function; you might expect that the client will block until the message is actually sent into the mixnet, then shutdown.
|
||||
|
||||
However, this is not true.
|
||||
|
||||
**This will only block until the message is put into client's internal queue**. Therefore in the above example, the client is being shut down before the message is _actually sent to the mixnet_; after being placed in the client's internal queue, there is still work to be done under the hood, such as route encrypting the message and placing it amongst the stream of cover traffic.
|
||||
|
||||
The simple solution? Make sure the program/client stays active, either by calling `sleep`, or listening out for new messages. As sending a one-shot message without listening out for a response is likely not what you'll be doing, then you will be then awaiting a response (see the [message helpers page](message-helpers.md) for an example of this).
|
||||
|
||||
Furthermore, you should always **manually disconnect your client** with `client.disconnect().await` as seen in the code examples. This is important as your client is writing to a local DB and dealing with SURB storage.
|
||||
|
||||
## Client receives empty messages when listening for response
|
||||
If you are sending out a message, it makes sense for your client to then listen out for incoming messages; this would probably be the reply you get from the service you've sent a message to.
|
||||
|
||||
You might however be receiving messages without data attached to them / empty payloads. This is most likely because your client is receiving a message containing a [SURB request](https://nymtech.net/docs/architecture/traffic-flow.html#private-replies-using-surbs) - a SURB requesting more SURB packets to be sent to the service, in order for them to have enough packets (with a big enough overall payload) to split the entire response to your initial request across.
|
||||
|
||||
Whether the `data` of a SURB request being empty is a feature or a bug is to be decided - there is some discussion surrounding whether we can use SURB requests to send additional data to streamline the process of sending large replies across the mixnet.
|
||||
|
||||
You can find a few helper functions [here](message-helpers.md) to help deal with this issue in the meantime.
|
||||
|
||||
> If you can think of a more succinct or different way of handling this do reach out - we're happy to hear other opinions
|
||||
@@ -1,4 +0,0 @@
|
||||
# Typescript SDK
|
||||
The Typescript SDK allows developers to start building browser-based mixnet applications quickly, by simply importing the SDK into their code via NPM as they would any other Typescript library.
|
||||
|
||||
> If you'd like to learn more, build apps or integrate Nym components using the TS SDK, please visit the **dedicated [TS SDK Handbook](https://sdk.nymtech.net/)** !
|
||||
Reference in New Issue
Block a user