From 92b4dbb250bc71b3bfd2ad44d7fbf73d7d885dc0 Mon Sep 17 00:00:00 2001 From: serinko Date: Thu, 13 Jul 2023 16:51:04 +0200 Subject: [PATCH 001/146] initilizing operators guides mdbook --- documentation/operators/book.toml | 123 +++ documentation/operators/src/SUMMARY.md | 10 + documentation/operators/src/faq.md | 7 + .../src/images/wallet-screenshots/bonding.png | Bin 0 -> 56520 bytes .../wallet-screenshots/node_settings.png | Bin 0 -> 55864 bytes .../images/wallet-screenshots/wallet-sign.png | Bin 0 -> 111066 bytes documentation/operators/src/introduction.md | 34 + .../operators/src/nodes/mix-node-setup.md | 700 ++++++++++++++++++ .../operators/src/nodes/setup-guides.md | 18 + 9 files changed, 892 insertions(+) create mode 100644 documentation/operators/book.toml create mode 100644 documentation/operators/src/SUMMARY.md create mode 100644 documentation/operators/src/faq.md create mode 100644 documentation/operators/src/images/wallet-screenshots/bonding.png create mode 100644 documentation/operators/src/images/wallet-screenshots/node_settings.png create mode 100644 documentation/operators/src/images/wallet-screenshots/wallet-sign.png create mode 100644 documentation/operators/src/introduction.md create mode 100644 documentation/operators/src/nodes/mix-node-setup.md create mode 100644 documentation/operators/src/nodes/setup-guides.md diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml new file mode 100644 index 0000000000..c39bb1c6a1 --- /dev/null +++ b/documentation/operators/book.toml @@ -0,0 +1,123 @@ +[book] +title = "Nym Operators Guides" +authors = ["Max Hampshire", "serinko"] +description = "Guides to setup Nym infrastructure" +language = "en" +multilingual = false # for the moment - ideally work on chinese, brazillian, spanish next +src = "src" + +################# +# PREPROCESSORS # +################# + +# Note if changing these fields: +# - make sure you aren't running `mdbook serve` +# - change value of `turn-off = true` to `false`. This is set to `true` usually to avoid a known constant-reload bug with `mdbook serve` and this preprocessor +# - delete `./theme/` dir +# - change the preprocessor values that you want to edit +# - run `mdbook build`: this will rebuild the `./theme` directory +# - change value of `turn-off` back to `true` +[preprocessor.theme] +pagetoc = true +# some variables related (defined in theme/css/variables.css) +pagetoc-width = "13%" +content-max-width = "70%" # 82 +pagetoc-fontsize = "14.5px" +sidebar-width = "300px" +menu-bar-height = "40px" # memu-bar = the bar on the top +page-padding = "20px" +mobile-content-max-width = "98%" + +# layout +content-padding = "0 10px" +content-main-margin-left = "10%" +content-main-margin-right = "10%" +nav-chapters-max-width = "auto" +nav-chapters-min-width = "auto" +chapter-line-height = "2em" +section-line-height = "1.5em" + +# if true, never read and touch the files in theme dir: this is used to stop the looping reload issue referred to in the readme +turn-off = false + +[preprocessor.admonish] +command = "mdbook-admonish" +assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` + +# variables preprocessor: import variables into files +# https://gitlab.com/tglman/mdbook-variables/ +[preprocessor.variables.variables] +minimum_rust_version = "1.66" +# vars for links: TODO think on how to streamline updating +platform_release_version = "v1.1.22" +wallet_release_version = "v1.2.5" + +[preprocessor.last-changed] +command = "mdbook-last-changed" +renderer = ["html"] + +# used for grabbing output of binary commands for automation +# https://github.com/FauconFan/mdbook-cmdrun +[preprocessor.cmdrun] + +# more pre-processor plugins to look into from https://github.com/rust-lang/mdBook/wiki/Third-party-plugins & https://lib.rs/keywords/mdbook-preprocessor +# mdbook-i18n + +######### +# BUILD # +######### + +[build] +build-dir = "book" # the directory where the output is placed +create-missing = true # whether or not to create missing pages +use-default-preprocessors = true # use the default preprocessors +extra-watch-dirs = [] # directories to watch for triggering builds + +########## +# OUTPUT # +########## + +[output.html] +theme = "theme" # this is the default if not explicitly set +default-theme = "coal" +preferred-dark-theme = "coal" +curly-quotes = true +# mathjax-support = false # useful if we want to pull equations in +copy-fonts = true +no-section-label = false +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] +additional-js = ["theme/pagetoc.js"] +git-repository-url = "https://github.com/nymtech/nym" +git-repository-icon = "fa-github" +# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" +# site-url = "/docs/" +# cname = "nymtech.net" +# input-404 = "not-found.md" # todo make custom 404 page + +[output.html.fold] +enable = true # whether or not to enable section folding +level = 0 # the depth to start folding + +# controlling rust sample code blocks +[output.html.playground] +editable = false # allows editing the source code +copyable = true # include the copy button for copying code snippets +copy-js = true # includes the JavaScript for the code editor +line-numbers = false # displays line numbers for editable code +runnable = true # displays a run button for rust code + +# options for the built in text search +[output.html.search] +enable = true # enables the search feature +limit-results = 30 # maximum number of search results +teaser-word-count = 30 # number of words used for a search result teaser +use-boolean-and = true # multiple search terms must all match +boost-title = 2 # ranking boost factor for matches in headers +boost-hierarchy = 1 # ranking boost factor for matches in page names +boost-paragraph = 1 # ranking boost factor for matches in text +expand = true # partial words will match longer terms +heading-split-level = 3 # link results to heading levels +copy-js = true # include Javascript code for search + +# [output.linkcheck] +# warning-policy = "warn" diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md new file mode 100644 index 0000000000..7bb81c8800 --- /dev/null +++ b/documentation/operators/src/SUMMARY.md @@ -0,0 +1,10 @@ +- [Introduction](introduction.md) + +# Operators Guides + +- [Node Setup Guides](./nodes/setup-guides.md) + - [Mix Node](./nodes/mix-node-setup.md) + - [Gateway](./nodes/gateway-setup.md) + - [Network Requester](./nodes/network-requester-setup.md) +- [Troubleshooting](./nodes/troubleshooting.md) +- [FAQ](./faq.md) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md new file mode 100644 index 0000000000..d6b32f3e77 --- /dev/null +++ b/documentation/operators/src/faq.md @@ -0,0 +1,7 @@ + diff --git a/documentation/operators/src/images/wallet-screenshots/bonding.png b/documentation/operators/src/images/wallet-screenshots/bonding.png new file mode 100644 index 0000000000000000000000000000000000000000..b5cef3bb89bdde0e2d865001d14f9b4d1b1b28cc GIT binary patch literal 56520 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 literal 0 HcmV?d00001 diff --git a/documentation/operators/src/images/wallet-screenshots/node_settings.png b/documentation/operators/src/images/wallet-screenshots/node_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..69568ce6a540cbc1d6c4e0fea6d286451ebc189b GIT binary patch literal 55864 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%0Arw=^F)sf3iGu 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 z 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

l-5 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

ly}MeV>=*ZTQ0urb=*FZRXrf1u%f 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 literal 0 HcmV?d00001 diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md new file mode 100644 index 0000000000..f0344db71a --- /dev/null +++ b/documentation/operators/src/introduction.md @@ -0,0 +1,34 @@ +# Introduction + +This is Nym's operators guide, containing information and setup tutorials about the various pieces of Nym mixnet infrastructure nodes, such as mix node, gateway and network requester. + +If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). + +If you want to go deeper into Nym architecture and various software such as different, application clients, existing applications like the desktop wallet, mixnet explorer or SDKs, visit [Nym's technical documentation](https://nymtech.net/docs/). + +If you are looking for information on grants and beta-release Nym apps, check out the [Shipyard](https://shipyard.nymtech.net) site. + + +## Popular pages + + + +**Network Architecture:** +* [Network Overview](https://nymtech.net/docs/architecture/network-overview.html) +* [Mixnet Traffic Flow](https://nymtech.net/docs/architecture/traffic-flow.html) + +**Node setup and usage guides:** +* [Mix nodes](./nodes/mix-node-setup.md) +* [Gateways](./nodes/gateway-setup.md) +* [Network requesters](./nodes/network-requester-setup.md) + + +**Client setup and usage guides:** +* [Websocket client](https://nymtech.net/docs/clients/websocket-client.html) +* [Socks5 client](https://nymtech.net/docs/clients/socks5-client.html) +* [Webassembly client](https://nymtech.net/docs/clients/webassembly-client.html) + +**SDK guides:** +* [Typescript SDK](https://nymtech.net/docs/sdk/typescript.html) +* [Rust SDK](https://nymtech.net/docs/sdk/rust.html) + diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md new file mode 100644 index 0000000000..a24ec587ad --- /dev/null +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -0,0 +1,700 @@ + + +# Mix Nodes + +> The Nym mix node binary was built in the [building nym](https://nymtech.net/docs/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. + +> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. + +## Current version +``` + +``` + +The `nym-mixnode` binary is currently one point version ahead of the rest of the platform binaries due to a patch applied between releases. + +## Preliminary steps + +There are a couple of steps that need completing before starting to set up your mix node: + +- preparing your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) +- requisitioning a VPS (Virtual Private Server) + +### Wallet preparation + +#### Mainnet + +Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). + +If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. + +`NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several [exchanges](https://www.coingecko.com/en/coins/nym#markets). + +> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. + +#### Sandbox testnet + +Make sure to download a wallet and create an account as outlined above. Then head to our [token faucet](https://faucet.nymtech.net/) and get some tokens to use to bond it. + +### VPS Hardware Specs + +You will need to rent a VPS to run your mix node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol). + +For the moment, we haven't put a great amount of effort into optimizing concurrency to increase throughput, so don't bother provisioning a beastly server with multiple cores. This will change when we get a chance to start doing performance optimizations in a more serious way. Sphinx packet decryption is CPU-bound, so once we optimize, more fast cores will be better. + +For now, see the below rough specs: + +- Processors: 2 cores are fine. Get the fastest CPUs you can afford. +- RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. +- Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. + +## Mix node setup + +Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. + +To begin, move to `/taget/release` directory from which you run the node commands: + +``` +cd target/release +``` + +### Viewing command help + +You can check that your binaries are properly compiled with: + +``` +./nym-mixnode --help +``` + +Which should return a list of all available commands. + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +You can also check the various arguments required for individual commands with: + +``` +./nym-mixnode --help +``` + +### Initialising your mix node + +To check available configuration options for initializing your node use: + +``` +./nym-mixnode init --help +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +Initalise your mixnode with the following command, replacing the value of `--id` with the moniker you wish to give your mixnode, and the `--wallet-address` with the Nym address you created earlier. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. + +``` +./nym-mixnode init --id --host $(curl ifconfig.me) --wallet-address +``` + + +~~~admonish example collapsible=true title="Console output" +``` +.nym-mixnode init --id --host $(curl ifconfig.me) --wallet-address + + +Initialising mixnode ... +Saved mixnet identity and sphinx keypairs + 2023-06-04T08:20:32.862Z INFO nym_config > Configuration file will be saved to "/home//.nym/mixnodes//config/config.toml" +Saved configuration file to "/home//.nym/mixnodes//config/config.toml" +Mixnode configuration completed. + + _ __ _ _ _ __ ___ + | '_ \| | | | '_ \ _ \ + | | | | |_| | | | | | | + |_| |_|\__, |_| |_| |_| + |___/ + + (nym-mixnode - version {{mix_node_release_version}}) + + +Identity Key: DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"{{mix_node_release_version}}"},"cost_params +Sphinx Key: CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z +Host: 62.240.134.189 (bind address: 62.240.134.189) +Version: {{mix_node_release_version}} +Mix Port: 1789, Verloc port: 1790, Http Port: 8000 +``` +~~~ + +> The `init` command will refuse to destroy existing mix node keys. + +During the `init` process you will have the option to change the `http_api`, `verloc` and `mixnode` ports from their default settings. If you wish to change these in the future you can edit their values in the `config.toml` file created by the initialization process, which is located at `~/.nym/mixnodes//`. + +### Bonding your mix node + +```admonish caution +From `v1.1.3`, if you unbond your mixnode that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. +``` + +#### Bond via the Desktop wallet (recommended) + +You can bond your mix node via the Desktop wallet. + +* Open your wallet, and head to the `Bond` page, then select the node type `Mixnode` and input your node details. Press `Next`. + +* Enter the `Amount`, `Operating cost` and `Profit margin` and press `Next`. + +* You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it. + +``` +./nym-mixnode sign --id --contract-msg +``` + +It will look something like this: + +~~~admonish example collapsible=true title="Console output" +``` +./nym-mixnode sign --id upgrade_test --contract-msg 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4 + + _ __ _ _ _ __ ___ + | '_ \| | | | '_ \ _ \ + | | | | |_| | | | | | | + |_| |_|\__, |_| |_| |_| + |___/ + + (nym-mixnode - version {{mix_node_release_version}}) + + +>>> attempting to sign 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4 +>>> decoding the message... +>>> message to sign: {"nonce":0,"algorithm":"ed25519","message_type":"mixnode-bonding","content":{"sender":"n1eufxdlgt0puwrwptgjfqne8pj4nhy2u5ft62uq","proxy":null,"funds":[{"denom":"unym","amount":"100000000"}],"data":{"mix_node":{"host":"62.240.134.189","mix_port":1789,"verloc_port":1790,"http_api_port":8000,"sphinx_key":"CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z","identity_key":"DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"1.1.14"},"cost_params":{"profit_margin_percent":"0.1","interval_operating_cost":{"denom":"unym","amount":"40000000"}}}}} +``` +~~~ + +* Copy the resulting signature: + +``` +>>> The base58-encoded signature is: +2GbKcZVKFdpi3sR9xoJWzwPuGdj3bvd7yDtDYVoKfbTWdpjqAeU8KS5bSftD5giVLJC3gZiCg2kmEjNG5jkdjKUt +``` + +* And paste it into the wallet nodal, press `Next` and confirm the transaction. + +![Paste Signature](../images/wallet-screenshots/wallet-sign.png) + +* Your node will now be bonded and ready to mix at the beginning of the next epoch (at most 1 hour). + +> You are asked to `sign` a transaction on bonding so that the mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. + +#### Bond via the CLI (power users) +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. + +### Running your mix node + +Now you've bonded your mix node, run it with: + +``` +./nym-mixnode run --id +``` + +If everything worked, you'll see your node running on the either the [Sandbox testnet network explorer](https://sandbox-explorer.nymtech.net) or the [mainnet network explorer](https://explorer.nymtech.net), depending on which network you're running. + +Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list. + + + +Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. + +### Describe your mix node (optional) + +In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mixnode with the following command: + +``` +./nym-mixnode describe --id +``` + +> Remember to restart your mix node process in order for the new description to be propagated. + +### Upgrading your mix node + +Upgrading your node is a two-step process: +* Updating the binary and `~/.nym/mixnodes//config.toml` on your VPS +* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. + +#### Step 1: Upgrading your binary +Follow these steps to upgrade your mix node binary and update its config file: +* pause your mix node process. +* replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. +* restart your mix node process with the new binary. + +#### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). + +You can either do this graphically via the Desktop Wallet, or the CLI. + +#### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +\ +![Bonding page](../images/wallet-screenshots/bonding.png) + +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +\ +![Node Settings Page](../images/wallet-screenshots/node_settings.png) + +#### Updating node information via the CLI +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. + +### Displaying mix node information + +You can always check the details of your mix node with the `node-details` command: + +``` +./nym-mixnode node-details --id +``` + +## VPS Setup and Automation +### Configure your firewall +The following commands will allow you to set up a firewall using `ufw`. + +``` +# check if you have ufw installed +ufw version + +# if it is not installed, install with +sudo apt install ufw -y + +# enable ufw +sudo ufw enable + +# check the status of the firewall +sudo ufw status +``` + +Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: + +``` +sudo ufw allow 1789,1790,8000,22/tcp + +# check the status of the firewall +sudo ufw status +``` + +For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. + +### Automating your mix node with tmux and systemd + +It's useful to have the mix node automatically start at system boot time. + +#### tmux + +One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated. + +Use the following command to get `tmux`. + +Platform|Install Command +---|--- +Arch Linux|`pacman -S tmux` +Debian or Ubuntu|`apt install tmux` +Fedora|`dnf install tmux` +RHEL or CentOS|`yum install tmux` +macOS (using Homebrew|`brew install tmux` +macOS (using MacPorts)|`port install tmux` +openSUSE|`zypper install tmux` + +In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control). + +**Running tmux** + +No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let the mixnode run on its own on the VPS. + +* Pause your mixnode +* Start tmux with the command +``` +tmux +``` +* The terminal should stay in the same directory, just the layout changed into tmux default layout. +* Start the mixnode again with a command: +``` +./nym-mixnode run --id +``` +* Now, without closing the tmux window, you can close the whole terminal and the mixnode (and any other process running in tmux) will stay active. +* Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session: +``` +tmux attach session +``` +* To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?` + +#### systemd + +Here's a systemd service file to do that: + +```ini +[Unit] +Description=Nym Mixnode ({{mix_node_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User= +LimitNOFILE=65536 +ExecStart=/home///nym-mixnode run --id +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. + +Change the `` in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `` so it is the user you are running as. + +If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` + +Then run: + +``` +systemctl enable nym-mixnode.service +``` + +Start your node: + +``` +service nym-mixnode start +``` + +This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. + +You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. + +Note: if you make any changes to your systemd script after you've enabled it, you will need to run: + +``` +systemctl daemon-reload +``` + +This lets your operating system know it's ok to reload the service configuration. + +#### Setting the ulimit + +Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. + +`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes. + +If you see errors such as: + +``` +Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } +``` + +This means that the operating system is preventing network connections from being made. + +##### Set the ulimit via `systemd` service file + +Query the `ulimit` of your mix node with: + +``` +grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits +``` + +You'll get back the hard and soft limits, which looks something like this: + +``` +Max open files 65536 65536 files +``` + +If your output is **the same as above**, your node will not encounter any `ulimit` related issues. + +However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: + +``` +LimitNOFILE=65536 +``` + +Reload the daemon: + +``` +systemctl daemon-reload +``` + +or execute this as root for system-wide setting of `ulimit`: + +``` +echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf +``` + +Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. + +##### Set the ulimit on `non-systemd` based distributions + +In case you chose tmux option for mixnode automatization, see your `ulimit` list by running: + +``` +ulimit -a + +# watch for the output line -n +-n: file descriptors 1024 +``` + +You can change it either by running a command: + +``` +ulimit -u -n 4096 +``` + +or editing `etc/security/conf` and add the following lines: + +``` +# Example hard limit for max opened files +username hard nofile 4096 + +# Example soft limit for max opened files +username soft nofile 4096 +``` + +Then reboot your server and restart your mixnode. + +## Node Description +Node description is a short text that describes your node. It is displayed in the `./nym-mixnode list` command and in the `./nym-mixnode node-details` command. It also shows up in the node explorer to let people know what your node is about and link to your website. + +To set your node description, create a file called `description.toml` and put it in the same directory as your `config.toml` file (`~/.nym/mixnodes//description.toml`). The file should look like this example: + +```toml +name = "Winston Smith" +description = "I am the Sphinx" +link = "https://nymtech.net" +location = "Giza, Egypt" +``` + +You will need to restart your node for the changes to take effect. + +## Node Families + +Node family involves setting up a group of mix nodes that work together to provide greater privacy and security for network communications. This is achieved by having the nodes in the family share information and routes, creating a decentralized network that makes it difficult for third parties to monitor or track communication traffic. + +### Create a Node Family + +To create a Node family, you will need to install and configure multiple mix nodes, and then use the CLI to link them together into a family. Once your Node family is up and running, you can use it to route your network traffic through a series of nodes, obscuring the original source and destination of the communication. + +You can use either `nym-cli` which can be downloaded from the [release page](https://github.com/nymtech/nym/releases) or compiling `nyxd`. + + +Change directory by `cd ///` and run the following on the family head to obtain the signature for the member: + +``` +./nym-mixnode sign --id --text +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +Using `nym-cli`: + +> `--mnemonic` is the mnemonic of the member wanting to be the head of family. + +``` +/nym-cli cosmwasm execute '{"create_family": {"signature": "","family_head": "","owner_signature":"","label": ""}}' --mnemonic +``` + +Using `nyxd`: + +> `--from` is mnemonic of the member wanting to join the family. + +``` +./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block +``` + +To get the node owner signature, use: + +`./nym-mixnode node-details --id ` + +### Joining a Node Family + +Change directory by `cd ///` and run the following on the family head to obtain the signature for the member: + +``` +./nym-mixnode sign --id --text +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +Using `nym-cli`: + +``` +./nym-cli cosmwasm execute '{"join_family": {"signature": "","family_head": "","owner_signautre": "", "label":""}}' --mnemonic +``` + +Using `nyxd`: + +``` +./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block +``` + + +To get the node owner signature, use: + +`./nym-mixnode node-details --id ` + + +### Leaving a family +If wanting to leave, run the same initial command as above, followed by: + +Using `nym-cli`: + +``` +./nym-cli cosmwasm execute '{"leave_family": {"signature": "","family_head": "","owner_signautre": ""}}' --mnemonic +``` + +Using `nyxd`: + +``` +./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block +``` + +## Checking that your node is mixing correctly +### Network explorers +Once you've started your mix node and it connects to the validator, your node will automatically show up in the 'Mix nodes' section of either the Nym Network Explorers: + +- [Mainnet](https://explorer.nymtech.net/overview) +- [Sandbox testnet](https://sandbox-explorer.nymtech.net/) + +Enter your **identity key** to find your node. There are numerous statistics about your node on that page that are useful for checking your uptime history, packets mixed, and any delegations your node may have. + +There are also 2 community explorers which have been created by [Nodes Guru](https://nodes.guru): + +- [Mainnet](https://mixnet.explorers.guru/) +- [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) + +For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) + + + +### Virtual IPs and hosting via Google & AWS +For tru internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a mixnode there, please read the following. + +On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl ifconfig.me)`, but also specify `--announce-host` with the public IP. Please make sure that you pass the correct, routable `--announce-host`. + +For example, on a Google machine, you may see the following output from the `ifconfig` command: + +``` +ens4: flags=4163 mtu 1460 + inet 10.126.5.7 netmask 255.255.255.255 broadcast 0.0.0.0 + ... +``` + +The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. + +`./nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. + +Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. + +The right thing to do in this situation is to init with a command: +``` +./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18 +``` + +This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. + +To find the right IP configuration, contact your VPS provider for support. + +## Metrics / API endpoints +The mix node binary exposes several API endpoints that can be pinged in order to gather information about the node, and the Nym API (previously 'Validator API') exposes numerous mix node related endpoints which provide network-wide information about mix nodes, the network topology (the list of avaliable mix nodes for packet routing), and information regarding uptime monitoring and rewarding history. + +### Mix node API endpoints +Since the mix node binary exposes several API endpoints itself, you can ping these easily via curl: + +| Endpoint | Description | Command | +| -------------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | +| `/description` | Returns the description of the node set with the `describe` command | `curl :8000/description` | +| `/hardware` | Returns the hardware information of the node | `curl :8000/hardware` | +| `/verloc` | Returns the verloc information of the node, updated every 12 hours | `curl :8000/verloc` | + +The code for exposed API endpoints can be found [here](https://github.com/nymtech/nym/tree/release/{{platform_release_version}}/mixnode/src/node/http). + +> You can get more detailed info by appending `?debug` to the URL, like so: +> ``` +> curl http://:8000/stats?debug +> ``` + +### Mix node related Nym API (previously 'Validator API') endpoints +Numerous endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. + +#### Mix node Reward Estimation API endpoint + +The Reward Estimation API endpoint allows mixnode operators to estimate the rewards they could earn for running a Nym mixnode with a specific `MIX_ID`. + +> The `` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). + +The endpoint is a particularly common for mixnode operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mixnode, the quality of the mixnode's performance, and the overall demand for mixnodes in the network. This information can be useful for mixnode operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability. + +Using this API endpoint returns information about the Reward Estimation: + +``` +/status/mixnode//reward-estimation +``` + +Query Response: + +``` + "estimation": { + "total_node_reward": "942035.916721770541325331", + "operator": "161666.263307386408152071", + "delegates": "780369.65341438413317326", + "operating_cost": "54444.444444444444444443" + }, +``` + +> The unit of value is measured in `uNYM`. + +- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node. + +- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network. + +- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network. + +- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. + +- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. + +## Ports +All mix node-specific port configuration can be found in `$HOME/.nym/mixnodes//config/config.toml`. If you do edit any port configs, remember to restart your mix node. + +### Mix node port reference +| Default port | Use | +| ------------ | ------------------------- | +| `1789` | Listen for mixnet traffic | +| `1790` | Listen for VerLoc traffic | +| `8000` | Metrics http API endpoint | +/ + diff --git a/documentation/operators/src/nodes/setup-guides.md b/documentation/operators/src/nodes/setup-guides.md new file mode 100644 index 0000000000..b19cf07deb --- /dev/null +++ b/documentation/operators/src/nodes/setup-guides.md @@ -0,0 +1,18 @@ + +# Node Setup Guides + +To setup any type of Nym's node, start with building [Nym's platform](https://nymtech.net/docs/binaries/building-nym.html) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). + +This section contains setup guides for the following node types: +* [Mix node](./mix-node-setup.md) +* [Gateway](./gateway-setup.md) +* [Network Requester](./network-requester-setup.md) +* [Validator](./validator-setup.md) + + From 7e5c79848ff4d64185b0b32a482fb57b04a91096 Mon Sep 17 00:00:00 2001 From: serinko Date: Thu, 13 Jul 2023 16:59:25 +0200 Subject: [PATCH 002/146] feature/operators-guide: coppied all configs from ../docs/ --- documentation/operators/.gitignore | 27 ++ documentation/operators/mdbook-admonish.css | 352 ++++++++++++++++++ .../operators/src/nodes/gateway-setup.md | 1 + .../src/nodes/network-requester-setup.md | 1 + .../operators/src/nodes/troubleshooting.md | 1 + 5 files changed, 382 insertions(+) create mode 100644 documentation/operators/.gitignore create mode 100644 documentation/operators/mdbook-admonish.css create mode 100644 documentation/operators/src/nodes/gateway-setup.md create mode 100644 documentation/operators/src/nodes/network-requester-setup.md create mode 100644 documentation/operators/src/nodes/troubleshooting.md diff --git a/documentation/operators/.gitignore b/documentation/operators/.gitignore new file mode 100644 index 0000000000..e84b38bdfb --- /dev/null +++ b/documentation/operators/.gitignore @@ -0,0 +1,27 @@ +# mdbook files +book +book/* +theme/index.hbs +theme/pagetoc.css +theme/pagetoc.js +theme/* +theme + +# --------------- +# Compiled assets +# --------------- +.sass-cache +_site + +# ---------- +# Developing +# ---------- +todo.md +.vscode + +# OSX +.DS_Store + +theme/ +theme +theme/* diff --git a/documentation/operators/mdbook-admonish.css b/documentation/operators/mdbook-admonish.css new file mode 100644 index 0000000000..5e360387df --- /dev/null +++ b/documentation/operators/mdbook-admonish.css @@ -0,0 +1,352 @@ +@charset "UTF-8"; +:root { + --md-admonition-icon--note: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--abstract: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--info: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--tip: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--success: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--question: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--warning: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--failure: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--danger: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--bug: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--example: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--quote: + url("data:image/svg+xml;charset=utf-8,"); + --md-details-icon: + url("data:image/svg+xml;charset=utf-8,"); +} + +:is(.admonition) { + display: flow-root; + margin: 1.5625em 0; + padding: 0 1.2rem; + color: var(--fg); + page-break-inside: avoid; + background-color: var(--bg); + border: 0 solid black; + border-inline-start-width: 0.4rem; + border-radius: 0.2rem; + box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); +} +@media print { + :is(.admonition) { + box-shadow: none; + } +} +:is(.admonition) > * { + box-sizing: border-box; +} +:is(.admonition) :is(.admonition) { + margin-top: 1em; + margin-bottom: 1em; +} +:is(.admonition) > .tabbed-set:only-child { + margin-top: 0; +} +html :is(.admonition) > :last-child { + margin-bottom: 1.2rem; +} + +a.admonition-anchor-link { + display: none; + position: absolute; + left: -1.2rem; + padding-right: 1rem; +} +a.admonition-anchor-link:link, a.admonition-anchor-link:visited { + color: var(--fg); +} +a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { + text-decoration: none; +} +a.admonition-anchor-link::before { + content: "§"; +} + +:is(.admonition-title, summary) { + position: relative; + margin-block: 0; + margin-inline: -1.6rem -1.2rem; + padding-block: 0.8rem; + padding-inline: 4.4rem 1.2rem; + font-weight: 700; + background-color: rgba(68, 138, 255, 0.1); + display: flex; +} +:is(.admonition-title, summary) p { + margin: 0; +} +html :is(.admonition-title, summary):last-child { + margin-bottom: 0; +} +:is(.admonition-title, summary)::before { + position: absolute; + top: 0.625em; + inset-inline-start: 1.6rem; + width: 2rem; + height: 2rem; + background-color: #448aff; + mask-image: url('data:image/svg+xml;charset=utf-8,'); + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; +} +:is(.admonition-title, summary):hover a.admonition-anchor-link { + display: initial; +} + +details.admonition > summary.admonition-title::after { + position: absolute; + top: 0.625em; + inset-inline-end: 1.6rem; + height: 2rem; + width: 2rem; + background-color: currentcolor; + mask-image: var(--md-details-icon); + -webkit-mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; + transform: rotate(0deg); + transition: transform 0.25s; +} +details[open].admonition > summary.admonition-title::after { + transform: rotate(90deg); +} + +:is(.admonition):is(.note) { + border-color: #448aff; +} + +:is(.note) > :is(.admonition-title, summary) { + background-color: rgba(68, 138, 255, 0.1); +} +:is(.note) > :is(.admonition-title, summary)::before { + background-color: #448aff; + mask-image: var(--md-admonition-icon--note); + -webkit-mask-image: var(--md-admonition-icon--note); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.abstract, .summary, .tldr) { + border-color: #00b0ff; +} + +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { + background-color: rgba(0, 176, 255, 0.1); +} +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { + background-color: #00b0ff; + mask-image: var(--md-admonition-icon--abstract); + -webkit-mask-image: var(--md-admonition-icon--abstract); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.info, .todo) { + border-color: #00b8d4; +} + +:is(.info, .todo) > :is(.admonition-title, summary) { + background-color: rgba(0, 184, 212, 0.1); +} +:is(.info, .todo) > :is(.admonition-title, summary)::before { + background-color: #00b8d4; + mask-image: var(--md-admonition-icon--info); + -webkit-mask-image: var(--md-admonition-icon--info); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.tip, .hint, .important) { + border-color: #00bfa5; +} + +:is(.tip, .hint, .important) > :is(.admonition-title, summary) { + background-color: rgba(0, 191, 165, 0.1); +} +:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { + background-color: #00bfa5; + mask-image: var(--md-admonition-icon--tip); + -webkit-mask-image: var(--md-admonition-icon--tip); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.success, .check, .done) { + border-color: #00c853; +} + +:is(.success, .check, .done) > :is(.admonition-title, summary) { + background-color: rgba(0, 200, 83, 0.1); +} +:is(.success, .check, .done) > :is(.admonition-title, summary)::before { + background-color: #00c853; + mask-image: var(--md-admonition-icon--success); + -webkit-mask-image: var(--md-admonition-icon--success); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.question, .help, .faq) { + border-color: #64dd17; +} + +:is(.question, .help, .faq) > :is(.admonition-title, summary) { + background-color: rgba(100, 221, 23, 0.1); +} +:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { + background-color: #64dd17; + mask-image: var(--md-admonition-icon--question); + -webkit-mask-image: var(--md-admonition-icon--question); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.warning, .caution, .attention) { + border-color: #ff9100; +} + +:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { + background-color: rgba(255, 145, 0, 0.1); +} +:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { + background-color: #ff9100; + mask-image: var(--md-admonition-icon--warning); + -webkit-mask-image: var(--md-admonition-icon--warning); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.failure, .fail, .missing) { + border-color: #ff5252; +} + +:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { + background-color: rgba(255, 82, 82, 0.1); +} +:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { + background-color: #ff5252; + mask-image: var(--md-admonition-icon--failure); + -webkit-mask-image: var(--md-admonition-icon--failure); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.danger, .error) { + border-color: #ff1744; +} + +:is(.danger, .error) > :is(.admonition-title, summary) { + background-color: rgba(255, 23, 68, 0.1); +} +:is(.danger, .error) > :is(.admonition-title, summary)::before { + background-color: #ff1744; + mask-image: var(--md-admonition-icon--danger); + -webkit-mask-image: var(--md-admonition-icon--danger); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.bug) { + border-color: #f50057; +} + +:is(.bug) > :is(.admonition-title, summary) { + background-color: rgba(245, 0, 87, 0.1); +} +:is(.bug) > :is(.admonition-title, summary)::before { + background-color: #f50057; + mask-image: var(--md-admonition-icon--bug); + -webkit-mask-image: var(--md-admonition-icon--bug); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.example) { + border-color: #7c4dff; +} + +:is(.example) > :is(.admonition-title, summary) { + background-color: rgba(124, 77, 255, 0.1); +} +:is(.example) > :is(.admonition-title, summary)::before { + background-color: #7c4dff; + mask-image: var(--md-admonition-icon--example); + -webkit-mask-image: var(--md-admonition-icon--example); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.quote, .cite) { + border-color: #9e9e9e; +} + +:is(.quote, .cite) > :is(.admonition-title, summary) { + background-color: rgba(158, 158, 158, 0.1); +} +:is(.quote, .cite) > :is(.admonition-title, summary)::before { + background-color: #9e9e9e; + mask-image: var(--md-admonition-icon--quote); + -webkit-mask-image: var(--md-admonition-icon--quote); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +.navy :is(.admonition) { + background-color: var(--sidebar-bg); +} + +.ayu :is(.admonition), .coal :is(.admonition) { + background-color: var(--theme-hover); +} + +.rust :is(.admonition) { + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { + color: var(--sidebar-fg); +} diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md new file mode 100644 index 0000000000..f4ee68e242 --- /dev/null +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -0,0 +1 @@ +# Gateway diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md new file mode 100644 index 0000000000..797dfd7795 --- /dev/null +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -0,0 +1 @@ +# Network Requester diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md new file mode 100644 index 0000000000..4f341277d3 --- /dev/null +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -0,0 +1 @@ +# Troubleshooting From 153e899e0e924c5542e00d4fc5254efb9f6aca97 Mon Sep 17 00:00:00 2001 From: serinko Date: Fri, 14 Jul 2023 11:20:51 +0200 Subject: [PATCH 003/146] mixnode-seup: minor edits --- documentation/operators/src/introduction.md | 10 ++++++++-- documentation/operators/src/nodes/mix-node-setup.md | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index f0344db71a..d2c148bf64 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -21,7 +21,13 @@ If you are looking for information on grants and beta-release Nym apps, check ou * [Mix nodes](./nodes/mix-node-setup.md) * [Gateways](./nodes/gateway-setup.md) * [Network requesters](./nodes/network-requester-setup.md) - +* [Validators](./nodes/validator-setup.md) + +**Troubleshooting and FAQ** +* [Troubleshooting](./nodes/troubleshooting.md) +* [FAQ](./faq.md) + + diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index a24ec587ad..723984ff39 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -63,7 +63,7 @@ For now, see the below rough specs: ## Mix node setup -Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](https://nymtech.net/docs/binaries/building-nym.html), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. To begin, move to `/taget/release` directory from which you run the node commands: From ff65d052b86160886b1a3d98a421e859714b1706 Mon Sep 17 00:00:00 2001 From: serinko Date: Fri, 14 Jul 2023 13:25:12 +0200 Subject: [PATCH 004/146] operators-guide: created generic docs maintenance.md and preliminary-steps.md to avoid redundancy --- documentation/operators/src/SUMMARY.md | 3 + documentation/operators/src/faq.md | 7 + .../wallet-gateway-sign.png | Bin 0 -> 118052 bytes documentation/operators/src/introduction.md | 3 +- .../operators/src/nodes/gateway-setup.md | 254 ++++++++++++- .../operators/src/nodes/maintenance.md | 357 ++++++++++++++++++ .../operators/src/nodes/mix-node-setup.md | 35 +- .../operators/src/preliminary-steps.md | 43 +++ 8 files changed, 667 insertions(+), 35 deletions(-) create mode 100644 documentation/operators/src/images/wallet-screenshots/wallet-gateway-sign.png create mode 100644 documentation/operators/src/nodes/maintenance.md create mode 100644 documentation/operators/src/preliminary-steps.md diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 7bb81c8800..796c7d41ed 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -3,8 +3,11 @@ # Operators Guides - [Node Setup Guides](./nodes/setup-guides.md) +- [Preliminary Steps](./preliminary-steps.md) - [Mix Node](./nodes/mix-node-setup.md) - [Gateway](./nodes/gateway-setup.md) - [Network Requester](./nodes/network-requester-setup.md) + - [Validator](./nodes/validator-setup.md) +- [Maintenance](./nodes/maintenance.md) - [Troubleshooting](./nodes/troubleshooting.md) - [FAQ](./faq.md) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index d6b32f3e77..5e1f5b72ad 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -4,4 +4,11 @@ TODO - [ ] List friendly VPS providers - [ ] Explain difficulty running a node on a self-hosted machine - [ ] Explain uNYM vs NYM. Why, ratio, etc + +Some community questions: +Hi, do you know if it's on the roadmap for network nodes (requesters, socks5 client, etc.) to reconnect to another gateway if the current gateway's connection drops or has issues? I have to reset my requester and socks5 clients to connect them to a new gateway almost every day...😕 having to delete the entire folders associated with them + +you should be able to switch gateway (and overwrite keys) using —force-register + + ---> diff --git a/documentation/operators/src/images/wallet-screenshots/wallet-gateway-sign.png b/documentation/operators/src/images/wallet-screenshots/wallet-gateway-sign.png new file mode 100644 index 0000000000000000000000000000000000000000..63a76aaf4daa49a970ceed5e65c6bcf03891d507 GIT binary patch literal 118052 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

gh{@Ld5VYc~WzO%W;Gv3S$jd$h&x{|!h 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

@E}Q7HmryqarIxWXBsD9W9l?>YP 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

TaZoR+yex1nQT6Ur! z1bY=;Ig?Sl{UDQy`?FE0UZ`fE$<~oeI*(}+|4ZtD*99D>1IXgx_{{PpW{l)J|zC2qS1i5jVb zFLDRx8vLT=+oY@)bnBa8CT8aIyBo2Y+-)hGW>1dLL8FaVc3c15K(7ldMAF*PAXqXSBPpXa%JGJf$pgzy7&v8rgc7voqJJ z28-UVRVo#3DSwmTW88ZO?SelaX-*59uQCd{p`7X3)U&whcxk=FTMAEp^9193t>7P9 z1JN`xPnccGWpZBc?pAqLuNVGRJEcuhMx!cVT2FL4wOK=&YrodzAC*)b7xbqKNIPtW zoFf<*q_`0WrxrOmEw^vT{GD|V)wHroG%5o^(<1^)?9}Le2haX2iIAM{Te+#jh`uaz zO20J3do4qiJtivhCGUL+pI|@|fGJ59kqV#O_NkdX@49<+m+{^4KL_2;z3l$y1Z=v+ zSKxh$nU7Pt`!cx1kJ>%}s)v+b+W&YCTa|lPA%<>IF;}PPD8zGpe{_>oJyR?IB^d`# z7q_{ilmMZF$mI?Wt@S=5sG8i`C>m}G@OPbQmRfkX?qxKY$047~=Q8IUN)`uKQ&VaU zUe+_u?hrF{RIbi83C{U`h(xDrWa)+YZZ%9=cPXYvkbM)M+dDqU9kd6VecE^7A^JxZ zbdey3@R3bKY@qMxkkxxPg3STgj$>iDSr==UC=AiRqbBy;0XlT;6 ze4r8F0H3=)1NvgXSGM=R-jFRxhurxor(=CxW*zt5&h#ev^%pM;h3t+>$zQ}Dqaa^z z)(O_9srGX_r0DA~g}%EAys6`EbB;UfUxYl*vM-vLrMVxAimpd2v+6pc-+wHAQvF(egZRN6Ng3=27LzmTx?vb3FQMxp2xzAyf8Cu01wR+*=D zOXz#y$+up|=LEVsdO=NAh(EWKKm_-hiH0nNvSgYagH7Sv#`;lXs?Lu&qPNJ&UNBuv z<}DuRBqL($5Tob?i389Wa-EeLn{bIVs^*088Eek0gz5_*Pv~ z65wSiqr5-DFcHi?^L`3Q(19ebh0x9Jt*pQD9;~%_EODEsE^(!1| z#Z#v5q0z(yISO%IFkk-|JO@^C8PVABk+IQ{G1C^G8YtAx3UxM;w1Q8{0HtlU|8>rm z$cn{5E?!q1Ca70rXU7X$`QH|5%U`3+?F4*IcE5hHjzsH(ZeWhr01?sbuQr8EBr=m$ z4?H{SAM7~C7AE7jyIXI3TiA8FnvI{oxuk>^{)&Ntp~Wm@X(V+>MPIMNL>eMcRsuCH z(h3U?{is1>{K8Nd{e6lLzftvbjjOkuO>&&3sNE4~jC{cMnVO@{Xd<$hRl`V$CO_#yT^QXOpWXUfSHJFO7u!#{YhZ~cRu-}r8?S1r?V+f9wIZH|?WY##a~fb7~e zx=D}|9^R1&J>oRY$V{&pvlqM-_KsDf_&CT@G1qTz#nr_nNG5O#1eixr(l4MYu4#I! zaS3(V)?|u$uQ7z|dH%Mg-Tg6lLn#3f6;+^`H8MB2IHW+9mtTiE$b?c^+mssDL^WMJ z1q~IyYwCCAR3hWlR3k-FdxX=~9w&Y_ZPoJGxDEco-5R;}7xCmApSkHpY=2Bz7L~ZE zDg{&KRen)znd7zfdY5eyOXg5z(9{&5p2g0|23=viR?#%6_E`Jn)1SXfRZ|uLhPUT$ zLC)a4o`3dFJ<#l=oQy1y!q7_w($U=MS@v+bo-=6Q#Zg>X1=q+xZXu)mkIr~aM-y3N zS;N_4)Oz8;qV!a>ZPxq};^N)h=C52&%nZ@j;gwMZqp=fTVHyz3x2nd}v*3-c+RN{A zYZ8&4MjUH{&nBr{wjYcbB(TI`-M=;FJrZYE{)r&JJ~&*`5QLzYS@*Jd;i;1TroWB1 zR3q2V#7wE>ZTGA@vc;6~*R#;sxw%2VRit;Oo-z7+TH7M0X~OK-91iT^O!bJxhQDyu zfW<&aWApc|gb1SMVhP_J1qHbdczY8O4>z}8UH~CpAoaiD9R60Xgd+fVW=2I>g5FPd zN~tjM6yeHLhk9dBWz)X+bP_&2)S&|(wCxISie2*v4%1VxOF78aD;ZtAVJw`!-O)RZ zm7otYG23fs{&vwbODvM63bLXYY0eogF6Mr%?P!!+96iPhP9>g6-^LrSn3Tq!j1=sA ze$#ApdH;6q;NO=GS?BhG;&~nmIO8iPZ~kK)>`cxMzq^ZO>@9ahwYPSEwjLJ|G;1(8 z>pMWFxziOaHpFQH6qYl-DMr^9x&DMZB>*vpW$=CG1D$Pqa0joM_}_FC@$@IcjqUFN z#i>#0=ZfQ?;mJ{{88MpTj{JNpNQUaixbFVmsyo7TZGm#%rhQS{7i$CVcEoQ;@BjPq zfZTfhy$w6_k&)431{*<|3X>LB*3Pr=j_#C-R!nn?aLe58X^OcTT{cUiaw=#3q%&$; zS4T&xh}K@{3Lb>=-;H!EUm>$N8U3K!7>DEEiu>1@5w39%rE1 zA|?FieZjZ?zgJNa(lht*7G`sXH%z!w+O3xa>EM-%eU}wy_H_v$??ERmg{eOZr@J)N zT>B|;^|Iuo4!?EdDt&f@A`;@!;0Y?}g@UVa-i&8DjBt{MIQRM{DmuU9@S1d2f1tD1+M>7^^0e6Cn{0g z&NC{bM>T_WJ5gd*(#q4b5(Tj9@a8p1Ry=9v0d2CApSQxUzI&)cc3B5f(E2L zylfD-`g8imCF}4(mMKq}*ySzwZz6J~1ok{-mOI40^8ZOLa9=|D|0Eau-@ol%B>J!9 zf~a_=Ypqelf6x+oCCTa$2-aWtB){=?-?s4)8C?g})9XhpO23UC|H3Ezzs8h+k%Eu^ zS;2m|*oTJ)VPyW6d*|-bqdR;`31u$Z`W0s5NUxD6sjA{OL$VX#XeO^xaKY(!Z(+bg=upEW;Mh&@6(&|NzXoI@se z)6%B*nLl|(aO?VcMr{cxy;!kM@l2U?c7M94MWDSRK}vU(5hwI$tL@dy!4jPl!X4yr z_$md~PTgi9{rPoBHKABhwTN~lDfKzS<%EX1UZkQDQ})&8o%oo zVOqt!{PYLq+)9+H;U*vyYre5!R@k`&7 zr%N;HW?SV-Q6fB6eI{Vxt6oV!%MCx?1+!x-E^z=hL3y$@RWn{y%7_x+-na!dtr!;( z7MgDgN-6fodiK5K{cO#%KJ3^}L6OL^@#TXGxFp17-pIYKu%W!w;%At=oLpb}!62&Q zI91gav8c_e5fvLd<@<8C`Y6y~S8^2C4ngg=%63hJ%iJq)L%4Hazm#9oK%Pf$ni$}lGNe68 z7zL9AQO$mQR~A+mT=DSwWo1LDoM(7#Rln&l-MUR=(&{ysHp;m zB?9#96)UZ9IyVD@t34z5k=h}q`3P^K*R(=>CdF|?X zCZzi_XPO8CT#NRgS@TQJd2>dir*uMOJ5#)dqw@aPyTBaHNV0u2g%}Sv3roX8h_5{I zhrSVy-Fr&n==Lr%-jLp63Q#3e-o9SZ@{siA%w}+@9K7RWPk;9-v(M0=4%4~EY8elc zm9L&-?<_6vdyH|LW=Os4<0I-?{xG!8ZJLgPV#77Zi^k>P>9qCi zl&*GxDvfhYwoOl)#jiFUP(2qFb#k{ovfTUpE(ZKdC(BQAE{Rb*poz1dypfA( zOLt&KMO@RDY(5@`nJ-xUI2|1w2XAr8LV0 ze#0YdM^{ZFvyP1ian?JXQeo!g;!EuEka_$#=uUV5OhVo>-?iFSxcGooe+$Y#o(#axLcN#zKPM%Qrh}q(h4YHo-4El zB#z3`N87enx3hI>cXO}(9lunjKSdPlA)cQl|qv_fr6*3<=oTlr{g0kStNZHMih8F3~52Ex7{hOz$3U z6%h8nfb_U*Z&M`m%u0>Z5{*;@DA=*e*uOe@w*VG?r^U)y!_CdgN?Y5r+Z=ZiAxBt) z+tdgF+=M|7V0nB|vm!JxD6qxzYinHqrDH6DNHJ}lnHpU)K(Nc|Eb9`49d#0M7N(VngfEwyL(lrNQBQ*BtbY%lSPis02u_uk zyCU*V&Y~#oc&Npg{C}N)60X7#AILQ0eS2qBAO>WBFy%CKgNGv ze&UgDg!WA2AU-m)8ac&#jn+uD4Z&8K!~@<3rAy@8zpy4voxc1y&`AGd;j8 zuKX_TF|4sYB)vvQ(Q8@TP_q1dj|TphVf+myJ?5b#)m;#`_V=#;B`VbV|qE zWE>e7`D0sC0Dcp!>KC2>pD~#XD1}VlO*NeXc5QfgO?>{(@xbHnA!*;1q5+TNM?1#V z({)JkfrL&{RW$RM)96e4>MK%)Qxdo-$7|cOW&j`Lq<`=3R?eWEE)ThI_(!@8=6ho! zm#>?tbnOMniky5gwn&nv975OjMHS#mP>~Yde6Q}=GDAjjzsgUWel*{lJ2AMq_93^= zy%_n#ZX4PI4=wEkK+VY5%X$GCYO58CuS@TiEIP1psN0=l#@RA5IT{15Aqw}lQeYMD z0HvXGSHHLZJMOTdnW3Qpa7{rcQ`JOD_bPW!m(G(UZmt5pOLjS4k!7mp_)WW`oDQE0 zmqCrk>6bs(Kgiypxsw61_snEX;UQp^K>5zk`_ud(+4UPY0r{~hDRLQY;`_75pfa31 zbMd54F|K^|TqclCCbD}KFt3c#!W{=uc03s{*WRweLV`vUVGrvcI_!JRO0!%vj6Zle zJV(21-oCxU6mO5ph!ZX~Rx233$@XXD+`qEQ_NwXR5D9|W5W{})6iH?UO7kC$J8x6D`rzjQm zswkz4AOPUhdAihCit&`@d_8x!*ay{3a9W&@xulQCel2=!gN8~K2z{dJH?>6}El#8pZtjvXe&D`uom20mu zeM-sjra5zfeC}TNY{106+=K;?TSSzzu54GIUj`nus;n|G?0Zu)R=uSE@k3UJBcP|c8`U`7!D@8*GO79m1 zd!#P+WARBjbdf>$B)E!gV~s5CW*_Y1)BXF#FW+1MOkh-Y1O@?k(|4yEiLB}qKhSm{ z!QH8HGcYJrF8W4a9}^wJm)f(MtQ+gVSD=fWk9sW4Ei7z%&sz*uRdfoNdcrk36X>f% znsjNmzTtvVdZTbrDrJ5BV}yh+SEm{Ey?bBBX#ooK*`Cxt-v5z%_b$M-GpD2DBNR?R z)KO85yzn@lt2^?cPk{y*|4P&C24j>Z2oiJ(S7bTs-NAhwMqZbB_6C-Ha4i=V1uow! zzu#FTU;n<*zNyX1- z3LA{QG++MwtmX&T$UI#fN$^x4PW-3$M)Sf?GK~@fX zzJnV(&;lx6ah9Z-MmnGOT+>f^;H_%KsF&H|X>{9AbO7)NG? ze!t{h<>!BXNuoXskBrb9YYz5z$?u>dZ?& z45Rh+<9UeGcjv?!B~JYrTppPjx-|K0+jZ+?Lixu^yi@JC|}s794%E8Ods0MQ5@xC4NzUJ0hK zY};ZjOD#?G7aWclSj-)9SUO#bzQDKz3xj%Nf4{3U@$pLniNF;JZ*zuPa(YSsBot)a z&m%>r$fuZJH6?X|3*?$3l(+M+#B*`hb!zcSjt7v1i$dGr9`Fq>TKS%+bu zl-#*R9Zo@E-qUT$KqY_#5K;9eGjq^fD>gzgLAJl`%}})p0ItF=GXoPN9~Bc=;@d6x zjLjs=MquBFjo_y2{4$ZfwovC1eQ}c46KfS+AQ%CP#A~>;dXzs_ql1Ah<|)@srQAh# zjg}_eXM2v8R)C$4(N*5D>&S%}w~-BT2*6=_mtVD8n*WynQCCZ4&e`IF%}2-)gvq>n zNLN;G-gf@+2N2R(HL}W$T1%^uMeUZqc%3`H-B7)G@V6drlBOyuCtcvw5(K>-1l3h{*$eUiW2-`Yxru)~65I|Gy; zb~|swJ03eKs;H#L#kr6CB^Rpowltpy0^wAXU63dZkvw=FX2EdL*Q;&3sXFh-q6kQ7 zg&e=DP?OQzk(BbDs(_r9Ez4ejx6w=YMy@CUj2xq`x=VhRlw`L5NdzGSB;f9D(+~s- z3wDnQiHObA2*~gLEsH?0h$ZId7eCv%SWGz!eruxE8+|kxL_-|W_KWZ1!_KAXyen65 zHIOthoBi)mUBv+8)z`urvXJHWlGfCWhd-L~E7t>2XF_VdT&x-t{$_iBBX^HtNf39} z$0;8?aA56x6ip=_K433cY*qMaVIj6py>{4DQ`1lel3$2Ll zVY1UWJmx{~@}6?$S^mmi!=0)xoz|Q^UFQb{5&+DJ_p24@fE|r;Nk6EkT)B8YT;U%; zL6DQ9gC7;qtEJ_0YRBNFt{MsR+f+Ym787xu^Kr;tD=&R8NxxgU;HLqe3MVM6tEXpU z`(5hwp{TI1JkwE&|8|q-yS2|_Fw}&Y!_f6B*%jlP4Ej2;bmT6AEw392L*!_G#6oqf zLkIdVvRLn&ijw+`F29MupMQ`Wp3u>T3lG;+#l!Oj1mD6VAd<}`)#o&S^SJoc#+?~B z?OX>)pg2%_ab$0u9BM2lc8L83am~T1L1pBkhqwu)Pf3^tZ2Xly_S&`L|Ju!_CHMB0mFRKiCA5E}`CxSd93CLDi)yA*(iF7yDV6Rp zjuZ?6z=u44^G)-~jedzpI`>zxNwIK|2$>ZQc20J6H6>}&*RhW7-q^LWQz3`xI%og0 zA8DP|Nc7oGT=w@nkg}pxk4A91fy8tPRMErztxpMh`xO~LsC8%5@Czidqhr!}vIupK z(Waa&KVAlRq}Ip*gT`FIZsqoBcR6j!1s2VEJM0dl&I?_%+r?Q45dL3S zJk`-zIjb#!VHW?qX_+P6Effi73^g(`hG3SuzgGc<=CP_qrm*YQ`o-C@Ib96*3`LBc zXe{B$d8;&WraI!_wT|kNYdaqiLsy^JJ<)JrnQSB+^prznOO`z&u%KS^n3}!doLNnJ zkvm$9IRjE~cD(d)SMBC~hXdF77Q{Ny?HA}xRmS(fK6P5}?Nt%ooINe?TjdxB^34wb zi7s%RkP5@b^Wg^)x8CiVJaEjQ&qG%lrWqTt7iWPpb#`Qg-{){Wf3jnc+-UE+hr+?5ZzXMSlkKY`+f&RD8>2+VJxC^dyui z{8r8Wa~{I`bDmF_Q!rGV)U#f+KlR65A7Hn{X2GRiA$wAwM-xi?Ja!Kvz}UULy@7F~ zWK?-#yXAJfzWGjpk>SHo;Nfs}bTn)65KHNnBZz02oE@G9pRixaiYqlQgU|Nv7I-zK zl=o&!>WYfG2OTw76*S0=L4dTq5-mpxe_ z4!c`yH_D!TCZjYN%i|MtjNJprpjF1Z`@V9^lPe$Y+V+0Iou)uzna(ud&XEqmo_BvcpdyoTaoNV6IsA|-cMJMN3ksTMHjv1<+5oqq3BDRzRbP4)AxY@P?jUf_)KK+kqzY32 z?h?tnZhNV+zjy_N?IZ_nFp}8-(zAlSpO<7=*3-toRq^!REHSGyAeF~rB(XI>m{3Z{ z5VuKq`p`Z0Ek<9E)I0Er*^VgiJb@5Q=!khm|95#$URGgrY?N3kCIU;`@(Qq{y_b0> z74RAiZj+(QKYn{6CY|*(Uq01*iHB~=_^_M^UU`d@FuB`ianT~Wy2hQ3gQtRSDZ|gC z++d3%Q3<#dKp_gs!LN;Z=p;W@B9Z2EJB z>sNn)BGb`(z94(s3n%GkWNNC7*|3v%FfI+~C4k`fC_XST{T{C{)ipIW9tW4+19Me# zZ5fwaThqX&mw<|ARJt7tn^H9eTz5eHVj^@Hl`PaO> z+S)QKfRbvN{C>f<;xdu#mcTZ(I94W6(4WD<2Avt1*=pb}AKviUk>d4RI%&@EzS|K; zNJ5g({T-;D0F7`PJIg!Xj_a2&*4g53Ms^N=9;>T$(i?K{LL`2FMws`l*zr%~`kvBq zsLb0p{S293J_)+^08ba0j6gv_PnsC^PmzF^_-x}BUf;N{(jww~i~w=0EI-d31{m)* z?}}g;^xNLk$H}g2f1&=^j?UpQKwJ5vwhTw^S3)UZ-WU=KW?;Oar>A63R%BxSZSD_C zhqv^#_fGo~-F$8t_F6E9y3Vz#6%2mnGQ792!$XNtr-rz0eUT-t z@o0FpDJ(M)WfQ&a1BH&A0}if1Q>%{8x8-~_!jKKFk=5#lL48)EegE!igw})bYC~?* zRwVO&r`abz;4e{#D|GvNko9z9W4k5zK(DW96ezK{wkuQNovZvgnq&(*BA)U{P*DQZ zAU1XJ^(}i^gt+v*3SYXX1VJI^){b32N_!3?Bi$j5l0Zv9JLy#$lqOVn$2#DvEn9@- zHpc+wj`nHpL%gicF4b%?X7pN_1d!Q%h@2fC%id2qKeqRRXM!gbp8ROCwa|MEXgS1eshy!=2`=GEIadZI9>>hsHSZ57ydt9njX8awrcdrA zeKyU{vOO{pL@kK6I`KAF!`T44Z zyT|oLWr8$jfOlKQx?+!;fGeia*xyrS6TG@lQSBBnNu2=~Xn#@Kzm%+WkZDtA*m=6N zcyTUC&ZH)>gWVT?2KI$eL$SiqApLSP^QI>l%Z*3AnLQKRN8ks~ws=BJs=W3JBz&4o zY{oZ?sTQ2GLx$Y()q$e?jzZ zyz_=#wp#>@m>7>xO?SmF2v+5JlQ*ys_<(Dm3d>SjT2pMSdRZbWE32!xfHHd2l{E&K ztnHCt4|#9)ZPXw>c2IF)c4k8+hBxcxlL76UJ6Jfn0n8&PNT65KZpHyxG3V(gz;op= zD?G>)@bU3MW{!vmZ=n6zV+QRH$#26jxP}82@pNOObwML-PeQc&_nPnyd4-B-{}$YC z{rp~oiTL|+%_lrbNy(;7OQP|P&W@;!Z5#en%IH-Gwcca6hPUrAFg-k@8lRlZ8>gkq zZaNDGMy^YLV9liEFTT=(`V_|*H$G$6`9?ebRK#S0B7`p448F+C@L-vRehY;=`2hgqnuYXhtm8d}3)l~|kGQEpx=rKK+ z&u`1RnI_M1zj;s*)T3tP2!J6G*-}PXQd?BC3i55NtBWL6%=<~}R&NA1`tR*<3-U#a zJe!mvVI6R(yS?+0MkK$ql%$Kw$2N&Y!-0DjR5OHmHsWO{+k21MANcvAW^((2+S+97 z1)G{Gc3%0dc4~)Zn)1YYU^$FboQ!>a``>uac)9|?x!B2Zens@F2sL1YM(-aAr}x_P z*7S4r2s&1C+5QYjhmODZsW6YuJ!yOMpoyW~)PJfxeh&^C? zhTrs+h??QR`GQpO^J_fVP4P+6Ezx^n9u?sehW8pj;S6rYY(KOYH+*5L@Zw_N!iPfU z@6mh&nM`7$c6!>JYfq}6Pmff=L0tCNPYYi?3qrnRx0L=0I+02e++hZ~oCx4g7kvWdiZ@Vn7G`M=!L(iYyf$ea4HVS>73wAgF7ZB}!r8D=jE9Nt6j8NaOW z_(-I5fA|==OYxyx$Alr!G7eNn>AfUCL;K;58?=JF?k}nwFFzsUGEU%1>AZ7ii90E& z?sXuX0S_;57oe(_6F`Nqv&mPG4+XS<_p!nB`^VBt;08pc z?D5p>6EUDs^O${kl&EZEJbfF}vbcGTaT=`I`G`OUGfuc9iSw} zoB^9`&~}HKuc-#fqh3t6Wi4u^)^6zgo=4HgPRq33HIRrR;^-yl2LiET>AgWTY6^A; z;Cq-`@owCCP+_{qc!t6(OLA-Ejy5&V)8OGXlL1cA%AMm<3zt*FJM}^vCslsAD18h8%Cn6cX+R#Jx)|l6&#$OCvD@+ zR3D!j3qBZoP;+VsV*Eu)WE>4gb|j{dcJ z6hiJ3btG)v2r}Ak{ANjdV?|N}jCx?g3)3g1ps*iX<&yw91b`tQ5bG6FF+~SPnzY;h zm^YsL%SDTndb{fz^X z2V#z_TW!h4U{WiHQ8)2+KWaXl$jBCfFmo|Ua*Fcu0&3d@<-B#8KKb962ll1|^aGv+ zqrQK*`&~=v4a{67(8R27DlfXG=!Gh!)7;FY2?;*q5BFc^Ks@ie%iU-82@v8=JmY?A z1dNo?$t^E&X}TOhvFE%;K-U?1^%t<{KeDWfIHy`cgB0aZwRI#1i18Q9rNI4MgMS%_}m_Av3t`ft_skaV5{ zb~dON^3d?+d+vBefSP{*HQjm84;*Quj>my5=0#exF&(+^U;|(kN&W5lAk&l}XJO$h zkb_&#{4X|VZ$BjvvsK4l;#yzokND2f!>Lqo75g z7V^i6dC2}WU_%l+=|0a~1>5zmy9nMJyKhWP1iyouc1@mJX&VOw$gL)VdbUtoi9QY* zyp4Php7UY;WMh46WW(!rUP7Ak!v(kLYQSgrWW+bI@z@31(#R0BRk9^M279BS-wrF@GfFdfkuN<`dfLY!> zJ|?_HBL5#EI~@rvqu0{Peduf!=+sHG-dJ)jQ}?Y~my~(JArLfp0Nnhbb?Du>$(3x- zbveAjHk|Kj0P|7#)sftt0veM%SUj`D0GMCR0w!Ru#l|ZlRB>=)UWnB}e)IWE#{FUK z^~02MHh_X-<1WivPa;6dTIks>HXihiZ-AN>*tzPwJ#l~~8)3DZMdHNvDxYOM0#=a} zC=M7`6<`oo=E&X30T*N8SB)kG6xJ@&89NPBIU>|a%DN!OwkfPC#L^QI5fPBw_F&2H zI66EM78W*r!iL#Im@EIWbSxpMdV;A4Yg_*ldfrS2Fy~Lxb{oQz)6RM~t_2Ts6DI~B z{{v?l0VC<=x+}vjuSn=8MHb7NN&Sjh%_qsAfJSeM+*;>3-k7fg|eFoiwZ?dH?dmi(1iazw(YNU(jg#;vgiDwQ9{hc<|1O#gUt__<+ zC775pXyk;B3_d0E1&s9!d?G9Elm!e0Fk=%D?NSk32eKz%A1@n!roTX?fyF3|myb`{ zt?dlGsiz&XB-)zy(n?2G_Tu9t0jg^aS3$yHro<{PDifke?}CSx{`? zF&2=8!tbcvJ#F&)X~md~R+x!MNxMy9muV1DH7ex2z5U=|EpUYz2*i@0GG8Km6#M4c ze_yKByU2Jw@sI?NmBzv@foDJb0p0pI@x#;tkkDfuWUedTWuU5IgZTbDl6hQngVDOy z=<=$H!n*R-t^Lu%AC1)E#8ppb%RnQ@pEWhVE4bjlz2!^QH_ox=AZu;~mO~s@B0+Ta z|L4+ada9^Aw;BdMnLn21pw{B$(9Y2m&w@T-Z#6JAO{}+=1rBlZ`1PN^+O9wQ%J}0h zaBlA2y&eP3$hAxQO{H6StvoI|8lY58o{ACs+L6MB27^p9*vsJXc1Ih&RAz z*|>c}&<-a<0IxI@&;p%##dURk_JWL|pbP3b%N^{RZ^(dy_tl(-Kj-@`s}7IY9g#>@ zb?OlG6!E1BJM1>!2rSt4=H~Irc_c&x1hI+lt=^^o-2StEG zF>VqK=v)fpq}0yQp)}{r3C{-H;Zo@Lcjq$~2O6+G#Y>kVxB(k?u|4bSPJ5hrytm^v z`0QQg9bGo9c4VE6p@+$`DC)!A>}9j1JK2fdv#V=S{^kLP`xV@}L74(Gb%_KJHNPidh zJTvnE(TiDz)8l4KDqwqK62CNom@gKxXBV=+`~3J~^x|amtptPPb$2a4!^!ZN{<T?wa9_1yJ`HU;_)O^b-8$JCs&$eDz82G0r#2UR zxx~?wy5?Ss$X?^Rvc{9&M?N8Lumc|RAR9lw)KNz+9u5x9UCG+L#;0GcUZ%E4&v(O4 z&{lDhg|gUg*o7VM>pIH0(b<;0#%v&tW3%y5P)x^WMZjqaOnq*^6y{piy?u7d6P!Gg zKF@H{yJLn;zd+ANM@R8z{K_B4H?E_X2$qo*7k>xAobsTWmXE>+OOCc?vjcV5(5L_g z$^G5;z`;`K3og&@^*K-zX+9a^2)Fp#NUdpVx=MPTgh7m*smx{03a-v+-1Oa-S01uq z{;8zAS#p8&iCS-#R7q8lSmOZi$9Y)O1`N9z!o|ks>UIn+-pVDElJjx$Fs1Ggm=vZD}cs(SgIUTy?IidI;wWmpVNqo$;-oUOhvEVB*%+DDR); zCgcdhMMvyj8i1Wh;I^YfMA2cx>W^A~f=p0@pW$kTf%kz41h6(Q3D1M8&MeRd`>zzVHz?ic(x zqu+N&ZMHvv!FjUEbKKkfbl>;lq)Ni|q9bFnCb7F7Kn&}_-@kvqlOrqvbL)dT3qXg2tD*Np^yPPzxp z=mS+ziW#omDSb{gx{{10LxT15lTRMk8>H5rn7^29ox zL9T7+f_=BLi0>QJihzT+1ECD&Lkc7sD$|B0-!Nmh)~eo3ET|y@Q0ICc;28`r)0l4J z1^rpxyM|ASJx?~5Ivo+{PT_)D_qH<)krT-?#iLN}JC4%kP*xj~-o94f_)X+ycHmj6 z@5OHLlY32P#T>22f2rm{G{PMGe)U&XmD9l3Tn zHxOOA`exE0bCY|$&x3T%S`x6IC${V6=7;H)zh=KZ41nUADw2|ur7?+AK0&Q^(+Ug_ zbdP6K`TVKEysEU3Y3%|^V(0aq9gkZesvyP0h?rcn$gvi9rWe`h1K3GJ5<`#Ny5OIc*VfX4Pv;9IalH zYh?^ke-QykloXVuFt6>>Q~}6zE!6j5MNkMBumI)!J1v^K`6#VqSW;h-UW4T@m~h;@ z=?KhhFftX$Ei(~yGV#tp=^p6WcRP?=2d>QorN(cL4e1|z@^s6 z$q93O=X5t0RH}%SipI0`ph8+TMPq_)~la&j~smUR(^WiBuv9AXDpPsdF6=uxO zjBFibW)gHGoFG9>wsXymOyEK_7K*_yK$?*`!wnF9{Pgl^c6;O$3L z$FcAS_UPhd!jh7x+k{+tP61H!BxK8UYY@B-y*b8RT7I^^tReRY3?*=7y~THaa%Mq2Bn3N8Sk5^fQmKk%^9uZtcP^%#N7P)}PK{EcEb)UrRP> z;&kBJamVr=Sb*bzkwy1X^LihUNZp!G`#{J5o92;&1+~l>)ynAj{KVcQLL(3{DCXIB zR4x{{Vs9GMhCQBjsWpgbQi2pp)dtCXcc2hCn}TVD`b7Hx^NGKD4~|JvfdQ z@1?&*B(M8ewG9=R5l(UqS*sU$I!a1=9I*4=oHhkn7P9r%`$cxB=H;UZh9*e-fQm{K z1QU3SpI%Q~Te8~yncK`@_HGQa$xL%$vKrmStPuBzVXF0@W=HaD8`xpz$UhrH&QCO8 z$A7?cRTHV59o0?8&CgCbG;j#mtT%icGF8c!cx_N{I|~Y1^?{n7Om^?RK2OxBbDOK) z-rJG%0L#$PkskxLLilERCRjaA%HIBd(lD7zIQO`|O&egQTzKsKQLV8o3lGE%?090@ z>}@2HzF`dn{LF4HgY-orRiY_U+puixC9l_k+PHb(URbz=ERz%nDLl?%dx45*8L#>y5q~-uH%+Jp~vRx5gFF z-`)sjH5+?Q6(@bZP!}gna`SyEtP<}H+qeGnNe=yTRh$QMW>@Itj6+JnqXFh5_1&4IU0){yr>hiA3?Lu_ zijpy=P#^sFIRQJZ!vkpW_ik_F`ue!jXD>mdm$&x=$;0-a`rd_9)(g48AwM?{*k0h1 z2E~`g8kda)pw7l1*ltpcntN)~=u?o>7u`iiCMSoc>g?um;PH6{$6Vd#WvWt9_8NyZ zrcmbiNDFH4r_@b4d!vbad%3`Qr&TZYYDq_u-dFs=p6vNZYTEJK{0un}YObcDo);U- zw{7<@$<{5WuWuQy5ecO64;_}^tT&%OTq_#3GvU^^c=pRJ_}FpBS%*o>Sl_PJz|nDY zs(J1iH zDqy{FJ3&9>cSB|P&YfV(=1;~pKETK|U-12x>b^55s%P!90YSha3@8jqkRV7Lau5Y| z$Rau*NFH($P_lq9D3Xz^2$CcRMY4dB89*c>Q6wWdND>r$oByr%!*1QG-L2gZd#5O7 z>YP4(PIo{36B0PKMbyq4CL}ZHa&LnO7b=$Eu)N!)ohy2EG_++DYOw9vMs_+7t{XNr)2+vIUw{2Nl!%onNQF& zQ8T`k%K@N6V%1~(rL_gVrM&a`xPl} zQ8k`&%Vz%1qsfnJL#BWC_GR@Iq?$#E!9{XWfY;Fz`ZXpbeOFJ&YvZX<+(1w5+qY}O z^^bQ2hD}@>Ni`77y%O^s`>YBNOFj8hOA29;o8OM60?-yHcJ^9X^K5gd(pFEPc#Z_< zYav8{o0S@>MU@-BR^!$#E6W*qxxFbFA=vnrI!*A1fBw8i?W3jDvo*`Rzou~8P*1^0 z3#utdgp{N-RL~169NR^~KoZk`cQ!Y;B(CM?>lB*?L7gO7VyY!2mQF;V0+DKZpf4ga3K8J&{`U z?jG z(X%zp)ACi9$Fl*r$@|F3(^KX(Y(*cA!m~nWS(rxH5`^DskH!{!$daKYx2)y(SAV3i zU}nxaMnqsrThPFu`Rkhi12DQC{A;@I8YE>PdUmcHALWIkt8_gAklkY(_{d!&dJ(W$DwTg zUZiPY4Ix4YxDuteO@?I)OE>DiSO&-WkzgGcK0&j5`&*9YWM@)lsLY z_fjr3Z|BRyExXeoD>Jl+|2^Zlgul+@ayaT!W^jN}OJGL3anJ?MR^440CIF&Ks)bi( z6H?8S>12H_5xLMoI_acEioO$cFWMO?GiHDrvb3PV?@`H9TKqRkCW@I+bpaJ!O?V2#x z|0N?hSz-WYaka%h!Bw3F`KKArGL8s->YTJiq>}IY`m4RVn=i;fbK=T?p~`ApaPjZp zwvP((%a1cf6Kh~4n<<*8NA!e5k5qI7ZB@p1S{1|YZ3NG% z+{>8?@(WiOpq;I_o~}&`=AN_IJo39czBR-2*HkDugQ|~W(apv!xOki~a$K@vWcI@w z!JeG_*^E?amZz>0dzTl^g{j_@Hj$s*2wU0LWsrPkA@X`l#eMc|&QyMPs#x&uF==a@ zw+_HlD4yJWD^m8^@1vN>AyTJ;&7w;Wsf?yAZF>A!x6f1Weeuw5rkL#_q)W&C8v1h` z`6yHLY~QXG>GSz#-HvaK739Y%YueqNt@@VUEgmc0!`RoF#{`P@I3}-V5`&vSj+97o zov*_1e4#K!E4^0Qjyvy8fWSvDLVf-PuWiAeea4qp>fV>DNc;IVjWdLb?8zK^-3hJY zJ>F3>b<}ffrYIhGbJQ`@FBa^6H^xD;#1P|@G=I<-Tl!nTjuPOF6dhpA!sm$>q`UY> z2G4#Q8$0lG{W1LGY}VDWlwN7cQyQ!SsRKfzXWde2$h|=y5;d{ z;A|;>g*5HK0FTv*#snue!KV1ZC?-p+$IonwLkLdIQV5h6)y=dWRd!l}f)gt=&hkr! zrpx`<1q#QF&?*&r9*<6~TL*C(&rfl2V#m+XBde5tcQ^HWCS9*D+(=xhoY2$H5^duH zbHXPx@lIcF`FL!#=>}Vj>5#{WwlXEJ4b@#v$17WN^>9`8s-Go1+MA;cu)U6X&7djG zjnc5pSOoZv>nEdR4#!66B=`;v9k^(6xMQ3{Ck*aajY#g=x`(!T982Af>Eh)4p86{) z%Ey>t?fXG1i`GG^?C9~ZfQ_6`Qpmmd5Y-;sQwSC{aP}<`hsPP0ID@ z%y!Y3qbsFvU(2{=hIUFHVSOa@wwtR)?s&mc(3ZO92{CscC`F0zS9>TQuTV95Cg13w z5_qkP932|kH8cG2VyJtSl@8#H`c7zn368{B@|nl)=KM441^i24EE|%+SGU~_lP2znfrVYB*z}y*f7fePWD0ZNA*^ zk+NSUH6=hp+Zsfl8G2dc|32$}(Ci=mPc3FgWjt0sM`p6ag({eWpR4|LS*vAx>kAL$ zofaSIc0Q4>RSL}+{FI<15N=dvEQQoJp8L}n`!i>A)S1g9+U9Q~sa4zcE0AP|TOneY zqA#WA0n-Y!N z&V7fK!>lX(4B=RH&BF8726EC9#r_dgsC2s|;UQ?095uF6Mm!5AoQu&m2A`mou z>Gt5bt8S-$Dcrh5KfYf=iA-^wi;QEKCk~G_=gW@IU`ldAnZGXl3&URxUt&cSn$;_*a)?^+t7*Jl37-HkuS3MjKg+Ql4CczZ58U<>F~k z5cgyCQ5P)|sTm6AVpIUa&WyV4app-NkypA%V~p?=*AR*q3A?AxLQAaF0D~EJ*W9{r z3M4-7k55%Kp?%9~-ZDE|I=nSP@#P6KN*VX7OoQwPI~VIY4l+hQH$?RVZ|!^l1(F19B346^f#Dvx#EFd;;e<|sE~n&nED=DTgCJh(>%z!8 zt>=-Va&m1oDh9;p>n$LneutN{nS~Z9nTf&3U4AP3(iKZd3L4JNxYb;5+-7WJxAWhba|?uJF) zEfGk( zyy7eL;cY?!j0L5fpGF-9rL1a=&|J{2ypwY!D8lyJ$Yab5MW>R+U_|V5{N(spY+9Og zndl=vz+nUPO`%KO!PTN+W57DWK%`D_CbY%I6xByG$@bzQyAjzb+#sA}Ou@c_=q>3b z-sLQGPpQ+hxoQK$q|3y9T7GqLQbdrMy2!8|92^|)Rldj}>+m!bF?>t8O|R0kn9EEs z+sGn{cnx_1UX2gQwd>4v{-v=>L@aT|gXav(w^n6FzUeqGhCXRB?=q)QX$o>eRER)R z2bpar{Ib)j?C_IgR~HpU?bjNoY^!ObPaTYtkJ>|cyNh47Vw-$zsT2uf^0HRG)Z)HG zkJ~O#c-R***gL#zT^q_FkQG@2Ma22w=@|<`Vxs+$5q)8~pu1G4X3en(` zUfp*&xoE@uOD8uYj}4pgqHiR@sO4+>!4!|R{`nW-FBYW={T6i$HMF_E8Q;6N>Q>7} zt;HD=(mJz+G16KLy7n9Hy#j4@JBBX%5(7sFldjP+oADf9KQWHnEDXc0EVmAw`>LFG zx$X$>SK~L5qNyBerrQE;3iFs}{oxJr%Odnrt-awHTULT(r=ZIsKhdkt&d(?KrE_0~ zmAbIiys9?7--nJCHrP}JTvEa@#R@5f52IB&IjviC*3 zj>&Lxj@)s{RW6}YL^QPTZY(HlHpbf@Z@Nv$U^7*`%jdrq*jMTrq+7pO+ECtqzP6Pb;EXm!;%L`sot_ofZjv>a^iXD#o^uH%7V;ZfRZ$S9h+|mPn@~S+F1jI9NKZHUVp15z_q5i281HZrB-2 zXy0;_zlUnEL!U!3kE{r-yXQ?Jxa*y`9f|Dd8X9*g(dr?h-qRn2-u*49brO075sK zJANSuIRJ+SSv{c2+n_OS)hb&KNn=2rw72Z_`E{dMc5XjpcZF2qm)6p-V6?;(p~~t^y7Lf>f@5P+7=x zZBe`#EeYD5YlAu7X})pgPqQaNU0Q#Ub|p)n9^kIeY8Rfj7P(;ql8B?(U{|f=wPaM{ zx?b&OjZc+Gm|WOjF+!C`l<9Zkv}h!fjBvfvg9zP~@23!K=$^Ry`}@-EBX*Yijrdl` zvWk#Kj}ME6{WJTlz&mdgdpQ|=)~mW+zodxN#0?iwhfo(q%Vp+2qLEf>ZQoNnVn314 zqAb^FQI@xQFXRHY`@V|xl9rn)mJP39$|Au1%sR@!U(oBgpKH{Ic3M0eSi;ixD&N02 zJ)?^G&FNm;N}n`2Kr11z)9kKfQ^dic(0U|1#hP1wr?H8aBI?L`dV5)n$(Q9;Jir&V zuXd6sk5`A}Kr0r?OKrl@)9$Yuzi*Mtxt+eil(Ru&0lfin!et`lDC>#ov?rexE|Q6Y zSxZYQVwB7pm2DJR;SSIOdH^Eiizm_QF3saXBWZX&5!$4uDn+Ts#k3sfLOXcqq87-p2*xwoXgW=uiR_JJ-@ViK~~%2sE&P z!=RetA=SC)nE3#|T1XJY2-g^2aNR)f(P`U2dOKphkN5I2`hMNV>wCL&+{ajz)U z%k94$c@oYrfw&+P{-I}`YfpO|9%8?U5eNb0TEw8i_U7Q-Km@+ygms`S=%TMufg2Lk zs(<0CMHF`wKBLjy<|R4tGor64qj$B&QdAEEnqPID{ru`IK)X}r9k`A*Swezrimb5l zuRj%i%@E{jK_Q!d__y&KA}$z(4;{$8hWlcsNM?t`t%?BL7$*rwEqvbF1*U(Gx5!Dv zrZBQCAK(P%WDyai{}sd0L8|Q2NlV^;N^{8eTN@FU1EqF+vnsfWg!1x99oOUE!B0Z{ zOrXjX#Q<(f!h=cI7O0swtWP>&y-3nJ2uEYd>>C2ipwr4H@5myIiwyS@3HhIF_?SY@ z8FNs|V~nEx2}O3&qG?<1UX&d)d{*T=!*qh$r^NkZp`S^+Woq{@!xf+t;MkS&T>mm1 z@gH0Cki3o}0<&CYtl;Jucw>1~s$LUeXEaL7SfG?Rbcw%$|(Qq~g+g+{v*WN#A zdkY`fP|X5BI*mEV2_01BI66(YW9s?l474KAU9fYuU25({n?$b@O`RJWE*-ZaO9kMu z?Wpj{H@-vpKiHoQ2k`&Q^`4`P_+Yym_DcM-_REo?q0ZrA_v+Uc-?l%`YrrUN+lM%l zq#PlWdll=k;k@Q4Z=07r;(4u* z_Gbbw)8w?p3(c+79^TP3zM<`^(HiknwoG8v!$*+8!EyWRkaS2pOu?WF#c=m?aVBA5 z<{(Tvt1u9P;jsam>Z^QZ;0PUeIK!(XI!SU&s7>xA}3Ub~Go`_5H+!>)j z>ZAQro6RQ6Hqzg%gfr+0y?ZC;yNYoseD?Ls*qCpHJJpugw|N)c?lcI%Kds6=^FZ$Y z&^7A!_Kkl&%I`OdJjZ1Ay%L8t_3CjDh^)lR2*Yq!MCMV!!pK$}vhbd;H$Kk(srk>Mt9k#+!ZY=sg?}4I$6+L zNd|9;IAbg#tPn=^X5@2pWlU+pz9nVfWpAn%u+9_|o@ z!SsW@l20wf^|6}r0=WYj@yp9{_40$GFt{IEAKd(7Y zbv!5jSx>k=y(B*yqJwUH4hrGZWI7x*)|UwPTi?e_8e4@co!kHd@70=4LuQDF$Vzgg zp{j+$dIknYy1Fy_r|Bq+F`O|Fl2|_V4`QD-ymgtGnTGAE6hyc2i`&I;BAe0Qg!MLJ z<*NiLkQ^%#nue8b4?R79xoJ99cEUt`{5Oen7I=kTvx<8*@d-RX$mw8OS57d-1A%sh63cRy_=VroHf(xdSH&mz86b%YhU{G!K6_F~Gt| z(T=dZv9`3ollfAtl2oz~b9hC0B~{H^ELPU}UFZBwY9QmiI@jQCzrwuGo$|?h-X*-1 zZh2K6Zs5``vj|p?+OJYyR%BP@l$4+ycpkaLRw2lFnwpI|NUqJ~I=mxCevjjV&w4fQ zL8ni0l~pFXAuwbwVt3^SJeQMi=u~szpi`juV{DBtzXv6p6@bq8H(s0n>`3IvsQ!1N ztrl!h|KHpOjSTt7LZrgRJQ?mF(t Fe*r}Fq&@%u literal 0 HcmV?d00001 diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index d2c148bf64..a97860f292 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -23,7 +23,8 @@ If you are looking for information on grants and beta-release Nym apps, check ou * [Network requesters](./nodes/network-requester-setup.md) * [Validators](./nodes/validator-setup.md) -**Troubleshooting and FAQ** +**Maintenance, troubleshooting and FAQ** +* [Maintenance](./nodes/maintenance.md) * [Troubleshooting](./nodes/troubleshooting.md) * [FAQ](./faq.md) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index f4ee68e242..591cd3d1a9 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -1 +1,253 @@ -# Gateway +# Gateways + +> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. + +> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. + +## Current version +``` + +``` + +## Preliminary steps + +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your gateway. + + +## Gateway setup +Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-gateway` binary, you can set up your gateway with the instructions below. + +To begin, move to `/taget/release` directory from which you run the node commands: + +``` +cd target/release +``` + +### Viewing command help +You can check that your binaries are properly compiled with: + +``` +./nym-gateway --help +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +You can also check the various arguments required for individual commands with: + +``` +./nym-gateway --help +``` + +### Initialising your gateway +To check available configuration options use: + +``` + ./nym-gateway init --help +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +The following command returns a gateway on your current IP with the `id` of `supergateway`: + +``` +./nym-gateway init --id supergateway --host $(curl ifconfig.me) --wallet-address n1eufxdlgt0puwrwptgjfqne8pj4nhy2u5ft62uq +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +The `$(curl ifconfig.me)` command above returns your IP automatically using an external service. Alternatively, you can enter your IP manually if you wish. If you do this, remember to enter your IP **without** any port information. + +### Bonding your gateway +#### Via the Desktop wallet +You can bond your gateway via the Desktop wallet. + +1. Open your wallet, and head to the `Bonding` page, then select the node type `Gateway` and input your node details (Location format is , ). Press `Next` + +2. Enter the `Amount`, `Operating cost` and press `Next`. + +3. You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it. + +``` +./nym-mixnode sign --id --contract-msg +``` + +It will look something like this: + +~~~admonish example collapsible=true title="Console output" +``` +./nym-gateway sign --id upgrade_test --contract-msg 2Mf8xYytgEeyJke9LA7TjhHoGQWNBEfgHZtTyy2krFJfGHSiqy7FLgTnauSkQepCZTqKN5Yfi34JQCuog9k6FGA2EjsdpNGAWHZiuUGDipyJ6UksNKRxnFKhYW7ri4MRduyZwbR98y5fQMLAwHne1Tjm9cXYCn8McfigNt77WAYwBk5bRRKmC34BJMmWcAxphcLES2v9RdSR68tkHSpy2C8STfdmAQs3tZg8bJS5Qa8pQdqx14TnfQAPLk3QYCynfUJvgcQTrg29aqCasceGRpKdQ3Tbn81MLXAGAs7JLBbiMEAhCezAr2kEN8kET1q54zXtKz6znTPgeTZoSbP8rzf4k2JKHZYWrHYF9JriXepuZTnyxAKAxvGFPBk8Z6KAQi33NRQkwd7MPyttatHna6kG9x7knffV6ebGzgRBf7NV27LurH8x4L1uUXwm1v1UYCA1WSBQ9Pp2JW69k5v5v7G9gBy8RUcZnMbeL26Qqb8WkuGcmuHhaFfoqSfV7PRHPpPT4M8uRqUyR4bjUtSJJM1yh6QSeZk9BEazzoJqPeYeGoiFDZ3LMj2jesbJweQR4caaYuRczK92UGSSqu9zBKmE45a + + + _ __ _ _ _ __ ___ + | '_ \| | | | '_ \ _ \ + | | | | |_| | | | | | | + |_| |_|\__, |_| |_| |_| + |___/ + + (nym-gateway - version {{platform_release_version}}) + + +>>> attempting to sign 2Mf8xYytgEeyJke9LA7TjhHoGQWNBEfgHZtTyy2krFJfGHSiqy7FLgTnauSkQepCZTqKN5Yfi34JQCuog9k6FGA2EjsdpNGAWHZiuUGDipyJ6UksNKRxnFKhYW7ri4MRduyZwbR98y5fQMLAwHne1Tjm9cXYCn8McfigNt77WAYwBk5bRRKmC34BJMmWcAxphcLES2v9RdSR68tkHSpy2C8STfdmAQs3tZg8bJS5Qa8pQdqx14TnfQAPLk3QYCynfUJvgcQTrg29aqCasceGRpKdQ3Tbn81MLXAGAs7JLBbiMEAhCezAr2kEN8kET1q54zXtKz6znTPgeTZoSbP8rzf4k2JKHZYWrHYF9JriXepuZTnyxAKAxvGFPBk8Z6KAQi33NRQkwd7MPyttatHna6kG9x7knffV6ebGzgRBf7NV27LurH8x4L1uUXwm1v1UYCA1WSBQ9Pp2JW69k5v5v7G9gBy8RUcZnMbeL26Qqb8WkuGcmuHhaFfoqSfV7PRHPpPT4M8uRqUyR4bjUtSJJM1yh6QSeZk9BEazzoJqPeYeGoiFDZ3LMj2jesbJweQR4caaYuRczK92UGSSqu9zBKmE45a +>>> decoding the message... +>>> message to sign: {"nonce":0,"algorithm":"ed25519","message_type":"gateway-bonding","content":{"sender":"n1ewmme88q22l8syvgshqma02jv0vqrug9zq9dy8","proxy":null,"funds":[{"denom":"unym","amount":"100000000"}],"data":{"gateway":{"host":"62.240.134.189","mix_port":1789,"clients_port":9000,"location":"62.240.134.189","sphinx_key":"FKbuN7mPdoCG9jA3CkAfXxC5X4rHhqeMVtmfRtJ3cFZd","identity_key":"3RoAhR8gEdfBETMjm2vbMFzKddxXDdE9ygBAnJHWqSzD","version":"1.1.13"}}}} +``` +~~~ + +* Copy the resulting signature: + +``` +>>> The base58-encoded signature is: +2SPDjLjX4b6XEtkgG7yD8Znsb1xycL1edFvRK4JcVnPsM9k6HXEUUeVS6rswRiYxoj1bMgiRKyPDwiksiuyxu8Xi +``` + +* And paste it into the wallet nodal, press `Next` and confirm the transaction. + +![Paste Signature](../images/wallet-screenshots/wallet-gateway-sign.png) + +* Your gateway is now bonded. + +> You are asked to `sign` a transaction on bonding so that the mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. + +#### Via the CLI (power users) +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. + +### Running your gateway +The `run` command starts the gateway: + +``` +./nym-gateway run --id +``` + +### Upgrading your gateway +Upgrading your node is a two-step process: +* Updating the binary and `config.toml` on your VPS +* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. + +>These instructions are specifically regarding upgrading your gateway binary from one version to another. If you want to change node information such as the listening port, you can do this by clicking the `node settings` tab in the `Bonding` page of the wallet. + +#### Step 1: Upgrading your binary +Follow these steps to upgrade your binary and update its config file: +* pause your gateway process. +* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. +* restart your gateway process with the new binary. + +> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. + +#### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). + +You can either do this graphically via the Desktop Wallet, or the CLI. + +#### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +![Bonding page](../images/wallet-screenshots/bonding.png) + +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +![Node Settings Page](../images/wallet-screenshots/node_settings.png) + +#### Updating node information via the CLI +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. + +## VPS Setup and Automation +### Configure your firewall +Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: + +``` +# check if you have ufw installed +ufw version +# if it is not installed, install with +sudo apt install ufw -y +# enable ufw +sudo ufw enable +# check the status of the firewall +sudo ufw status +``` + +Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: + +``` +sudo ufw allow 1789,22,9000/tcp +# check the status of the firewall +sudo ufw status +``` + +For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. + +### Automating your gateway with systemd +Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: + +```ini +[Unit] +Description=Nym Gateway ({{platform_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User=nym +LimitNOFILE=65536 +ExecStart=/home/nym/nym-gateway run --id supergateway +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. + +Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. + +If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` + + +Then run: + +``` +systemctl enable nym-gateway.service +``` + +Start your node: + +``` +service nym-gateway start +``` + +This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. + +You can also do `service nym-gateway stop` or `service nym-gateway restart`. + +Note: if you make any changes to your systemd script after you've enabled it, you will need to run: + +``` +systemctl daemon-reload +``` + +This lets your operating system know it's ok to reload the service configuration. + +## Gateway related Validator API endpoints +Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. + +## Ports +All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. + +### Gateway port reference +| Default port | Use | +|--------------|---------------------------| +| 1789 | Listen for Mixnet traffic | +| 9000 | Listen for Client traffic | diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md new file mode 100644 index 0000000000..b2fe722d0a --- /dev/null +++ b/documentation/operators/src/nodes/maintenance.md @@ -0,0 +1,357 @@ +# Maintenance + + + + + +### Upgrading your mix node + +Upgrading your node is a two-step process: +* Updating the binary and `~/.nym/mixnodes//config.toml` on your VPS +* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. + +#### Step 1: Upgrading your binary +Follow these steps to upgrade your mix node binary and update its config file: +* pause your mix node process. +* replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. +* restart your mix node process with the new binary. + +#### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). + +You can either do this graphically via the Desktop Wallet, or the CLI. + +#### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +\ +![Bonding page](../images/wallet-screenshots/bonding.png) + +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +\ +![Node Settings Page](../images/wallet-screenshots/node_settings.png) + +#### Updating node information via the CLI +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. + +--- + +## VPS Setup and Automation +### Configure your firewall +The following commands will allow you to set up a firewall using `ufw`. + +``` +# check if you have ufw installed +ufw version + +# if it is not installed, install with +sudo apt install ufw -y + +# enable ufw +sudo ufw enable + +# check the status of the firewall +sudo ufw status +``` + +Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: + +``` +sudo ufw allow 1789,1790,8000,22/tcp + +# check the status of the firewall +sudo ufw status +``` + +For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. + +### Automating your mix node with tmux and systemd + +It's useful to have the mix node automatically start at system boot time. + +#### tmux + +One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated. + +Use the following command to get `tmux`. + +Platform|Install Command +---|--- +Arch Linux|`pacman -S tmux` +Debian or Ubuntu|`apt install tmux` +Fedora|`dnf install tmux` +RHEL or CentOS|`yum install tmux` +macOS (using Homebrew|`brew install tmux` +macOS (using MacPorts)|`port install tmux` +openSUSE|`zypper install tmux` + +In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control). + +**Running tmux** + +No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let the mixnode run on its own on the VPS. + +* Pause your mixnode +* Start tmux with the command +``` +tmux +``` +* The terminal should stay in the same directory, just the layout changed into tmux default layout. +* Start the mixnode again with a command: +``` +./nym-mixnode run --id +``` +* Now, without closing the tmux window, you can close the whole terminal and the mixnode (and any other process running in tmux) will stay active. +* Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session: +``` +tmux attach session +``` +* To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?` + +#### systemd + +Here's a systemd service file to do that: + +```ini +[Unit] +Description=Nym Mixnode ({{mix_node_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User= +LimitNOFILE=65536 +ExecStart=/home///nym-mixnode run --id +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. + +Change the `` in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `` so it is the user you are running as. + +If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` + +Then run: + +``` +systemctl enable nym-mixnode.service +``` + +Start your node: + +``` +service nym-mixnode start +``` + +This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. + +You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. + +Note: if you make any changes to your systemd script after you've enabled it, you will need to run: + +``` +systemctl daemon-reload +``` + +This lets your operating system know it's ok to reload the service configuration. + +#### Setting the ulimit + +Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. + +`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes. + +If you see errors such as: + +``` +Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } +``` + +This means that the operating system is preventing network connections from being made. + +##### Set the ulimit via `systemd` service file + +Query the `ulimit` of your mix node with: + +``` +grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits +``` + +You'll get back the hard and soft limits, which looks something like this: + +``` +Max open files 65536 65536 files +``` + +If your output is **the same as above**, your node will not encounter any `ulimit` related issues. + +However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: + +``` +LimitNOFILE=65536 +``` + +Reload the daemon: + +``` +systemctl daemon-reload +``` + +or execute this as root for system-wide setting of `ulimit`: + +``` +echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf +``` + +Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. + +##### Set the ulimit on `non-systemd` based distributions + +In case you chose tmux option for mixnode automatization, see your `ulimit` list by running: + +``` +ulimit -a + +# watch for the output line -n +-n: file descriptors 1024 +``` + +You can change it either by running a command: + +``` +ulimit -u -n 4096 +``` + +or editing `etc/security/conf` and add the following lines: + +``` +# Example hard limit for max opened files +username hard nofile 4096 + +# Example soft limit for max opened files +username soft nofile 4096 +``` + +Then reboot your server and restart your mixnode. + + + + + +#### Step 1: Upgrading your binary +Follow these steps to upgrade your binary and update its config file: +* pause your gateway process. +* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. +* restart your gateway process with the new binary. + +> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. + +#### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). + +You can either do this graphically via the Desktop Wallet, or the CLI. + +#### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +![Bonding page](../images/wallet-screenshots/bonding.png) + +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +![Node Settings Page](../images/wallet-screenshots/node_settings.png) + +#### Updating node information via the CLI +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. + +--- + +## VPS Setup and Automation +### Configure your firewall +Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: + +``` +# check if you have ufw installed +ufw version +# if it is not installed, install with +sudo apt install ufw -y +# enable ufw +sudo ufw enable +# check the status of the firewall +sudo ufw status +``` + +Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: + +``` +sudo ufw allow 1789,22,9000/tcp +# check the status of the firewall +sudo ufw status +``` + +For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. + +### Automating your gateway with systemd +Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: + +```ini +[Unit] +Description=Nym Gateway ({{platform_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User=nym +LimitNOFILE=65536 +ExecStart=/home/nym/nym-gateway run --id supergateway +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. + +Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. + +If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` + + +Then run: + +``` +systemctl enable nym-gateway.service +``` + +Start your node: + +``` +service nym-gateway start +``` + +This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. + +You can also do `service nym-gateway stop` or `service nym-gateway restart`. + +Note: if you make any changes to your systemd script after you've enabled it, you will need to run: + +``` +systemctl daemon-reload +``` + +This lets your operating system know it's ok to reload the service configuration. + +## Gateway related Validator API endpoints +Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 723984ff39..68f6bf9090 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -28,42 +28,11 @@ The `nym-mixnode` binary is currently one point version ahead of the rest of the ## Preliminary steps -There are a couple of steps that need completing before starting to set up your mix node: - -- preparing your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) -- requisitioning a VPS (Virtual Private Server) - -### Wallet preparation - -#### Mainnet - -Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). - -If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. - -`NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several [exchanges](https://www.coingecko.com/en/coins/nym#markets). - -> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. - -#### Sandbox testnet - -Make sure to download a wallet and create an account as outlined above. Then head to our [token faucet](https://faucet.nymtech.net/) and get some tokens to use to bond it. - -### VPS Hardware Specs - -You will need to rent a VPS to run your mix node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol). - -For the moment, we haven't put a great amount of effort into optimizing concurrency to increase throughput, so don't bother provisioning a beastly server with multiple cores. This will change when we get a chance to start doing performance optimizations in a more serious way. Sphinx packet decryption is CPU-bound, so once we optimize, more fast cores will be better. - -For now, see the below rough specs: - -- Processors: 2 cores are fine. Get the fastest CPUs you can afford. -- RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. -- Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your mixnode. ## Mix node setup -Now that you have built the [codebase](https://nymtech.net/docs/binaries/building-nym.html), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](https://nymtech.net/docs/binaries/building-nym.html), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. To begin, move to `/taget/release` directory from which you run the node commands: diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md new file mode 100644 index 0000000000..1c738b34bb --- /dev/null +++ b/documentation/operators/src/preliminary-steps.md @@ -0,0 +1,43 @@ +# Preliminary Steps + +> The Nym mixnode, gateway and network requester binaries were built in the [building nym](https://nymtech.net/docs/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. + +## Preliminary steps + +There are a couple of steps that need completing before starting to set up your mixnode, gateway or a network requester: + +- preparing your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) +- requisitioning a VPS (Virtual Private Server) + +### Wallet preparation +#### Mainnet +Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). + +If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. + +`NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several [exchanges](https://www.coingecko.com/en/coins/nym#markets). + +> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. + + +#### Sandbox testnet +Make sure to download a wallet and create an account as outlined above. Then head to our [token faucet](https://faucet.nymtech.net/) and get some tokens to use to bond it. + +### VPS Hardware Specs +You will need to rent a VPS to run your node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol). + +For the moment, we haven't put a great amount of effort into optimizing concurrency to increase throughput, so don't bother provisioning a beastly server with multiple cores. This will change when we get a chance to start doing performance optimizations in a more serious way. Sphinx packet decryption is CPU-bound, so once we optimize, more fast cores will be better. + +For now, see the below rough specs: + +- Processors: 2 cores are fine. Get the fastest CPUs you can afford. + +#### For Nym Mixnode + +- RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. +- Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. + +#### For Nym Gateway + +- RAM: Memory requirements depend on the amount of users your Gateway will be serving at any one time. If you're just going to be using it yourself, then minimal RAM is fine. **If you're running your Gateway as part of a Service Grant, get something with at least 4GB RAM.** +- Disks: much like the amount of RAM your Gateway could use, the amount of disk space required will vary with the amount of users your Gateway is serving. **If you're running your Gateway as part of a Service Grant, get something with at least 40GB storage.** From 141b9d396c415d8be6425805af4e7927b1caa1a4 Mon Sep 17 00:00:00 2001 From: serinko Date: Fri, 14 Jul 2023 17:17:07 +0200 Subject: [PATCH 005/146] operator-guides: made todo notes --- documentation/operators/src/faq.md | 2 ++ documentation/operators/src/nodes/gateway-setup.md | 8 +++++++- documentation/operators/src/nodes/mix-node-setup.md | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 5e1f5b72ad..e09a78c21c 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -10,5 +10,7 @@ Hi, do you know if it's on the roadmap for network nodes (requesters, socks5 cli you should be able to switch gateway (and overwrite keys) using —force-register +make a note that the keys will be overwritten in bold when you're noting it in the operators guides + ---> diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 591cd3d1a9..ecd04d1005 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -1,3 +1,7 @@ + # Gateways > The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. @@ -153,9 +157,11 @@ You can either do this graphically via the Desktop Wallet, or the CLI. #### Updating node information via the Desktop Wallet * Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +/ ![Bonding page](../images/wallet-screenshots/bonding.png) * Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +/ ![Node Settings Page](../images/wallet-screenshots/node_settings.png) #### Updating node information via the CLI @@ -244,7 +250,7 @@ This lets your operating system know it's ok to reload the service configuration Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. ## Ports -All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. +All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. ### Gateway port reference | Default port | Use | diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 68f6bf9090..dc27005feb 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -10,6 +10,10 @@ TODO - [x] Add second console output to Initialising your mixnode manually as the automatized is not working - [ ] Point users to understand the requirements for becoming a part of the active set. - [ ] Include how to move a mix node from one VPS to another while keeping the delegation etc (ie init a new mix node and move `/home/nym/.nym/mixnodes/data/*` there ?) + - copy that dir over to the new vps + - re-run init - remember that init doesn't overwrite existing keys - to generate a config with the new listening address etc + - change the node info via the wallet + - Since otherwise their keys will point to the old IP address in the smart contract, and their node will (a) not be able to be connected to, and (b) fail uptime checks - [ ] Explain more about self hosted nodes in the 6.1 not only as a troubleshooting ---> From cf71d655e294e97292f745cd75b42aaac391f0c0 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Jul 2023 19:21:25 +0200 Subject: [PATCH 006/146] operators-guide: moved repeating to maintenance.md, shortened and cleaned the existing guides --- .../operators/src/nodes/gateway-setup.md | 126 +------ .../operators/src/nodes/maintenance.md | 249 ++++++------ .../operators/src/nodes/mix-node-setup.md | 356 +----------------- 3 files changed, 142 insertions(+), 589 deletions(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index ecd04d1005..eaacfaf52a 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -1,6 +1,6 @@ # Gateways @@ -133,127 +133,7 @@ The `run` command starts the gateway: ``` ./nym-gateway run --id ``` +## Maintenance -### Upgrading your gateway -Upgrading your node is a two-step process: -* Updating the binary and `config.toml` on your VPS -* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. +For gateway upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) ->These instructions are specifically regarding upgrading your gateway binary from one version to another. If you want to change node information such as the listening port, you can do this by clicking the `node settings` tab in the `Bonding` page of the wallet. - -#### Step 1: Upgrading your binary -Follow these steps to upgrade your binary and update its config file: -* pause your gateway process. -* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your gateway process with the new binary. - -> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. - -#### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). - -You can either do this graphically via the Desktop Wallet, or the CLI. - -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -/ -![Bonding page](../images/wallet-screenshots/bonding.png) - -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -/ -![Node Settings Page](../images/wallet-screenshots/node_settings.png) - -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. - -## VPS Setup and Automation -### Configure your firewall -Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: - -``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status -``` - -Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: - -``` -sudo ufw allow 1789,22,9000/tcp -# check the status of the firewall -sudo ufw status -``` - -For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. - -### Automating your gateway with systemd -Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: - -```ini -[Unit] -Description=Nym Gateway ({{platform_release_version}}) -StartLimitInterval=350 -StartLimitBurst=10 - -[Service] -User=nym -LimitNOFILE=65536 -ExecStart=/home/nym/nym-gateway run --id supergateway -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 - -[Install] -WantedBy=multi-user.target -``` - -Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. - -Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. - -If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: - -`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` - - -Then run: - -``` -systemctl enable nym-gateway.service -``` - -Start your node: - -``` -service nym-gateway start -``` - -This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. - -You can also do `service nym-gateway stop` or `service nym-gateway restart`. - -Note: if you make any changes to your systemd script after you've enabled it, you will need to run: - -``` -systemctl daemon-reload -``` - -This lets your operating system know it's ok to reload the service configuration. - -## Gateway related Validator API endpoints -Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. - -## Ports -All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. - -### Gateway port reference -| Default port | Use | -|--------------|---------------------------| -| 1789 | Listen for Mixnet traffic | -| 9000 | Listen for Client traffic | diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index b2fe722d0a..583bb6aa47 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -1,47 +1,46 @@ # Maintenance - +## Upgrading your node - - -### Upgrading your mix node +> The process is the similar for mixnode, gateway and network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. Upgrading your node is a two-step process: -* Updating the binary and `~/.nym/mixnodes//config.toml` on your VPS -* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. +* Updating the binary and `~/.nym///config.toml` on your VPS +* Updating the node information in the [mixnet smart contract](https://nymtech.net/docs/nyx/mixnet-contract.html). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. -#### Step 1: Upgrading your binary +### Step 1: Upgrading your binary Follow these steps to upgrade your mix node binary and update its config file: * pause your mix node process. * replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. * restart your mix node process with the new binary. -#### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). +### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). You can either do this graphically via the Desktop Wallet, or the CLI. -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -\ +### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: + ![Bonding page](../images/wallet-screenshots/bonding.png) -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -\ +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. + ![Node Settings Page](../images/wallet-screenshots/node_settings.png) -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. +### Updating node information via the CLI +If you want to bond your `` via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. ---- ## VPS Setup and Automation ### Configure your firewall -The following commands will allow you to set up a firewall using `ufw`. +Although your `` is now ready to recieve traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`. ``` # check if you have ufw installed @@ -57,20 +56,24 @@ sudo ufw enable sudo ufw status ``` -Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: +Finally open your `` p2p port, as well as ports for ssh and ports for verloc and measurement pings: ``` +# for mixnode sudo ufw allow 1789,1790,8000,22/tcp +# for gateway +sudo ufw allow 1789,22,9000/tcp + # check the status of the firewall sudo ufw status ``` -For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. +For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) or [gateway port reference table](https://nymtech.net/docs/nodes/gateway-setup.html#gateway-port-reference) below. -### Automating your mix node with tmux and systemd +### Automating your node with tmux and systemd -It's useful to have the mix node automatically start at system boot time. +Although it’s not totally necessary, it's useful to have the mix node automatically start at system boot time. #### tmux @@ -92,22 +95,22 @@ In case it didn't work for your distribution, see how to build `tmux` from [vers **Running tmux** -No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let the mixnode run on its own on the VPS. +No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let your `` run on its own on the VPS. -* Pause your mixnode +* Pause your `` * Start tmux with the command ``` tmux ``` -* The terminal should stay in the same directory, just the layout changed into tmux default layout. -* Start the mixnode again with a command: +* The tmux terminal should open in the same working directory, just the layout changed into tmux default layout. +* Start the `` again with a command: ``` -./nym-mixnode run --id +./ run --id ``` -* Now, without closing the tmux window, you can close the whole terminal and the mixnode (and any other process running in tmux) will stay active. +* Now, without closing the tmux window, you can close the whole terminal and the `` (and any other process running in tmux) will stay active. * Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session: ``` -tmux attach session +tmux attach-session ``` * To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?` @@ -115,6 +118,8 @@ tmux attach session Here's a systemd service file to do that: +For mixnode: + ```ini [Unit] Description=Nym Mixnode ({{mix_node_release_version}}) @@ -133,29 +138,60 @@ RestartSec=30 WantedBy=multi-user.target ``` -Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. +* Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. -Change the `` in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `` so it is the user you are running as. +For gateway: -If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command might look like this: +```ini +[Unit] +Description=Nym Gateway ({{platform_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 -`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` +[Service] +User=nym +LimitNOFILE=65536 +ExecStart=/home///nym-gateway run --id +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +* Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. + +Change the `` in `ExecStart` to point at your `` binary (`nym-mixnode` or `nym-gateway), and the `` so it is the user you are running as. + +If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command for nym mixnode might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id `. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` Then run: ``` +# for mixnode systemctl enable nym-mixnode.service + +# for gateway +systemctl enable nym-gateway.service ``` Start your node: ``` +# for mixnode service nym-mixnode start + +# for gateway +service nym-gateway start + ``` This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. -You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. +You can also do `service stop` or `service restart`. Note: if you make any changes to your systemd script after you've enabled it, you will need to run: @@ -165,7 +201,7 @@ systemctl daemon-reload This lets your operating system know it's ok to reload the service configuration. -#### Setting the ulimit +### Setting the ulimit Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. @@ -179,7 +215,9 @@ Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too This means that the operating system is preventing network connections from being made. -##### Set the ulimit via `systemd` service file +#### Set the ulimit via `systemd` service file + +The ulimit setup is relevant for maintenance of nym mixnode only. Query the `ulimit` of your mix node with: @@ -215,7 +253,7 @@ echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. -##### Set the ulimit on `non-systemd` based distributions +#### Set the ulimit on `non-systemd` based distributions In case you chose tmux option for mixnode automatization, see your `ulimit` list by running: @@ -244,114 +282,89 @@ username soft nofile 4096 Then reboot your server and restart your mixnode. +## Virtual IPs and hosting via Google & AWS +For true internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a `` there, please read the following. +On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl ifconfig.me)`, but also specify `--announce-host` with the public IP. Please make sure that you pass the correct, routable `--announce-host`. - - -#### Step 1: Upgrading your binary -Follow these steps to upgrade your binary and update its config file: -* pause your gateway process. -* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your gateway process with the new binary. - -> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. - -#### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). - -You can either do this graphically via the Desktop Wallet, or the CLI. - -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -![Bonding page](../images/wallet-screenshots/bonding.png) - -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -![Node Settings Page](../images/wallet-screenshots/node_settings.png) - -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. - ---- - -## VPS Setup and Automation -### Configure your firewall -Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: +For example, on a Google machine, you may see the following output from the `ifconfig` command: ``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status +ens4: flags=4163 mtu 1460 + inet 10.126.5.7 netmask 255.255.255.255 broadcast 0.0.0.0 + ... ``` -Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: +The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. +`./nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. + +Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. + +The right thing to do in this situation is to init with a command: ``` -sudo ufw allow 1789,22,9000/tcp -# check the status of the firewall -sudo ufw status +./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18 ``` -For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. +This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. -### Automating your gateway with systemd -Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: +To find the right IP configuration, contact your VPS provider for support. -```ini -[Unit] -Description=Nym Gateway ({{platform_release_version}}) -StartLimitInterval=350 -StartLimitBurst=10 +## Nym API (previously 'Validator API') endpoints +Numerous API endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. -[Service] -User=nym -LimitNOFILE=65536 -ExecStart=/home/nym/nym-gateway run --id supergateway -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 +### Mix node Reward Estimation API endpoint -[Install] -WantedBy=multi-user.target -``` +The Reward Estimation API endpoint allows mixnode operators to estimate the rewards they could earn for running a Nym mixnode with a specific `MIX_ID`. -Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. +> The `` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). -Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. +The endpoint is a particularly common for mixnode operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mixnode, the quality of the mixnode's performance, and the overall demand for mixnodes in the network. This information can be useful for mixnode operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability. -If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: - -`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` - - -Then run: +Using this API endpoint returns information about the Reward Estimation: ``` -systemctl enable nym-gateway.service +/status/mixnode//reward-estimation ``` -Start your node: +Query Response: ``` -service nym-gateway start + "estimation": { + "total_node_reward": "942035.916721770541325331", + "operator": "161666.263307386408152071", + "delegates": "780369.65341438413317326", + "operating_cost": "54444.444444444444444443" + }, ``` -This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. +> The unit of value is measured in `uNYM`. -You can also do `service nym-gateway stop` or `service nym-gateway restart`. +- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node. -Note: if you make any changes to your systemd script after you've enabled it, you will need to run: +- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network. -``` -systemctl daemon-reload -``` +- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network. -This lets your operating system know it's ok to reload the service configuration. +- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. -## Gateway related Validator API endpoints -Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. +- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. + +## Ports +All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your mix node. + +### Mix node port reference +| Default port | Use | +| ------------ | ------------------------- | +| `1789` | Listen for mixnet traffic | +| `1790` | Listen for VerLoc traffic | +| `8000` | Metrics http API endpoint | + + +### Gateway port reference +| Default port | Use | +|--------------|---------------------------| +| `1789` | Listen for Mixnet traffic | +| `9000` | Listen for Client traffic | + +/ diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index dc27005feb..8690b17806 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -1,6 +1,6 @@ # Mix Nodes @@ -198,263 +199,16 @@ Keep reading to find out more about configuration options or troubleshooting if Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. -### Describe your mix node (optional) +## Node Description (optional) In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mixnode with the following command: ``` ./nym-mixnode describe --id ``` +Node description is a short text that describes your node. It is displayed in the `./nym-mixnode list` command and in the `./nym-mixnode node-details --id ` command. It also shows up in the node explorer to let people know what your node is about and link to your website. -> Remember to restart your mix node process in order for the new description to be propagated. - -### Upgrading your mix node - -Upgrading your node is a two-step process: -* Updating the binary and `~/.nym/mixnodes//config.toml` on your VPS -* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. - -#### Step 1: Upgrading your binary -Follow these steps to upgrade your mix node binary and update its config file: -* pause your mix node process. -* replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your mix node process with the new binary. - -#### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). - -You can either do this graphically via the Desktop Wallet, or the CLI. - -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -\ -![Bonding page](../images/wallet-screenshots/bonding.png) - -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -\ -![Node Settings Page](../images/wallet-screenshots/node_settings.png) - -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. - -### Displaying mix node information - -You can always check the details of your mix node with the `node-details` command: - -``` -./nym-mixnode node-details --id -``` - -## VPS Setup and Automation -### Configure your firewall -The following commands will allow you to set up a firewall using `ufw`. - -``` -# check if you have ufw installed -ufw version - -# if it is not installed, install with -sudo apt install ufw -y - -# enable ufw -sudo ufw enable - -# check the status of the firewall -sudo ufw status -``` - -Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: - -``` -sudo ufw allow 1789,1790,8000,22/tcp - -# check the status of the firewall -sudo ufw status -``` - -For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. - -### Automating your mix node with tmux and systemd - -It's useful to have the mix node automatically start at system boot time. - -#### tmux - -One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated. - -Use the following command to get `tmux`. - -Platform|Install Command ----|--- -Arch Linux|`pacman -S tmux` -Debian or Ubuntu|`apt install tmux` -Fedora|`dnf install tmux` -RHEL or CentOS|`yum install tmux` -macOS (using Homebrew|`brew install tmux` -macOS (using MacPorts)|`port install tmux` -openSUSE|`zypper install tmux` - -In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control). - -**Running tmux** - -No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let the mixnode run on its own on the VPS. - -* Pause your mixnode -* Start tmux with the command -``` -tmux -``` -* The terminal should stay in the same directory, just the layout changed into tmux default layout. -* Start the mixnode again with a command: -``` -./nym-mixnode run --id -``` -* Now, without closing the tmux window, you can close the whole terminal and the mixnode (and any other process running in tmux) will stay active. -* Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session: -``` -tmux attach session -``` -* To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?` - -#### systemd - -Here's a systemd service file to do that: - -```ini -[Unit] -Description=Nym Mixnode ({{mix_node_release_version}}) -StartLimitInterval=350 -StartLimitBurst=10 - -[Service] -User= -LimitNOFILE=65536 -ExecStart=/home///nym-mixnode run --id -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 - -[Install] -WantedBy=multi-user.target -``` - -Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. - -Change the `` in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `` so it is the user you are running as. - -If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command might look like this: - -`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` - -Then run: - -``` -systemctl enable nym-mixnode.service -``` - -Start your node: - -``` -service nym-mixnode start -``` - -This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. - -You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. - -Note: if you make any changes to your systemd script after you've enabled it, you will need to run: - -``` -systemctl daemon-reload -``` - -This lets your operating system know it's ok to reload the service configuration. - -#### Setting the ulimit - -Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. - -`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes. - -If you see errors such as: - -``` -Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } -``` - -This means that the operating system is preventing network connections from being made. - -##### Set the ulimit via `systemd` service file - -Query the `ulimit` of your mix node with: - -``` -grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits -``` - -You'll get back the hard and soft limits, which looks something like this: - -``` -Max open files 65536 65536 files -``` - -If your output is **the same as above**, your node will not encounter any `ulimit` related issues. - -However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: - -``` -LimitNOFILE=65536 -``` - -Reload the daemon: - -``` -systemctl daemon-reload -``` - -or execute this as root for system-wide setting of `ulimit`: - -``` -echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf -``` - -Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. - -##### Set the ulimit on `non-systemd` based distributions - -In case you chose tmux option for mixnode automatization, see your `ulimit` list by running: - -``` -ulimit -a - -# watch for the output line -n --n: file descriptors 1024 -``` - -You can change it either by running a command: - -``` -ulimit -u -n 4096 -``` - -or editing `etc/security/conf` and add the following lines: - -``` -# Example hard limit for max opened files -username hard nofile 4096 - -# Example soft limit for max opened files -username soft nofile 4096 -``` - -Then reboot your server and restart your mixnode. - -## Node Description -Node description is a short text that describes your node. It is displayed in the `./nym-mixnode list` command and in the `./nym-mixnode node-details` command. It also shows up in the node explorer to let people know what your node is about and link to your website. - -To set your node description, create a file called `description.toml` and put it in the same directory as your `config.toml` file (`~/.nym/mixnodes//description.toml`). The file should look like this example: +You can set your node description, by creating a file called `description.toml` and put it in the same directory as your `config.toml` file (`~/.nym/mixnodes//description.toml`). The file should look like this example: ```toml name = "Winston Smith" @@ -463,7 +217,7 @@ link = "https://nymtech.net" location = "Giza, Egypt" ``` -You will need to restart your node for the changes to take effect. +> Remember to restart your mix node process in order for the new description to be propagated. ## Node Families @@ -573,101 +327,7 @@ For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) -### Virtual IPs and hosting via Google & AWS -For tru internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a mixnode there, please read the following. +## Maintenance -On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl ifconfig.me)`, but also specify `--announce-host` with the public IP. Please make sure that you pass the correct, routable `--announce-host`. - -For example, on a Google machine, you may see the following output from the `ifconfig` command: - -``` -ens4: flags=4163 mtu 1460 - inet 10.126.5.7 netmask 255.255.255.255 broadcast 0.0.0.0 - ... -``` - -The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. - -`./nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. - -Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. - -The right thing to do in this situation is to init with a command: -``` -./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18 -``` - -This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. - -To find the right IP configuration, contact your VPS provider for support. - -## Metrics / API endpoints -The mix node binary exposes several API endpoints that can be pinged in order to gather information about the node, and the Nym API (previously 'Validator API') exposes numerous mix node related endpoints which provide network-wide information about mix nodes, the network topology (the list of avaliable mix nodes for packet routing), and information regarding uptime monitoring and rewarding history. - -### Mix node API endpoints -Since the mix node binary exposes several API endpoints itself, you can ping these easily via curl: - -| Endpoint | Description | Command | -| -------------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -| `/description` | Returns the description of the node set with the `describe` command | `curl :8000/description` | -| `/hardware` | Returns the hardware information of the node | `curl :8000/hardware` | -| `/verloc` | Returns the verloc information of the node, updated every 12 hours | `curl :8000/verloc` | - -The code for exposed API endpoints can be found [here](https://github.com/nymtech/nym/tree/release/{{platform_release_version}}/mixnode/src/node/http). - -> You can get more detailed info by appending `?debug` to the URL, like so: -> ``` -> curl http://:8000/stats?debug -> ``` - -### Mix node related Nym API (previously 'Validator API') endpoints -Numerous endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. - -#### Mix node Reward Estimation API endpoint - -The Reward Estimation API endpoint allows mixnode operators to estimate the rewards they could earn for running a Nym mixnode with a specific `MIX_ID`. - -> The `` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). - -The endpoint is a particularly common for mixnode operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mixnode, the quality of the mixnode's performance, and the overall demand for mixnodes in the network. This information can be useful for mixnode operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability. - -Using this API endpoint returns information about the Reward Estimation: - -``` -/status/mixnode//reward-estimation -``` - -Query Response: - -``` - "estimation": { - "total_node_reward": "942035.916721770541325331", - "operator": "161666.263307386408152071", - "delegates": "780369.65341438413317326", - "operating_cost": "54444.444444444444444443" - }, -``` - -> The unit of value is measured in `uNYM`. - -- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node. - -- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network. - -- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network. - -- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. - -- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. - -## Ports -All mix node-specific port configuration can be found in `$HOME/.nym/mixnodes//config/config.toml`. If you do edit any port configs, remember to restart your mix node. - -### Mix node port reference -| Default port | Use | -| ------------ | ------------------------- | -| `1789` | Listen for mixnet traffic | -| `1790` | Listen for VerLoc traffic | -| `8000` | Metrics http API endpoint | -/ +For mixnode upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) From cf79bdc098a8bbd201b43c90df8481d2b76acd7b Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Jul 2023 12:53:32 +0200 Subject: [PATCH 007/146] operators-guide: create NR page & edit maintenance page --- documentation/operators/src/SUMMARY.md | 10 +- .../operators/src/nodes/gateway-setup.md | 2 +- .../operators/src/nodes/maintenance.md | 83 +++++++- .../operators/src/nodes/mix-node-setup.md | 2 +- .../src/nodes/network-requester-setup.md | 179 +++++++++++++++++- 5 files changed, 269 insertions(+), 7 deletions(-) diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 796c7d41ed..3e0fcf4280 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -1,9 +1,17 @@ +# Summary + - [Introduction](introduction.md) +# Binaries +- [Pre-built Binaries](../../docs/src/binaries/pre-built-binaries.md) +- [Building from Source](../../docs/src/binaries/building-nym.md) +- [Binary Initialisation and Configuration](../../docs/src/binaries/init-and-config.md) + + # Operators Guides - [Node Setup Guides](./nodes/setup-guides.md) -- [Preliminary Steps](./preliminary-steps.md) + - [Preliminary Steps](./preliminary-steps.md) - [Mix Node](./nodes/mix-node-setup.md) - [Gateway](./nodes/gateway-setup.md) - [Network Requester](./nodes/network-requester-setup.md) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index eaacfaf52a..dd5c65e2ad 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -4,7 +4,7 @@ TODO ---> # Gateways -> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym gateway was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 583bb6aa47..9216556050 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -20,6 +20,8 @@ Follow these steps to upgrade your mix node binary and update its config file: * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. * restart your mix node process with the new binary. +> In case of a network requester this is all all, the following step is only for mix nodes and gateways. + ### Step 2: Updating your node information in the smart contract Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). @@ -38,6 +40,37 @@ You can either do this graphically via the Desktop Wallet, or the CLI. If you want to bond your `` via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. +### Upgrading Network Requester to >= v1.1.10 from +``` + +Copy the old keys from your client to the network-requester configuration that was created above: + +``` +cp -vr ~/.nym/clients/myoldclient/data/* ~/.nym/service-providers/network-requester//data +``` + +Edit the configuration to match what you used on your client. Specifically, edit the configuration file at: + +``` +~/.nym/service-providers/network-requester//config/config.toml +``` + +Ensure that the fields `gateway_id`, `gateway_owner`, `gateway_listener` in the new config match those in the old client config at: + +``` +~/.nym/clients/myoldclient/config/config.toml +``` + + ## VPS Setup and Automation ### Configure your firewall Although your `` is now ready to recieve traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`. @@ -65,11 +98,16 @@ sudo ufw allow 1789,1790,8000,22/tcp # for gateway sudo ufw allow 1789,22,9000/tcp -# check the status of the firewall +# for network requester +sudo ufw allow 22,9000/tcp +``` + +Check the status of the firewall: +``` sudo ufw status ``` -For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) or [gateway port reference table](https://nymtech.net/docs/nodes/gateway-setup.html#gateway-port-reference) below. +For more information about your node's port configuration, check the [port reference table](https://nymtech.net/docs/nodes/gateway-setup.html#ports) below. ### Automating your node with tmux and systemd @@ -162,6 +200,39 @@ WantedBy=multi-user.target * Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. +For network requester: + +```ini +[Unit] +Description=Nym Network Requester ({{platform_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User=nym # replace this with whatever user you wish +LimitNOFILE=65536 +# remember to add the `--enable-statistics` flag if running as part of a service grant and check the path to your nym-network-requester binary +ExecStart=/home/nym/nym-network-requester run --id +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Now enable and start your requester: + +``` +systemctl enable nym-network-requester.service +systemctl start nym-network-requester.service + +# you can always check your requester has succesfully started with: +systemctl status nym-network-requester.service +``` +* Put the above file onto your system at `/etc/systemd/system/nym-network-requester.service`. + + Change the `` in `ExecStart` to point at your `` binary (`nym-mixnode` or `nym-gateway), and the `` so it is the user you are running as. If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command for nym mixnode might look like this: @@ -351,7 +422,7 @@ Query Response: - `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. ## Ports -All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your mix node. +All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your client and node processes. ### Mix node port reference | Default port | Use | @@ -367,4 +438,10 @@ All ``-specific port configuration can be found in `$HOME/.nym// The Nym mix node binary was built in the [building nym](https://nymtech.net/docs/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym mix node binary was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 797dfd7795..1f5e5eee0c 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -1 +1,178 @@ -# Network Requester + +# Network Requesters + +> The Nym gateway was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. + +> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. + +## Current version +``` + +``` + +## Preliminary steps + +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your network requester. + +## Network Requester Whitelist +If you have access to a server, you can run the network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. + +By default the network requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester//`) as a whitelist for outbound requests. + +Any request to a URL which is not on this list will be blocked. + +On startup, if this file is not present, the requester will grab the default whitelist from [Nym's default list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) automatically. + +This default whitelist is useful for knowing that the majority of network requesters are able to support certain apps 'out of the box'. + +**Operators of a network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. + +The domains and IPs on the default whitelist can be broken down by application as follows: + + +``` +# Keybase +keybaseapi.com +s3.amazonaws.com +amazonaws.com +twitter.com +keybase.io +gist.githubusercontent.com + +# Used to for uptime healthcheck (see the section on testing your requester below for more) +nymtech.net + +# Blockstream Green Bitcoin Wallet +blockstream.info +blockstream.com +greenaddress.it + +# Electrum Bitcoin Wallet +electrum.org + +# Helios Ethereum Client +alchemy.com +lightclientdata.org +p2pify.com + +# Telegram - these IPs have been copied from https://core.telegram.org/resources/cidr.txt as Telegram does +# not seem to route by domain as the other apps on this list do +91.108.56.0/22 +91.108.4.0/22 +91.108.8.0/22 +91.108.16.0/22 +91.108.12.0/22 +149.154.160.0/20 +91.105.192.0/23 +91.108.20.0/22 +185.76.151.0/24 +2001:b28:f23d::/48 +2001:b28:f23f::/48 +2001:67c:4e8::/48 +2001:b28:f23c::/48 +2a0a:f280::/32 + +# Matrix +matrix.org + +``` + +## Network Requester Directory +You can find a list of Network Requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. + +> We are currently working on a smart-contract based solution more in line with how Mix nodes and Gateways announce themselves to the network. + +## Viewing command help + +To begin, move to `/taget/release` directory from which you run the node commands: + +``` +cd target/release +``` + +The `./nym-network-requester --help ` command can be used to show a list of available parameters. + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +You can check the required parameters for available commands by running: + +``` +./nym-network-requester --help +``` + +## Initializing and running your network requester + +The network-requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: + +``` + ./nym-network-requester init --id +``` + +In the following we used `example`. + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + + +Now that we have initialized our network-requester, we can start it with the following command: + +``` + ./nym-network-requester run --id +``` + +## Maintenance + +For network requester upgrade (including an upgrade from `= v1.1.10`), firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md). + + +## Using your network requester + +The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make network requests to any system on the internet. + +To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list`. + +### Supporting custom domains with your network requester +It is easy to add new domains and services to your network requester - simply find out which endpoints (both URLs and raw IP addresses are supported) you need to whitelist, and then add these endpoints to your `allowed.list`. + +How to go about this? Have a look in your nym-network-requester config directory: + +``` +ls $HOME/.nym/service-providers/network-requester/ + +# returns: allowed.list unknown.list +``` + +We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to restart your network requester! + +> If you are adding custom domains, please note that whilst they may appear in the logs of your network-requester as something like `api-0.core.keybaseapi.com:443`, you **only need** to include the main domain name, in this instance `keybaseapi.com` + +### Running an open proxy +If you *really* want to run an open proxy, perhaps for testing purposes for your own use or among a small group of trusted friends, it is possible to do so. You can disable network checks by passing the flag `--open-proxy` flag when you run it. If you run in this configuration, you do so at your own risk. + +## Testing your network requester +1. Make sure `nymtech.net` is in your `allowed.list` (remember to restart your network requester). + +2. Ensure that your network-requester is initialized and running. + +3. In another terminal window, run the following: + +``` +curl -x socks5h://localhost:1080 https://nymtech.net/.wellknown/connect/healthcheck.json +``` + +This command should return the following: + +``` +{ "status": "ok" } +``` + From f2a395fe42b52beebf93b2acd53b57f819f3e4f3 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 26 Jul 2023 11:46:36 +0200 Subject: [PATCH 008/146] operators-guide: create validator tutorial & add maintenance points --- documentation/operators/src/SUMMARY.md | 6 +- documentation/operators/src/introduction.md | 2 +- .../operators/src/nodes/maintenance.md | 219 +++++++++++++++++- .../operators/src/nodes/troubleshooting.md | 17 ++ 4 files changed, 231 insertions(+), 13 deletions(-) diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 3e0fcf4280..f767aec6f7 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -10,12 +10,14 @@ # Operators Guides -- [Node Setup Guides](./nodes/setup-guides.md) +- [Mixnet Nodes Setup](./nodes/setup-guides.md) - [Preliminary Steps](./preliminary-steps.md) - [Mix Node](./nodes/mix-node-setup.md) - [Gateway](./nodes/gateway-setup.md) - [Network Requester](./nodes/network-requester-setup.md) - - [Validator](./nodes/validator-setup.md) +- [Nyx Validator Setup](./nodes/validator-setup.md) - [Maintenance](./nodes/maintenance.md) - [Troubleshooting](./nodes/troubleshooting.md) + diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index a97860f292..48b5984eef 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -1,6 +1,6 @@ # Introduction -This is Nym's operators guide, containing information and setup tutorials about the various pieces of Nym mixnet infrastructure nodes, such as mix node, gateway and network requester. +This is Nym's operators guide, containing information and setup tutorials about the various pieces of Nym mixnet infrastructure nodes, such as mix node, gateway and network requester as well as Nyx chain validators. If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 9216556050..1ac31c959c 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -2,8 +2,7 @@ ## Upgrading your node @@ -70,10 +69,34 @@ Ensure that the fields `gateway_id`, `gateway_owner`, `gateway_listener` in the ~/.nym/clients/myoldclient/config/config.toml ``` +### Upgrading your validator + +Upgrading from `v0.31.1` -> `v0.32.0` process is fairly simple. Grab the `v0.32.0` release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files: + +- the new validator (`nyxd`) v0.32.0 +- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`) + +Wait for the upgrade height to be reached and the chain to halt awaiting upgrade, then: + +* copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`) replacing your existing file with the same name. +* swap in your new `nyxd` binary and restart. + +You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/9). + +Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. + +#### Common reasons for your validator being jailed + +The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. + +Running the command `df -H` will return the size of the various partitions of your VPS. + +If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. + ## VPS Setup and Automation ### Configure your firewall -Although your `` is now ready to recieve traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`. +Although your `` is now ready to receive traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`. ``` # check if you have ufw installed @@ -100,6 +123,9 @@ sudo ufw allow 1789,22,9000/tcp # for network requester sudo ufw allow 22,9000/tcp + +# for validator +sudo ufw allow 1317,26656,26660,22,80,443/tcp ``` Check the status of the firewall: @@ -156,7 +182,7 @@ tmux attach-session Here's a systemd service file to do that: -For mixnode: +##### For Mixnode ```ini [Unit] @@ -178,7 +204,7 @@ WantedBy=multi-user.target * Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. -For gateway: +##### For Gateway ```ini [Unit] @@ -200,7 +226,7 @@ WantedBy=multi-user.target * Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. -For network requester: +##### For Network requester ```ini [Unit] @@ -232,8 +258,41 @@ systemctl status nym-network-requester.service ``` * Put the above file onto your system at `/etc/systemd/system/nym-network-requester.service`. +##### For Validator -Change the `` in `ExecStart` to point at your `` binary (`nym-mixnode` or `nym-gateway), and the `` so it is the user you are running as. +Below is a systemd unit file to place at `/etc/systemd/system/nymd.service`: + +```ini +[Unit] +Description=Nyxd +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User=nyx # change to your user +Type=simple +Environment="LD_LIBRARY_PATH=/home/youruser/path/to/nyx/binaries" # change to correct path +ExecStart=/home/youruser/path/to/nyx/binaries/nymd start # change to correct path +Restart=on-failure +RestartSec=30 +LimitNOFILE=infinity + +[Install] +WantedBy=multi-user.target +``` + +Proceed to start it with: + +``` +systemctl daemon-reload # to pickup the new unit file +systemctl enable nymd # to enable the service +systemctl start nymd # to actually start the service +journalctl -f # to monitor system logs showing the service start +``` + +##### Following steps for Nym Mixnet nodes + +Change the `` in `ExecStart` to point at your `` binary (`nym-mixnode`, `nym-gateway` or `nym-network-requester`), and the `` so it is the user you are running as. If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command for nym mixnode might look like this: @@ -288,14 +347,22 @@ This means that the operating system is preventing network connections from bein #### Set the ulimit via `systemd` service file +> Replace `` variable with `nym-mixnode`, `nym-gateway` or `nym-network-requester` according the node you running on your machine. + The ulimit setup is relevant for maintenance of nym mixnode only. -Query the `ulimit` of your mix node with: +Query the `ulimit` of your `` with: ``` -grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits +# for nym-mixnode, nym-gateway and nym-network requester: +grep -i "open files" /proc/$(ps -A -o pid,cmd|grep | grep -v grep |head -n 1 | awk '{print $1}')/limits + +# for nyx validator: +grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nymd | grep -v grep |head -n 1 | awk '{print $1}')/limits ``` + + You'll get back the hard and soft limits, which looks something like this: ``` @@ -322,7 +389,15 @@ or execute this as root for system-wide setting of `ulimit`: echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf ``` -Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. +Reboot your machine and restart your node. When it comes back, use: +``` +# for nym-mixnode, nym-gateway and nym-network requester: +cat /proc/$(pidof )/limits | grep "Max open files"` to make sure the limit has changed to 65535. + +# for validator +cat /proc/$(pidof nym-validator)/limits | grep "Max open files" +``` +Make sure the limit has changed to 65535. #### Set the ulimit on `non-systemd` based distributions @@ -421,6 +496,121 @@ Query Response: - `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. +### Validator: Installing and configuring nginx for HTTPS +#### Setup +[Nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.) is an open source software used for operating high-performance web servers. It allows us to set up reverse proxying on our validator server to improve performance and security. + +Install `nginx` and allow the 'Nginx Full' rule in your firewall: + +``` +sudo ufw allow 'Nginx Full' +``` + +Check nginx is running via systemctl: + +``` +systemctl status nginx +``` + +Which should return: + +``` +● nginx.service - A high performance web server and a reverse proxy server + Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) + Active: active (running) since Fri 2018-04-20 16:08:19 UTC; 3 days ago + Docs: man:nginx(8) + Main PID: 2369 (nginx) + Tasks: 2 (limit: 1153) + CGroup: /system.slice/nginx.service + ├─2369 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; + └─2380 nginx: worker process +``` + +#### Configuration + +Proxying your validator's port `26657` to nginx port `80` can then be done by creating a file with the following at `/etc/nginx/conf.d/validator.conf`: + +``` +server { + listen 80; + listen [::]:80; + server_name "domain_name"; + + location / { + proxy_pass http://127.0.0.1:26657; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} +``` + +Followed by: + +``` +sudo apt install certbot nginx python3 +certbot --nginx -d nym-validator.yourdomain.com -m you@yourdomain.com --agree-tos --noninteractive --redirect +``` + +```admonish caution title="" +If using a VPS running Ubuntu 20: replace `certbot nginx python3` with `python3-certbot-nginx` +``` + +These commands will get you an https encrypted nginx proxy in front of the API. + +### Configuring Prometheus metrics (optional) + +Configure Prometheus with the following commands (adapted from NodesGuru's [Agoric setup guide](https://nodes.guru/agoric/setup-guide/en)): + +``` +echo 'export OTEL_EXPORTER_PROMETHEUS_PORT=9464' >> $HOME/.bashrc +source ~/.bashrc +sed -i '/\[telemetry\]/{:a;n;/enabled/s/false/true/;Ta}' $HOME/.nymd/config/app.toml +sed -i "s/prometheus-retention-time = 0/prometheus-retention-time = 60/g" $HOME/.nymd/config/app.toml +sudo ufw allow 9464 +echo 'Metrics URL: http://'$(curl -s ifconfig.me)':26660/metrics' +``` + +Your validator's metrics will be available to you at the returned 'Metrics URL'. + +~~~admonish example collapsible=true title="Console output" +``` +# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles. +# TYPE go_gc_duration_seconds summary +go_gc_duration_seconds{quantile="0"} 6.7969e-05 +go_gc_duration_seconds{quantile="0.25"} 7.864e-05 +go_gc_duration_seconds{quantile="0.5"} 8.4591e-05 +go_gc_duration_seconds{quantile="0.75"} 0.000115919 +go_gc_duration_seconds{quantile="1"} 0.001137591 +go_gc_duration_seconds_sum 0.356555301 +go_gc_duration_seconds_count 2448 +# HELP go_goroutines Number of goroutines that currently exist. +# TYPE go_goroutines gauge +go_goroutines 668 +# HELP go_info Information about the Go environment. +# TYPE go_info gauge +go_info{version="go1.15.7"} 1 +# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use. +# TYPE go_memstats_alloc_bytes gauge +go_memstats_alloc_bytes 1.62622216e+08 +# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed. +# TYPE go_memstats_alloc_bytes_total counter +go_memstats_alloc_bytes_total 2.09341707264e+11 +# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table. +# TYPE go_memstats_buck_hash_sys_bytes gauge +go_memstats_buck_hash_sys_bytes 5.612319e+06 +# HELP go_memstats_frees_total Total number of frees. +# TYPE go_memstats_frees_total counter +go_memstats_frees_total 2.828263344e+09 +# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started. +# TYPE go_memstats_gc_cpu_fraction gauge +go_memstats_gc_cpu_fraction 0.03357798610671518 +# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata. +# TYPE go_memstats_gc_sys_bytes gauge +go_memstats_gc_sys_bytes 1.3884192e+07 +``` +~~~ + ## Ports All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your client and node processes. @@ -444,4 +634,13 @@ All ``-specific port configuration can be found in `$HOME/.nym// + + + # Troubleshooting + +### Common reasons for your validator being jailed + +The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. + +Running the command `df -H` will return the size of the various partitions of your VPS. + +If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. + From c120196be0061bc27f071a2d5058c8af2337dcd2 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:55:05 +0200 Subject: [PATCH 009/146] operators-guide: incorporated PR #3656 --- documentation/operators/src/nodes/gateway-setup.md | 1 + documentation/operators/src/nodes/maintenance.md | 14 ++++++++++++++ .../operators/src/nodes/mix-node-setup.md | 2 ++ .../operators/src/nodes/network-requester-setup.md | 2 ++ 4 files changed, 19 insertions(+) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index dd5c65e2ad..cdc72700e2 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -45,6 +45,7 @@ You can also check the various arguments required for individual commands with: ``` ./nym-gateway --help ``` +> Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. ### Initialising your gateway To check available configuration options use: diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 1ac31c959c..d4884bad84 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -4,6 +4,20 @@ TODO - [x] Compare mixnode, gateway, NR steps and validator of upgrading and automation and make a generic page - this one - for all of them with additional notes for particular nodes ---> +## Useful commands + +> 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. + +For example `./target/debug/nym-network-requester --no-banner build-info --output json` will return: + +``` +{"binary_name":"nym-network-requester","build_timestamp":"2023-07-24T15:38:37.00657Z","build_version":"1.1.23","commit_sha":"c70149400206dce24cf20babb1e64f22202672dd","commit_timestamp":"2023-07-24T14:45:45Z","commit_branch":"feature/simplify-cli-parsing","rustc_version":"1.71.0","rustc_channel":"stable","cargo_profile":"debug"} +``` + ## Upgrading your node > The process is the similar for mixnode, gateway and network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 435f560a59..8797c13056 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -67,6 +67,8 @@ You can also check the various arguments required for individual commands with: ./nym-mixnode --help ``` +> Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. + ### Initialising your mix node To check available configuration options for initializing your node use: diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 1f5e5eee0c..33dc3c7c90 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -107,6 +107,8 @@ You can check the required parameters for available commands by running: ./nym-network-requester --help ``` +> Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. + ## Initializing and running your network requester The network-requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: From 7ccadffdba81ca07dc531a5ea819673c58b0555c Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:41:22 +0200 Subject: [PATCH 010/146] operators-guide:troubleshooting.md done - content ready to go out --- documentation/operators/src/faq.md | 3 +- .../operators/src/nodes/maintenance.md | 41 ++- .../operators/src/nodes/mix-node-setup.md | 10 +- .../operators/src/nodes/troubleshooting.md | 325 +++++++++++++++++- 4 files changed, 365 insertions(+), 14 deletions(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index e09a78c21c..88836f17f2 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -3,7 +3,8 @@ TODO - [ ] Explain active set and needed metrics - [ ] List friendly VPS providers - [ ] Explain difficulty running a node on a self-hosted machine -- [ ] Explain uNYM vs NYM. Why, ratio, etc +- [ ] Explain uNYM vs NYM/uNYX vs NYX. Why, ratio, etc +- [ ] Explain why validators set is whitelisted Some community questions: Hi, do you know if it's on the roadmap for network nodes (requesters, socks5 client, etc.) to reconnect to another gateway if the current gateway's connection drops or has issues? I have to reset my requester and socks5 clients to connect them to a new gateway almost every day...😕 having to delete the entire folders associated with them diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index d4884bad84..d809027150 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -3,6 +3,11 @@ ## Useful commands @@ -107,6 +112,32 @@ Running the command `df -H` will return the size of the various partitions of yo If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. +## Moving a node + +In case of a need to move a node from one machine to another and avoiding to lose the delegation, here are few steps how to do it. + +The following examples transfers a mixnode (in case of other nodes, change the `mixnodes` in the command for the `` of your desire. + +* Pause your node process. + +Assuming both machines are remote VPS. + +* Make sure your `~/.ssh/.pub` is in both of the machines `~/.ssh/authorized_keys` file +* Create a `mixnodes` folder in the target VPS. Ssh in from your terminal and run: +``` +# in case none of the nym configs was created previously +mkdir ~/.nym + +#in case no nym mixnode was initialized previously +mkdir ~/.nym/mixnodes +``` +* Move the node data (keys) and config file to the new machine by opening a local terminal (as that one's ssh key is authorized in both of the machines) and running: +``` +scp -r @:~/.nym/mixnodes/ @:~/.nym/mixnodes/ +``` +* Re-run init (remember that init doesn't overwrite existing keys) to generate a config with the new listening address etc. +* Change the node smart contract info via the wallet interface. Otherwise the keys will point to the old IP address in the smart contract, and the node will not be able to be connected, and it will fail up-time checks. +* Re-run the node from the new location. ## VPS Setup and Automation ### Configure your firewall @@ -149,10 +180,18 @@ sudo ufw status For more information about your node's port configuration, check the [port reference table](https://nymtech.net/docs/nodes/gateway-setup.html#ports) below. -### Automating your node with tmux and systemd +### Automating your node with nohup, tmux and systemd Although it’s not totally necessary, it's useful to have the mix node automatically start at system boot time. +#### nohup + +`nohup` is a command with which your terminal is told to ignore the `HUP` or 'hangup' signal. This will stop the node process ending if you kill your session. + +``` +nohup ./ run --id # where `` is the id you set during the `init` command and depends on which node you starting +``` + #### tmux One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated. diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 8797c13056..7e1cafa64c 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -8,13 +8,7 @@ TODO - [x] Add step 2/3 in the wallet bonding - [x] Better picture alignment. - [x] Add second console output to Initialising your mixnode manually as the automatized is not working -- [ ] Point users to understand the requirements for becoming a part of the active set. -- [ ] Include how to move a mix node from one VPS to another while keeping the delegation etc (ie init a new mix node and move `/home/nym/.nym/mixnodes/data/*` there ?) - - copy that dir over to the new vps - - re-run init - remember that init doesn't overwrite existing keys - to generate a config with the new listening address etc - - change the node info via the wallet - - Since otherwise their keys will point to the old IP address in the smart contract, and their node will (a) not be able to be connected to, and (b) fail uptime checks -- [ ] Explain more about self hosted nodes in the 6.1 not only as a troubleshooting +- [x] Explain more about self hosted nodes in the 6.1 not only as a troubleshooting - [x] Move the upgrade, automation, ulimit, vps, API and port parts to maintenance.md ---> @@ -327,7 +321,7 @@ There are also 2 community explorers which have been created by [Nodes Guru](htt For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) - + ## Maintenance diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index b27a417063..e5333bcfe4 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -1,13 +1,323 @@ - - # Troubleshooting +## Binary Build Problems + +### I am trying to build from the GitHub archive files and the build fails + +GitHub automatically includes .zip and tar.gz files of the Nym repository in its release. You cannot extract these and build - you'll see something like this: + +``` + process didn't exit successfully: `/build/nym/src/nym-0.12.1/target/release/build/nym-socks5-client-c1d0f76a8c7d7e9a/build-script-build` (exit status: 101) + --- stderr + thread 'main' panicked at 'failed to extract build metadata: could not find repository from '/build/nym/src/nym-0.12.1/clients/socks5'; class=Repository (6); code=NotFound (-3)', clients/socks5/build.rs:7:31 + note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +warning: build failed, waiting for other jobs to finish... +error: build failed +``` + +Why does this happen? + +We have scripts which automatically include the Git commit hash and Git tag in the binary for easier debugging later. If you download a .zip and try building from that, it's not a Git repository and build will fail as above. + +What to do? + +* Open terminal in the directory where you want to have a git repository +* To get Nym repository for the first time, run: +``` +git clone https://github.com/nymtech/nym.git +``` +* Follow the instructions to build the platform +* To upgrade, pause your nodes, in the same terminal window run `git pull`, follow the upgrade instructions and re-start your nodes. + +## General Node Config + +### Where can I find my private and public keys and config? + +All config and keys files are stored in a directory named after your `id` which you chose during the `init` process, and can be found at the following PATH: `$HOME/.nym//` where `$HOME` is a home directory of the user (your current user in this case) that launched the node or client. + +The directory structure for each node will be roughly as follows: + +``` +bob@nym:~$ tree /home/nym/.nym/mixnodes/ +/home/nym/.nym/mixnodes/ +|-- nym010 +| |-- config +| | `-- config.toml +| `-- data +| |-- private_identity.pem +| |-- private_sphinx.pem +| |-- public_identity.pem +| `-- public_sphinx.pem +``` + +> If you `cat` the `public_sphinx.pem` key, the output will be different from the public key you will see on Nym [dashboard](https://sandbox-explorer.nymtech.net/). The reason for this is that `.pem` files are encoded in **base64**, however on the web they are in **base58**. Don't be confused if your keys look different. They are the same keys, just with different encoding :) + + +## Mix Nodes + +### How can I tell my node is up and running and mixing traffic? + +First of all check the 'Mixnodes' section of either the Nym Network Explorers: +* [Mainnet](https://explorer.nymtech.net/) +* [Sandbox testnet](https://sandbox-explorer.nymtech.net/) + +Enter your **identity key** to find your node. Check the contents of the `Mixnode stats` and `Routing score` sections. + +There are 2 community explorers currently, which have been created by [Nodes Guru](https://nodes.guru): +* [Mainnet](https://mixnet.explorers.guru/) +* [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) + +If you want more information, or if your node isn't showing up on the explorer of your choice and you want to double-check, here are some examples on how to check if the node is configured properly. + +#### Check from your VPS + +Additional details can be obtained via various methods after you connect to your VPS: + +##### Socket statistics with `ss` + +``` +sudo ss -s -t | grep 1789 # if you have specified a different port in your mixnode config, change accordingly +``` + +This command should return a lot of data containing `ESTAB`. This command should work on every unix based system. + +##### List open files and reliant processes with `lsof` + +``` +# check if lsof is installed: +lsof -v +# install if not installed +sudo apt install lsof +# run against mixnode port +sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly +``` + +This command should return something like this: + +``` +nym-mixno 103349 root 53u IPv6 1333229972 0t0 TCP [2a03:b0c0:3:d0::ff3:f001]:57844->[2a01:4f9:c011:38ae::5]:1789 (ESTABLISHED) +nym-mixno 103349 root 54u IPv4 1333229973 0t0 TCP nym:57104->194.5.78.73:1789 (ESTABLISHED) +nym-mixno 103349 root 55u IPv4 1333229974 0t0 TCP nym:48130->static.236.109.119.168.clients.your-server.de:1789 (ESTABLISHED) +nym-mixno 103349 root 56u IPv4 1333229975 0t0 TCP nym:52548->vmi572614.contaboserver.net:1789 (ESTABLISHED) +nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3:f001]:43244->[2600:1f18:1031:2401:c04b:2f25:ca79:fef3]:1789 (ESTABLISHED) +``` + +##### Query `systemd` journal with `journalctl` + +``` +sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed" +``` + +If you have created `nym-mixnode.service` file (i.e. you are running your mixnode via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: + +``` +2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets! +2021-05-18T12:38:02.178Z INFO nym_mixnode::node::metrics > Since startup mixed 233739 packets! +2021-05-18T12:40:32.344Z INFO nym_mixnode::node::metrics > Since startup mixed 233837 packets! +2021-05-18T12:46:08.549Z INFO nym_mixnode::node::metrics > Since startup mixed 234081 packets! +2021-05-18T12:56:57.129Z INFO nym_mixnode::node::metrics > Since startup mixed 234491 packets! +``` + +You can add ` | tail` to the end of the command to watch for new entries in real time if needed. + +##### 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. + +For example `./target/debug/nym-network-requester --no-banner build-info --output json` will return: + +``` +{"binary_name":"nym-network-requester","build_timestamp":"2023-07-24T15:38:37.00657Z","build_version":"1.1.23","commit_sha":"c70149400206dce24cf20babb1e64f22202672dd","commit_timestamp":"2023-07-24T14:45:45Z","commit_branch":"feature/simplify-cli-parsing","rustc_version":"1.71.0","rustc_channel":"stable","cargo_profile":"debug"} +``` + +#### Check from your local machine + +##### Scan ports with `nmap`: + +``` +nmap -p 1789 -Pn +``` + +If your mixnode is configured properly it should output something like this: + +``` +bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn + +Host is up (0.053s latency). + +PORT STATE SERVICE +1789/tcp open hello +``` + +##### Query online nodes: + +``` +curl --location --request GET 'https://validator.nymtech.net/api/v1/mixnodes/' +``` + +Will return a list all nodes currently online. + +You can query gateways by replacing `mixnodes` with `gateways` in the above command, and can query for the mixnodes and gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`. + + +#### Check with Network API + +We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mixnode, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). + +### Why is my node not mixing any packets? + +If you are still unable to see your node on the dashboard, or your node is declaring it has not mixed any packets, there are several potential issues: + +- The firewall on your host machine is not configured properly. Checkout the [instructions](./maintenance.md#configure-your-firewall). +- You provided incorrect information when bonding your node. +- You are running your mixnode from a VPS without IPv6 support. +- You did not use the `--announce-host` flag while running the mixnode from your local machine behind NAT. +- You did not configure your router firewall while running the mixnode from your local machine behind NAT, or you are lacking IPv6 support. +- Your mixnode is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). + +```admonish caution +Your mixnode **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! +``` + +#### Incorrect bonding information + +Check that you have provided the correct information when bonding your mixnode in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, un-bond and then re-bond your node! + +> All delegated stake will be lost when un-bonding! However the mixnode must be operational in the first place for the delegation to have any effect. + +#### Missing `announce-host` flag + +On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mixnode host. + +If the difference between the two is unclear, contact the help desk of your VPS provider. + +#### No IPv6 connectivity + +Make sure that your VPS has IPv6 connectivity available with whatever provider you are using. + +To get all ip addresses of your host, try following commands: + +``` +hostname -i +``` + +Will return your **local ip** address. + +``` +hostname -I +``` + +Will return all of the ip addresses of your host. This output should look something like this: + +``` +bob@nym:~$ hostname -I +88.36.11.23 172.18.0.1 2a01:28:ca:102::1:641 +``` + +- The first **ipv4** is the public ip you need to use for the `--announce-host` flag. +- The second **ipv4** is the local ip you need to use for the `--host` flag. +- The 3rd output should confirm if your machine has ipv6 available. + +### Running on a local machine behind NAT with no fixed IP address + +Your ISP has to be IPv6 ready if you want to run a mixnode on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. + +Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! + +If all goes well and you have IPv6 available, then you will need to `init` the mixnode with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). + +Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support. + +Here is a sample of the `init` command example to create the mixnode config. + +``` +./nym-mixnode init --id --host 0.0.0.0 --announce-host 85.160.12.13 +``` + +- `--host 0.0.0.0` should work every time even if your local machine IPv4 address changes. For example on Monday your router gives your machine an address `192.168.0.13` and on Wednesday, the DHCP lease will end and you will be asigned `192.168.0.14`. Using `0.0.0.0` should avoid this without having to set any static ip in your router`s configuration. + +- you can get your current IPv4 address by either using `curl ipinfo.io` if you're on MacOS or Linux or visiting [whatsmyip site](https://www.whatsmyip.org/). Simply copy it and use it as `--anounce-host` address. + +Make sure you check if your node is really mixing. We are aiming to improve the setup for operators running locally, however you may need a bit of patience to set this up from your home behind NAT. + +### Accidentally killing your node process on exiting session + +When you close your current terminal session, you need to make sure you don't kill the mixnode process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). + +### Common errors and warnings + +Most of the `ERROR` and `WARN` messages in your node logs are benign - as long as your node outputs `since startup mixed X packets!` (`X` bust be > 0) in your logs (and this number increases over time), your node is mixing packets. If you want to be sure, check the Nym [dashboard](https://sandbox-explorer.nymtech.net/) or see other ways on how to check if your node is mixing properly as outlined in the section [**How can I tell my node is up and running and mixing traffic?**](./troubleshooting.md#how-can-i-tell-my-node-is-up-and-running-and-mixing-traffic?) above. + +More specific errors and warnings are covered below. + +#### `tokio runtime worker` error + +If you are running into issues with an error including the following: + +``` +thread 'tokio-runtime-worker' panicked at 'Failed to create TCP listener: Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }' +``` + +Then you need to `--announce-host ` and `--host ` on startup. This issue is addressed [above](./troubleshooting.md#missing-`announce-host`-flag) + + +### Can I use a port other than 1789 ? + +Yes! Here is what you will need to do: + +Assuming you would like to use port `1337` for your mixnode, you need to open the new port (and close the old one): + +``` +sudo ufw allow 1337 +sudo ufw deny 1789 +``` + +And then edit the mixnode's config. + +> If you want to change the port for an already running node, you need to stop the process before editing your config file. + +The config file is located at `~/.nym/mixnodes//config/config.toml`. + +For example, assuming `` was chosen to be `alice-node`: + +``` +nano ~/.nym/mixnodes/alice-node/config/config.toml +``` + +You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. + +Finally, restart your node. You should see if the mixnode is using the port you have changed in the config.toml file right after you run the node. + +### What is `verloc` and do I have to configure my mixnode to implement it? + +`verloc` is short for _verifiable location_. Mixnodes and gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fakeable and trustworthy manner. + +You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet from version `0.10.1` onward. + +## Validators + ### Common reasons for your validator being jailed The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. @@ -16,3 +326,10 @@ Running the command `df -H` will return the size of the various partitions of yo If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. + +## Where can I get more help? + +The fastest way to reach one of us or get a help from the community, visit our [Telegram Node Setup Help Chat](https://t.me/nymchan_help_chat) or head to our [Discord](https://Discord.gg/nym). + +For more tech heavy question join our [Matrix core community channel](https://matrix.to/#/#general:nymtech.chat), where you can meet other builders and Nym core team members. + From 3aa9ad01972cd8088368853a386f2964c0630169 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 27 Jul 2023 13:01:09 +0200 Subject: [PATCH 011/146] corrected scp -3 option --- documentation/operators/src/nodes/maintenance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index d809027150..26d5375a7d 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -133,7 +133,7 @@ mkdir ~/.nym/mixnodes ``` * Move the node data (keys) and config file to the new machine by opening a local terminal (as that one's ssh key is authorized in both of the machines) and running: ``` -scp -r @:~/.nym/mixnodes/ @:~/.nym/mixnodes/ +scp -r -3 @:~/.nym/mixnodes/ @:~/.nym/mixnodes/ ``` * Re-run init (remember that init doesn't overwrite existing keys) to generate a config with the new listening address etc. * Change the node smart contract info via the wallet interface. Otherwise the keys will point to the old IP address in the smart contract, and the node will not be able to be connected, and it will fail up-time checks. From 02f5fa6816d4713e04507a74a1708682508fdeea Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 28 Jul 2023 13:22:40 +0200 Subject: [PATCH 012/146] faq.md: initial questions and answers - in progress --- documentation/operators/src/faq.md | 67 ++- .../operators/src/nodes/validator-setup.md | 558 ++++++++++++++++++ 2 files changed, 620 insertions(+), 5 deletions(-) create mode 100644 documentation/operators/src/nodes/validator-setup.md diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 88836f17f2..4fbc17694a 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -1,10 +1,10 @@ +---> +# Frequently Asked Questions + +## Mixnet nodes + +### What determines the rewards when running a mixnode? + +The stake required for a mix node to achieve maximum rewards is called to the mix node saturation point os simply stake saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. + +The node stake saturation point, which we denote by Nsat, is given by the stake supply, target level of staking divided by the number of rewarded (active) nodes. + +This design ensures the nodes aim to have a same size of stake (reputation) which can be done by delegation staking, as well as it ensures that there is a decentralization of staking as any higher level of staked tokens per node results in worse rewards. On the contrary, the more mix nodes are active, the lower is Nsat. The equilibrium is reached when the staked tokens are delegated equally across the active mix-nodes and that's our basis for this incentive system. + +For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). And [here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. And finally an [update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. + +### Which VPS providers would you recommend? + +Consider in which jurisdiction they reside and where they want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. + +### Why is a mixnode setup on a self-hosted machine so tricky? + +### What's the Sphinx packet size? + +The sizes are shown in the configs [here](https://github.com/nymtech/nym/blob/1ba6444e722e7757f1175a296bed6e31e25b8db8/common/nymsphinx/params/src/packet_sizes.rs#L12) (default is the one clients use, the others are for research purposes, not to be used in production as this would fragment the anonymity set). More info can be found [here](https://github.com/nymtech/nym/blob/4844ac953a12b29fa27688609ec193f1d560c996/common/nymsphinx/anonymous-replies/src/reply_surb.rs#L80). + +### Why a mix node and a gateway cannot be bond to the same wallet? + +Becauase of the way the smart contract works we keep it one-node one-address at the moment. + +### Which nodes are the most needed to be setup to strengthen Nym infrastructure and which ones bring rewards? + +Right now only mix nodes are rewarded. We're working on gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do mix nodes. + +### Are mixnodes whitelisted? + +Nope, anyone can run a mixnode. Purely reliant on the node's reputation (self stake + delegations) & routing score. + +## Validators and tokens + +### What's the difference between NYM and uNYM? + +1 NYM = 1 000 000 uNYM + + + +### Can I run a validator? + +We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. + +### Why is validator set entry whitelisted? + +We understand that the early days of the Nyx blockchain will face possible vulnerabilities in terms of size - easy to disrupt or halt the chain if a malicious party entered with a large portion of stake. Besides that, there are some legal issues we need to address before we can distribute the validator set in a fully permissions fashion. + +### Why does Nym do many airdrops? + +It is part of ensuring decentralisation - we need to avoid a handful of people having too much control over the token and market. Of course ideally people will stake the tokens and contribute to the project at this stage. We run surveys to better understand what people are doing with their tokens and what usability issues there are for staking. Any feedback is appreciated as it helps us improve all aspects of using the token and participating in the ecosystem. diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md new file mode 100644 index 0000000000..6eafb49106 --- /dev/null +++ b/documentation/operators/src/nodes/validator-setup.md @@ -0,0 +1,558 @@ + +# Validators + +> Nym has two main codebases: +> - the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code except for the validators. +> - the [Nym validators](https://github.com/nymtech/nyxd), written in Go. + +The validator is built using [Cosmos SDK](https://cosmos.network) and [Tendermint](https://tendermint.com), with a [CosmWasm](https://cosmwasm.com) smart contract controlling the directory service, node bonding, and delegated mixnet staking. + +> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. + +## Building your validator + +> Any syntax in `<>` brackets is a user's unique variable. Exchange it with a corresponding name without the `<>` brackets. + +### Prerequisites +#### `git`, `gcc`, `jq` + +* Debian-based systems: +``` +apt install git build-essential jq + +# optional additional manual pages can be installed with: +apt-get install manpages-dev +``` + +* Arch-based systems: +Install `git`, `gcc` and `jq` with the following: +``` +pacman -S git gcc jq +``` + +#### `Go` +`Go` can be installed via the following commands (taken from the [Go Download and install page](https://go.dev/doc/install)): + +``` +# First remove any existing old Go installation and extract the archive you just downloaded into /usr/local: +# You may need to run the command as root or through sudo +rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.6.linux-amd64.tar.gz + +# Add /usr/local/go/bin to the PATH environment variable +export PATH=$PATH:/usr/local/go/bin +source $HOME/.profile +``` + + +Verify `Go` is installed with: + +``` +go version +# Should return something like: +go version go1.20.4 linux/amd64 +``` + +### Download a precompiled validator binary +You can find pre-compiled binaries for Ubuntu `22.04` and `20.04` [here](https://github.com/nymtech/nyxd/releases). + +```admonish caution title="" +There are seperate releases for Mainnet and the Sandbox testnet - make sure to download the correct binary to avoid `bech32Prefix` mismatches. +``` + +### Manually compiling your validator binary +The codebase for the Nyx validators can be found [here](https://github.com/nymtech/nyxd). + +The validator binary can be compiled by running the following commands: +``` +git clone https://github.com/nymtech/nyxd.git +cd nyxd +git checkout release/ + +# Mainnet +make build + +# Sandbox testnet +BECH32_PREFIX=nymt make build +``` + +At this point, you will have a copy of the `nyxd` binary in your `build/` directory. Test that it's compiled properly by running: + +``` +./build/nyxd +``` + +You should see a similar help menu printed to you: + +~~~admonish example collapsible=true title="Console output" +``` +Wasm Daemon (server) + +Usage: + nyxd [command] + +Available Commands: + add-genesis-account Add a genesis account to genesis.json + add-wasm-genesis-message Wasm genesis subcommands + collect-gentxs Collect genesis txs and output a genesis.json file + config Create or query an application CLI configuration file + debug Tool for helping with debugging your application + export Export state to JSON + gentx Generate a genesis tx carrying a self delegation + help Help about any command + init Initialize private validator, p2p, genesis, and application configuration files + keys Manage your application's keys + query Querying subcommands + rollback rollback cosmos-sdk and tendermint state by one height + start Run the full node + status Query remote node for status + tendermint Tendermint subcommands + tx Transactions subcommands + validate-genesis validates the genesis file at the default location or at the location passed as an arg + version Print the application binary version information + +Flags: + -h, --help help for nyxd + --home string directory for config and data (default "/home/willow/.nyxd") + --log_format string The logging format (json|plain) (default "plain") + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) (default "info") + --trace print out full stack trace on errors + +Use "nyxd [command] --help" for more information about a command. + +``` +~~~ + +### Linking `nyxd` to `libwasmvm.so` + +`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1`. + +If you downloaded your `nyxd` binary from Github, you will have seen this file when un-`tar`-ing the `.tar.gz` file from the releases page. + +If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.so` file to correct location. + +Simply `cp` or `mv` that file to `/lib/x86_64-linux-gnu/` and re-run `nyxd`. + +### Adding `nyxd` to your `$PATH` +You'll need to set `LD_LIBRARY_PATH` in your user's `~/.bashrc` or `~/.zshrc` file (depends on the terminal you use), and add that to our path. Replace `/home///binaries` in the command below to the locations of `nyxd` and `libwasmvm.so` and run it. If you have compiled these on the server, they will be in the `build/` folder: + +``` +NYX_BINARIES=/home/// + +# if you are using another shell like zsh replace '.bashrc' with the relevant config file +echo 'export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:'NYX_BINARIES >> ~/.bashrc +echo 'export PATH=$PATH:'${NYX_BINARIES} >> ~/.bashrc +source ~/.bashrc +``` + +Test everything worked: + +``` +nyxd +``` + +This should return the regular help menu: + +~~~admonish example collapsible=true title="Console output" +``` +Wasm Daemon (server) + +Usage: + nyxd [command] + +Available Commands: + add-genesis-account Add a genesis account to genesis.json + add-wasm-genesis-message Wasm genesis subcommands + collect-gentxs Collect genesis txs and output a genesis.json file + config Create or query an application CLI configuration file + debug Tool for helping with debugging your application + export Export state to JSON + gentx Generate a genesis tx carrying a self delegation + help Help about any command + init Initialize private validator, p2p, genesis, and application configuration files + keys Manage your application's keys + query Querying subcommands + rollback rollback cosmos-sdk and tendermint state by one height + start Run the full node + status Query remote node for status + tendermint Tendermint subcommands + tx Transactions subcommands + validate-genesis validates the genesis file at the default location or at the location passed as an arg + version Print the application binary version information + +Flags: + -h, --help help for nyxd + --home string directory for config and data (default "/home/willow/.nyxd") + --log_format string The logging format (json|plain) (default "plain") + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) (default "info") + --trace print out full stack trace on errors + +Use "nyxd [command] --help" for more information about a command. + +``` +~~~ + +## Initialising your validator +### Prerequisites: + +- FQDN Domain name +- IPv4 and IPv6 connectivity + +Choose a name for your validator and use it in place of `` in the following command: + +``` +# Mainnet +nyxd init --chain-id=nyx + +# Sandbox testnet +nyxd init --chain-id=sandbox +``` + +```admonish caution title="" +`init` generates `priv_validator_key.json` and `node_key.json`. + +If you have already set up a validator on a network, **make sure to back up the key located at** +`~/.nyxd/config/priv_validator_key.json`. + +If you don't save the validator key, then it can't sign blocks and will be jailed all the time, and +there is no way to deterministically (re)generate this key. +``` + +At this point, you have a new validator, with its own genesis file located at `$HOME/.nyxd/config/genesis.json`. You will need to replace the contents of that file that with either the Nyx Mainnet or Sandbox Testnet genesis file. + +You can use the following command to download them for the correct network: + +``` +# Mainnet +wget -O $HOME/.nyxd/config/genesis.json https://nymtech.net/genesis/genesis.json + +# Sandbox testnet +wget -O $HOME/.nyxd/config/genesis.json https://sandbox-validator1.nymtech.net/snapshots/genesis.json +``` + +### `config.toml` configuration + +Edit the following config options in `$HOME/.nyxd/config/config.toml` to match the information below for your network: + +``` +# Mainnet +persistent_peers = "ee03a6777fb76a2efd0106c3769daaa064a3fcb5@51.79.21.187:26656" +create_empty_blocks = false +laddr = "tcp://0.0.0.0:26656" +``` + +``` +# Sandbox testnet +cors_allowed_origins = ["*"] +persistent_peers = "8421c0a3d90d490e27e8061f2abcb1276c8358b6@sandbox-validator1.nymtech.net:26666" +create_empty_blocks = false +laddr = "tcp://0.0.0.0:26656" +``` + +These affect the following: +* `persistent_peers = "@.nymtech.net:26666"` allows your validator to start pulling blocks from other validators. **The main sandbox validator listens on `26666` instead of the default `26656` for debugging**. It is recommended you do not change your port from `26656`. +* `create_empty_blocks = false` will save space +* `laddr = "tcp://0.0.0.0:26656"` is in your p2p configuration options + +Optionally, if you want to enable [Prometheus](https://prometheus.io/) metrics then the following must also match in the `config.toml`: + +- `prometheus = true` +- `prometheus_listen_addr = ":26660"` + +> Remember to enable metrics in the 'Configuring Prometheus metrics' section below as well. + +And if you wish to add a human-readable moniker to your node: + +- `moniker = ""` + +Finally, if you plan on using [Cockpit](https://cockpit-project.org/documentation.html) on your server, change the `grpc` port from `9090` as this is the port used by Cockpit. + +### `app.toml` configuration +In the file `$HOME/nyxd/config/app.toml`, set the following values: + +``` +# Mainnet +minimum-gas-prices = "0.025unym,0.025unyx" +enable = true in the `[api]` section to get the API server running +``` +``` +# Sandbox Testnet +minimum-gas-prices = "0.025unymt,0.025unyxt" +enable = true` in the `[api]` section to get the API server running +``` + +### Setting up your validator's admin user +You'll need an admin account to be in charge of your validator. Set that up with: + +``` +nyxd keys add nyxd-admin +``` + +This will add keys for your administrator account to your system's keychain and log your name, address, public key, and mnemonic. As the instructions say, remember to **write down your mnemonic**. + +You can get the admin account's address with: + +``` +nyxd keys show nyxd-admin -a +``` + +Type in your keychain **password**, not the mnemonic, when asked. + +## Starting your validator + +```admonish caution title="" +If you are running a Sandbox testnet validator, please skip the `validate-genesis` command: it will fail due to the size of the genesis file as this is a fork of an existing chain state. +``` + +Everything should now be ready to go. You've got the validator set up, all changes made in `config.toml` and `app.toml`, the Nym genesis file copied into place (replacing the initial auto-generated one). Now let's validate the whole setup: + +``` +nyxd validate-genesis +``` + +If this check passes, you should receive the following output: + +``` +File at /path/to/genesis.json is a valid genesis file +``` + +> If this test did not pass, check that you have replaced the contents of `//.nymd/config/genesis.json` with that of the correct genesis file. + +### Open firewall ports + +Before starting the validator, we will need to open the firewall ports: + +``` +# if ufw is not already installed: +sudo apt install ufw +sudo ufw enable +sudo ufw allow 1317,26656,26660,22,80,443/tcp +# to check everything worked +sudo ufw status +``` + +Ports `22`, `80`, and `443` are for ssh, http, and https connections respectively. The rest of the ports are documented [here](https://docs.cosmos.network/main/core/grpc_rest). + +For more information about your validator's port configuration, check the [validator port reference table](https://nymtech.net/operators/binaries/maintenance.html#ports) below. + +> If you are planning to use [Cockpit](https://cockpit-project.org/) on your validator server then you will have defined a different `grpc` port in your `config.toml` above: remember to open this port as well. + +Start the validator: + +``` +nyxd start +``` + +Once your validator starts, it will start requesting blocks from other validators. This may take several hours. Once it's up to date, you can issue a request to join the validator set with the command below. + +### Syncing from a snapshot +If you wish to sync from a snapshot on **mainnet** use Polkachu's [mainnet](https://polkachu.com/networks/nym) resources. + +If you wish to sync from a snapshot on **Sandbox testnet** use the below commands, which are a modified version of Polkachu's excellent resources. These commands assume you are running an OS with `apt` as the package manager: + +``` +# install lz4 if necessary +sudo apt install snapd -y +sudo snap install lz4 + +# download the snapshot +wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://sandbox-validator1.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4 + +# reset your validator state +nyxd tendermint unsafe-reset-all + +# unpack the snapshot +lz4 -c -d nyxd-sandbox-snapshot-data.tar.lz4 | tar -x -C $HOME/.nyxd +``` + +You can then restart `nyxd` - it should start syncing from a block > 2000000. + +### Joining Consensus +```admonish caution title="" +When joining consensus, make sure that you do not disrupt (or worse - halt) the network by coming in with a disproportionately large amount of staked tokens. + +Please initially stake a small amount of tokens compared to existing validators, then delegate to yourself in tranches over time. +``` + +Once your validator has synced and you have received tokens, you can join consensus and produce blocks. + +``` +# Mainnet +nyxd tx staking create-validator + --amount=10000000unyx + --fees=0unyx + --pubkey=$(/home///nyxd/binaries/nyxd tendermint show-validator) + --moniker="" + --chain-id=nyx + --commission-rate="0.10" + --commission-max-rate="0.20" + --commission-max-change-rate="0.01" + --min-self-delegation="1" + --gas="auto" + --gas-adjustment=1.15 + --from="KEYRING_NAME" + --node https://rpc-1.nyx.nodes.guru:443 +``` +``` +# Sandbox Testnet +nyxd tx staking create-validator + --amount=10000000unyxt + --fees=5000unyxt + --pubkey=$(/home///nym/binaries/nyxd tendermint show-validator) + --moniker="" + --chain-id=sandbox + --commission-rate="0.10" + --commission-max-rate="0.20" + --commission-max-change-rate="0.01" + --min-self-delegation="1" + --gas="auto" + --gas-adjustment=1.15 + --from="KEYRING_NAME" + --node https://sandbox-validator1.nymtech.net:443 +``` + +You'll need either `unyxt` tokens on Sandbox, or `unyx` tokens on mainnet to perform this command. + +> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. + +If you want to edit some details for your node you will use a command like this: + +``` +# Mainnet +nyxd tx staking edit-validator + --chain-id=nyx + --moniker="" + --details="Nyx validator" + --security-contact="" + --identity="" + --gas="auto" + --gas-adjustment=1.15 + --from="KEYRING_NAME" + --fees 2000unyx +``` +``` +# Sandbox testnet +nyxd tx staking edit-validator + --chain-id=sandbox + --moniker="" + --details="Sandbox testnet validator" + --security-contact="your email" + --identity="" + --gas="auto" + --gas-adjustment=1.15 + --from="KEYRING_NAME" + --fees 2000unyxt +``` + +With above command you can specify the `gpg` key last numbers (as used in `keybase`) as well as validator details and your email for security contact. + +### Automating your validator with systemd +You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#systemd) with a quick tutorial. + +### Installing and configuring nginx for HTTPS + +If you want to set up a reverse proxying on the validator server to improve security and performance, using [nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.), follow the manual on the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#setup). + +### Setting the ulimit + +Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#Setting-the-ulimit) to change the `ulimit` value for validators. + +## Using your validator +### Unjailing your validator +If your validator gets jailed, you can fix it with the following command: + +``` +# Mainnet +nyxd tx slashing unjail + --broadcast-mode=block + --from="KEYRING_NAME" + --chain-id=nyx + --gas=auto + --gas-adjustment=1.4 + --fees=7000unyx +``` +``` +# Sandbox Testnet +nyxd tx slashing unjail + --broadcast-mode=block + --from="KEYRING_NAME" + --chain-id=sandbox + --gas=auto + --gas-adjustment=1.4 + --fees=7000unyxt +``` + +### Upgrading your validator + +To upgrade your validator, follow the steps on the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#Setting-the-ulimit). + +#### Common reasons for your validator being jailed + +The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. + +Running the command `df -H` will return the size of the various partitions of your VPS. + +If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. + +### Day 2 operations with your validator + +You can check your current balances with: + +``` +nymd query bank balances ${ADDRESS} +``` + +For example, on the Sanbox testnet this would return: + +```yaml +balances: +- amount: "919376" +denom: unymt +pagination: +next_key: null +total: "0" +``` + +You can, of course, stake back the available balance to your validator with the following command. + +> Remember to save some tokens for gas costs! + +``` +# Mainnet +nyxd tx staking delegate VALOPERADDRESS AMOUNTunym + --from="KEYRING_NAME" + --keyring-backend=os + --chain-id=nyx + --gas="auto" + --gas-adjustment=1.15 + --fees 5000unyx +``` +``` +# Sandbox Testnet +nyxd tx staking delegate VALOPERADDRESS AMOUNTunymt + --from="KEYRING_NAME" + --keyring-backend=os + --chain-id=sandbox + --gas="auto" + --gas-adjustment=1.15 + --fees 5000unyxt +``` + From db407847e310b59abaace3055ee9cdfeb574f203 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:25:11 +0200 Subject: [PATCH 013/146] operators: book build - minor issues remain --- documentation/operators/book.toml | 10 ++++++---- documentation/operators/src/SUMMARY.md | 3 +-- documentation/operators/src/faq.md | 2 +- .../operators/src/nodes/mix-node-setup.md | 14 -------------- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index c39bb1c6a1..4202abc3f9 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -52,9 +52,11 @@ minimum_rust_version = "1.66" platform_release_version = "v1.1.22" wallet_release_version = "v1.2.5" -[preprocessor.last-changed] -command = "mdbook-last-changed" -renderer = ["html"] + +# [preprocessor.last-changed] +# command = "mdbook-last-changed" +# renderer = ["html"] + # used for grabbing output of binary commands for automation # https://github.com/FauconFan/mdbook-cmdrun @@ -85,7 +87,7 @@ curly-quotes = true # mathjax-support = false # useful if we want to pull equations in copy-fonts = true no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css"] #,"last-changed.css"] additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index f767aec6f7..04d855952f 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -18,6 +18,5 @@ - [Nyx Validator Setup](./nodes/validator-setup.md) - [Maintenance](./nodes/maintenance.md) - [Troubleshooting](./nodes/troubleshooting.md) - + diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 4fbc17694a..0de60740bd 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -31,7 +31,7 @@ For more detailed calculation, read our blog post [Nym Token Economics update](h ### Which VPS providers would you recommend? -Consider in which jurisdiction they reside and where they want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. +Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. ### Why is a mixnode setup on a self-hosted machine so tricky? diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 7e1cafa64c..f8981fed68 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -1,17 +1,3 @@ - - # Mix Nodes > The Nym mix node binary was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. From ce87df3026474eb1597f152a8a7e9534d96a17d5 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:47:57 +0200 Subject: [PATCH 014/146] operators: comment missing info --- documentation/operators/src/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 0de60740bd..3c832b68ed 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -33,7 +33,7 @@ For more detailed calculation, read our blog post [Nym Token Economics update](h Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. -### Why is a mixnode setup on a self-hosted machine so tricky? + ### What's the Sphinx packet size? From 432af5a20495e6829dd5b506461ef1e321b0205d Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:53:21 +0200 Subject: [PATCH 015/146] operators: typo edit --- documentation/operators/src/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 3c832b68ed..faefd70b18 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -21,7 +21,7 @@ make a note that the keys will be overwritten in bold when you're noting it in t ### What determines the rewards when running a mixnode? -The stake required for a mix node to achieve maximum rewards is called to the mix node saturation point os simply stake saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. +The stake required for a mix node to achieve maximum rewards is called mix node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. The node stake saturation point, which we denote by Nsat, is given by the stake supply, target level of staking divided by the number of rewarded (active) nodes. From 615c65cb22c9c2923e169859813ae8200b32873b Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:58:29 +0200 Subject: [PATCH 016/146] operators guide: add src/binaries/ files, fix links --- documentation/operators/src/SUMMARY.md | 6 +- .../operators/src/binaries/building-nym.html | 350 ++++++++++++++++++ .../operators/src/binaries/building-nym.md | 71 ++++ .../src/binaries/init-and-config.html | 290 +++++++++++++++ .../operators/src/binaries/init-and-config.md | 13 + .../src/binaries/pre-built-binaries.html | 286 ++++++++++++++ .../src/binaries/pre-built-binaries.md | 6 + .../src/binaries/version-compatiblity.md | 38 ++ .../operators/src/nodes/gateway-setup.md | 2 +- .../operators/src/nodes/mix-node-setup.md | 4 +- .../src/nodes/network-requester-setup.md | 2 +- .../operators/src/nodes/setup-guides.md | 8 +- .../operators/src/nodes/validator-setup.md | 10 +- .../operators/src/preliminary-steps.md | 2 +- 14 files changed, 1071 insertions(+), 17 deletions(-) create mode 100644 documentation/operators/src/binaries/building-nym.html create mode 100644 documentation/operators/src/binaries/building-nym.md create mode 100644 documentation/operators/src/binaries/init-and-config.html create mode 100644 documentation/operators/src/binaries/init-and-config.md create mode 100644 documentation/operators/src/binaries/pre-built-binaries.html create mode 100644 documentation/operators/src/binaries/pre-built-binaries.md create mode 100644 documentation/operators/src/binaries/version-compatiblity.md diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 04d855952f..a3f55376c8 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -3,9 +3,9 @@ - [Introduction](introduction.md) # Binaries -- [Pre-built Binaries](../../docs/src/binaries/pre-built-binaries.md) -- [Building from Source](../../docs/src/binaries/building-nym.md) -- [Binary Initialisation and Configuration](../../docs/src/binaries/init-and-config.md) +- [Pre-built Binaries](./binaries/pre-built-binaries.md) +- [Building from Source](./binaries/building-nym.md) +- [Binary Initialisation and Configuration](./binaries/init-and-config.md) # Operators Guides diff --git a/documentation/operators/src/binaries/building-nym.html b/documentation/operators/src/binaries/building-nym.html new file mode 100644 index 0000000000..2f73af4b4f --- /dev/null +++ b/documentation/operators/src/binaries/building-nym.html @@ -0,0 +1,350 @@ + + + + + + Building from Source - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Building from Source

+
+

Nym runs on Mac OS X, Linux, and Windows. All nodes except the Desktop Wallet and NymConnect on Windows should be considered experimental - it works fine if you’re an app developer but isn’t recommended for running nodes.

+
+

Building Nym

+

Nym has two main codebases:

+
    +
  • the Nym platform, written in Rust. This contains all of our code except for the validators.
  • +
  • the Nym validators, written in Go.
  • +
+
+

This page details how to build the main Nym platform code. If you want to build and run a validator, go here instead.

+
+

Prerequisites

+
    +
  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
  • +
+
apt install pkg-config build-essential libssl-dev curl jq git
+
+
    +
  • Arch/Manjaro: base-devel
  • +
+
pacman -S base-devel
+
+
    +
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git +Running the following the script installs Homebrew and the above dependencies:
  • +
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
+
    +
  • Rust & cargo >= 1.66
  • +
+

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

+

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

+

Download and build Nym binaries

+

The following commands will compile binaries into the nym/target/release directory:

+
rustup update
+git clone https://github.com/nymtech/nym.git
+cd nym
+
+git reset --hard # in case you made any changes on your branch
+git pull # in case you've checked it out before
+
+git checkout release/v1.1.22 # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks
+
+cargo build --release # build your binaries with **mainnet** configuration
+NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration
+
+

Quite a bit of stuff gets built. The key working parts are:

+ +

The repository also contains Typescript applications which aren’t built in this process. These can be built by following the instructions on their respective docs pages.

+ +
+

You cannot build from GitHub’s .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn’t a Git repository). Check the code out from github using git clone instead.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/operators/src/binaries/building-nym.md b/documentation/operators/src/binaries/building-nym.md new file mode 100644 index 0000000000..8610fcb63a --- /dev/null +++ b/documentation/operators/src/binaries/building-nym.md @@ -0,0 +1,71 @@ +# Building from Source + +> Nym runs on Mac OS X, Linux, and Windows. All nodes **except the Desktop Wallet and NymConnect** on Windows should be considered experimental - it works fine if you're an app developer but isn't recommended for running nodes. + +## Building Nym +Nym has two main codebases: + +- the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code _except_ for the validators. +- the [Nym validators](https://github.com/nymtech/nyxd), written in Go. + +> This page details how to build the main Nym platform code. **If you want to build and run a validator, [go here](../nodes/validator-setup.md) instead.** + +## Prerequisites +- Debian/Ubuntu: `pkg-config`, `build-essential`, `libssl-dev`, `curl`, `jq`, `git` + +``` +apt install pkg-config build-essential libssl-dev curl jq git +``` + +- Arch/Manjaro: `base-devel` + +``` +pacman -S base-devel +``` + +- Mac OS X: `pkg-config` , `brew`, `openss1`, `protobuf`, `curl`, `git` +Running the following the script installs Homebrew and the above dependencies: + +``` +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +- `Rust & cargo >= {{minimum_rust_version}}` + +We recommend using the [Rust shell script installer](https://www.rust-lang.org/tools/install). Installing cargo from your package manager (e.g. `apt`) is not recommended as the packaged versions are usually too old. + +If you really don't want to use the shell script installer, the [Rust installation docs](https://forge.rust-lang.org/infra/other-installation-methods.html) contain instructions for many platforms. + +## Download and build Nym binaries +The following commands will compile binaries into the `nym/target/release` directory: + +``` +rustup update +git clone https://github.com/nymtech/nym.git +cd nym + +git reset --hard # in case you made any changes on your branch +git pull # in case you've checked it out before + +git checkout release/{{platform_release_version}} # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks + +cargo build --release # build your binaries with **mainnet** configuration +NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration +``` + +Quite a bit of stuff gets built. The key working parts are: + +* [mix node](../nodes/mix-node-setup.md): `nym-mixnode` +* [gateway node](../nodes/gateway-setup.md): `nym-gateway` +* [websocket client](https://nymtech.net/docs/clients/websocket-client.html): `nym-client` +* [socks5 client](https://nymtech.net/docs/clients/socks5-client.html): `nym-socks5-client` +* [webassembly client](https://nymtech.net/docs/clients/webassembly-client.html): `webassembly-client` +* [network requester](../nodes/network-requester-setup.md): `nym-network-requester` +* [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli` + +The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages. +* [Nym Wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) +* [Nym Connect](https://nymtech.net/developers/quickstart/nymconnect-gui.html) +* [Network Explorer UI](https://nymtech.net/docs/explorers/mixnet-explorer.html) + +> You cannot build from GitHub's .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn't a Git repository). Check the code out from github using `git clone` instead. diff --git a/documentation/operators/src/binaries/init-and-config.html b/documentation/operators/src/binaries/init-and-config.html new file mode 100644 index 0000000000..147c89cc2d --- /dev/null +++ b/documentation/operators/src/binaries/init-and-config.html @@ -0,0 +1,290 @@ + + + + + + Binary Initialisation and Configuration - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Binary Initialisation and Configuration

+

All Nym binaries must first be initialised with init before being run.

+

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

+

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will not overwrite existing keypairs if they are present.

+

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

+

Once you have run init, you can start your binary with the run command, usually only accompanied by the id of the binary that you specified.

+

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/operators/src/binaries/init-and-config.md b/documentation/operators/src/binaries/init-and-config.md new file mode 100644 index 0000000000..e749662b8e --- /dev/null +++ b/documentation/operators/src/binaries/init-and-config.md @@ -0,0 +1,13 @@ +# Binary Initialisation and Configuration + +All Nym binaries must first be initialised with `init` before being `run`. + +The `init` command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc. + +The `init` command will also create the necessary keypairs and configuration files at `~/.nym///` if these files do not already exist. **It will not overwrite existing keypairs if they are present.** + +You can reconfigure your binaries at any time by editing the config file located at `~/.nym///config/config.toml` and restarting the binary process. + +Once you have run `init`, you can start your binary with the `run` command, usually only accompanied by the `id` of the binary that you specified. + +This `id` is **never** transmitted over the network, and is used to select which local config and key files to use for startup. diff --git a/documentation/operators/src/binaries/pre-built-binaries.html b/documentation/operators/src/binaries/pre-built-binaries.html new file mode 100644 index 0000000000..3497c15d85 --- /dev/null +++ b/documentation/operators/src/binaries/pre-built-binaries.html @@ -0,0 +1,286 @@ + + + + + + Pre-built Binaries - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Pre-built Binaries

+

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

+

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/operators/src/binaries/pre-built-binaries.md b/documentation/operators/src/binaries/pre-built-binaries.md new file mode 100644 index 0000000000..269c26276c --- /dev/null +++ b/documentation/operators/src/binaries/pre-built-binaries.md @@ -0,0 +1,6 @@ +# Pre-built Binaries + +The [Github releases page](https://github.com/nymtech/nym/releases) has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere. + +If the pre-built binaries don't work or are unavailable for your system, you will need to build the platform yourself. + diff --git a/documentation/operators/src/binaries/version-compatiblity.md b/documentation/operators/src/binaries/version-compatiblity.md new file mode 100644 index 0000000000..67e8a71ce6 --- /dev/null +++ b/documentation/operators/src/binaries/version-compatiblity.md @@ -0,0 +1,38 @@ +# Version Compatibility Table + +There are numerous components to Nym which are released independently of one another aside from when breaking changes occur in the [core platform code](https://github.com/nymtech/nym/) - mix nodes, gateways, network requesters, and clients. + +Whilst in general it recommended to be running the most recent version of any software, if you cannot do that for whatever reason this table will tell you which versions of different components are mutually compatible with which platform code releases. + + +| Core Platform | SDK | Wallet | NymConnect | Network Explorer | Mixnet contract | Vesting contract | +| ---------------- | ------------- | --------------- | --------------- | ---------------- | --------------- | ---------------- | +| 1.1.13 - 1.1.14* | 1.1.7 | 1.1.12 - 1.1.13 | 1.1.12 - 1.1.13 | 1.1.2 | 1.2.0 - 1.3.0 | 1.2.0 - 1.3.0 | +| 1.1.1 - 1.1.12 | 1.1.4 - 1.1.7 | 1.1.0 - 1.1.12 | 1.1.1 - 1.1.12 | 1.1.0 - 1.1.2 | 1.1.0 - 1.1.3 | 1.1.0 - 1.1.3 | +| 1.1.0 - 1.1.1 | 1.1.4 | 1.1.0 | 1.1.0 - 1.1.1 | 1.1.0 | 1.1.0 | 1.1.0 | +| 1.1.0 | x | 1.1.0 | 1.1.0 | 1.1.0 | 1.1.0 | 1.1.0 | + +`*` the `nym-mixnode` binary is currently one point ahead of the main platform release version + +> There are seperate changelogs for [`NymConnect`](https://github.com/nymtech/nym/blob/release/{{platform_release_version}}/nym-connect/CHANGELOG.md) and the [`Desktop Wallet`](https://github.com/nymtech/nym/blob/release/{{platform_release_version}}/nym-wallet/CHANGELOG.md). The changelog referenced below is for the core platform code. + +| Platform release changelog | +| ---------------------------------------------------------------------------------------- | +| 1.1.14 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.14/CHANGELOG.md)) | +| 1.1.13 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.13/CHANGELOG.md)) | +| 1.1.12 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.12/CHANGELOG.md)) | +| 1.1.11 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.11/CHANGELOG.md)) | +| 1.1.10 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.10/CHANGELOG.md)) | +| 1.1.9 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.9/CHANGELOG.md)) | +| 1.1.8 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.8/CHANGELOG.md)) | +| 1.1.7 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.7/CHANGELOG.md)) | +| 1.1.6 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.6/CHANGELOG.md)) | +| 1.1.5 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.5/CHANGELOG.md)) | +| 1.1.4 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.4/CHANGELOG.md)) | +| 1.1.3 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.3/CHANGELOG.md)) | +| 1.1.2 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.2/CHANGELOG.md)) | +| 1.1.1 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.1/CHANGELOG.md)) | +| 1.1.0 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.0/CHANGELOG.md)) | +| 1.0.2 ([CHANGELOG](https://github.com/nymtech/nym/blob/nym-binaries-1.0.2/CHANGELOG.md)) | +| 1.0.1 ([CHANGELOG](https://github.com/nymtech/nym/blob/nym-binaries-1.0.1/CHANGELOG.md)) | +| 1.0.0 ([CHANGELOG](https://github.com/nymtech/nym/blob/nym-binaries-1.0.0/CHANGELOG.md)) | diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index cdc72700e2..31cff54c22 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -4,7 +4,7 @@ TODO ---> # Gateways -> The Nym gateway was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index f8981fed68..0e711b6faf 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -1,6 +1,6 @@ # Mix Nodes -> The Nym mix node binary was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym mix node binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. @@ -17,7 +17,7 @@ Make sure you do the preparation listed in the [preliminary steps page](../preli ## Mix node setup -Now that you have built the [codebase](https://nymtech.net/docs/binaries/building-nym.html), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. To begin, move to `/taget/release` directory from which you run the node commands: diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 33dc3c7c90..1cfee00e9b 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -4,7 +4,7 @@ TODO: ---> # Network Requesters -> The Nym gateway was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. diff --git a/documentation/operators/src/nodes/setup-guides.md b/documentation/operators/src/nodes/setup-guides.md index b19cf07deb..37955a6549 100644 --- a/documentation/operators/src/nodes/setup-guides.md +++ b/documentation/operators/src/nodes/setup-guides.md @@ -1,13 +1,13 @@ # Node Setup Guides -To setup any type of Nym's node, start with building [Nym's platform](https://nymtech.net/docs/binaries/building-nym.html) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). +To setup any type of Nym's node, start with building [Nym's platform](../binaries/building-nym.md) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). This section contains setup guides for the following node types: * [Mix node](./mix-node-setup.md) diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 6eafb49106..1c843a4cab 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -351,7 +351,7 @@ sudo ufw status Ports `22`, `80`, and `443` are for ssh, http, and https connections respectively. The rest of the ports are documented [here](https://docs.cosmos.network/main/core/grpc_rest). -For more information about your validator's port configuration, check the [validator port reference table](https://nymtech.net/operators/binaries/maintenance.html#ports) below. +For more information about your validator's port configuration, check the [validator port reference table](./maintenance.md#ports) below. > If you are planning to use [Cockpit](https://cockpit-project.org/) on your validator server then you will have defined a different `grpc` port in your `config.toml` above: remember to open this port as well. @@ -465,15 +465,15 @@ nyxd tx staking edit-validator With above command you can specify the `gpg` key last numbers (as used in `keybase`) as well as validator details and your email for security contact. ### Automating your validator with systemd -You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#systemd) with a quick tutorial. +You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](./maintenance.md#systemd) with a quick tutorial. ### Installing and configuring nginx for HTTPS -If you want to set up a reverse proxying on the validator server to improve security and performance, using [nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.), follow the manual on the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#setup). +If you want to set up a reverse proxying on the validator server to improve security and performance, using [nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.), follow the manual on the [maintenance page](./maintenance.md#setup). ### Setting the ulimit -Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#Setting-the-ulimit) to change the `ulimit` value for validators. +Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](./maintenance.md#Setting-the-ulimit) to change the `ulimit` value for validators. ## Using your validator ### Unjailing your validator @@ -502,7 +502,7 @@ nyxd tx slashing unjail ### Upgrading your validator -To upgrade your validator, follow the steps on the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#Setting-the-ulimit). +To upgrade your validator, follow the steps on the [maintenance page](./maintenance.md#setting-the-ulimit). #### Common reasons for your validator being jailed diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index 1c738b34bb..5cb76d8e19 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,6 +1,6 @@ # Preliminary Steps -> The Nym mixnode, gateway and network requester binaries were built in the [building nym](https://nymtech.net/docs/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym mixnode, gateway and network requester binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ## Preliminary steps From 1965df05e724e6e5f472ef6e4db4f7e705cb95be Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:04:11 +0200 Subject: [PATCH 017/146] operators guide: book built --- docs/src/binaries/building-nym.html | 242 ++++++++++++ docs/src/binaries/building-nym.md | 1 + docs/src/binaries/init-and-config.html | 242 ++++++++++++ docs/src/binaries/init-and-config.md | 1 + docs/src/binaries/pre-built-binaries.html | 242 ++++++++++++ docs/src/binaries/pre-built-binaries.md | 1 + .../docs/src/binaries/building-nym.html | 350 ++++++++++++++++++ .../docs/src/binaries/init-and-config.html | 290 +++++++++++++++ .../docs/src/binaries/pre-built-binaries.html | 286 ++++++++++++++ 9 files changed, 1655 insertions(+) create mode 100644 docs/src/binaries/building-nym.html create mode 100644 docs/src/binaries/building-nym.md create mode 100644 docs/src/binaries/init-and-config.html create mode 100644 docs/src/binaries/init-and-config.md create mode 100644 docs/src/binaries/pre-built-binaries.html create mode 100644 docs/src/binaries/pre-built-binaries.md create mode 100644 documentation/docs/src/binaries/building-nym.html create mode 100644 documentation/docs/src/binaries/init-and-config.html create mode 100644 documentation/docs/src/binaries/pre-built-binaries.html diff --git a/docs/src/binaries/building-nym.html b/docs/src/binaries/building-nym.html new file mode 100644 index 0000000000..90e9c937cc --- /dev/null +++ b/docs/src/binaries/building-nym.html @@ -0,0 +1,242 @@ + + + + + + Building from Source - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Building from Source

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/docs/src/binaries/building-nym.md b/docs/src/binaries/building-nym.md new file mode 100644 index 0000000000..f195be32f9 --- /dev/null +++ b/docs/src/binaries/building-nym.md @@ -0,0 +1 @@ +# Building from Source diff --git a/docs/src/binaries/init-and-config.html b/docs/src/binaries/init-and-config.html new file mode 100644 index 0000000000..2a9390a316 --- /dev/null +++ b/docs/src/binaries/init-and-config.html @@ -0,0 +1,242 @@ + + + + + + Binary Initialisation and Configuration - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Binary Initialisation and Configuration

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/docs/src/binaries/init-and-config.md b/docs/src/binaries/init-and-config.md new file mode 100644 index 0000000000..9087d5cf00 --- /dev/null +++ b/docs/src/binaries/init-and-config.md @@ -0,0 +1 @@ +# Binary Initialisation and Configuration diff --git a/docs/src/binaries/pre-built-binaries.html b/docs/src/binaries/pre-built-binaries.html new file mode 100644 index 0000000000..a02f51d2bd --- /dev/null +++ b/docs/src/binaries/pre-built-binaries.html @@ -0,0 +1,242 @@ + + + + + + Pre-built Binaries - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Pre-built Binaries

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/docs/src/binaries/pre-built-binaries.md b/docs/src/binaries/pre-built-binaries.md new file mode 100644 index 0000000000..8c52595ce9 --- /dev/null +++ b/docs/src/binaries/pre-built-binaries.md @@ -0,0 +1 @@ +# Pre-built Binaries diff --git a/documentation/docs/src/binaries/building-nym.html b/documentation/docs/src/binaries/building-nym.html new file mode 100644 index 0000000000..2f73af4b4f --- /dev/null +++ b/documentation/docs/src/binaries/building-nym.html @@ -0,0 +1,350 @@ + + + + + + Building from Source - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Building from Source

+
+

Nym runs on Mac OS X, Linux, and Windows. All nodes except the Desktop Wallet and NymConnect on Windows should be considered experimental - it works fine if you’re an app developer but isn’t recommended for running nodes.

+
+

Building Nym

+

Nym has two main codebases:

+
    +
  • the Nym platform, written in Rust. This contains all of our code except for the validators.
  • +
  • the Nym validators, written in Go.
  • +
+
+

This page details how to build the main Nym platform code. If you want to build and run a validator, go here instead.

+
+

Prerequisites

+
    +
  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
  • +
+
apt install pkg-config build-essential libssl-dev curl jq git
+
+
    +
  • Arch/Manjaro: base-devel
  • +
+
pacman -S base-devel
+
+
    +
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git +Running the following the script installs Homebrew and the above dependencies:
  • +
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
+
    +
  • Rust & cargo >= 1.66
  • +
+

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

+

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

+

Download and build Nym binaries

+

The following commands will compile binaries into the nym/target/release directory:

+
rustup update
+git clone https://github.com/nymtech/nym.git
+cd nym
+
+git reset --hard # in case you made any changes on your branch
+git pull # in case you've checked it out before
+
+git checkout release/v1.1.22 # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks
+
+cargo build --release # build your binaries with **mainnet** configuration
+NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration
+
+

Quite a bit of stuff gets built. The key working parts are:

+ +

The repository also contains Typescript applications which aren’t built in this process. These can be built by following the instructions on their respective docs pages.

+ +
+

You cannot build from GitHub’s .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn’t a Git repository). Check the code out from github using git clone instead.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/docs/src/binaries/init-and-config.html b/documentation/docs/src/binaries/init-and-config.html new file mode 100644 index 0000000000..147c89cc2d --- /dev/null +++ b/documentation/docs/src/binaries/init-and-config.html @@ -0,0 +1,290 @@ + + + + + + Binary Initialisation and Configuration - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Binary Initialisation and Configuration

+

All Nym binaries must first be initialised with init before being run.

+

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

+

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will not overwrite existing keypairs if they are present.

+

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

+

Once you have run init, you can start your binary with the run command, usually only accompanied by the id of the binary that you specified.

+

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/docs/src/binaries/pre-built-binaries.html b/documentation/docs/src/binaries/pre-built-binaries.html new file mode 100644 index 0000000000..3497c15d85 --- /dev/null +++ b/documentation/docs/src/binaries/pre-built-binaries.html @@ -0,0 +1,286 @@ + + + + + + Pre-built Binaries - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Pre-built Binaries

+

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

+

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + From 20d51437b59750ff1ece9ee53639229183234578 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:30:07 +0200 Subject: [PATCH 018/146] reinitialized the book - simplified book.toml --- documentation/operators/.gitignore | 26 -- documentation/operators/book.toml | 120 +----- documentation/operators/mdbook-admonish.css | 352 ------------------ documentation/operators/src/faq.md | 17 - .../operators/src/nodes/gateway-setup.md | 4 - .../src/nodes/network-requester-setup.md | 4 - .../operators/src/nodes/setup-guides.md | 7 - .../operators/src/nodes/validator-setup.md | 8 - 8 files changed, 1 insertion(+), 537 deletions(-) delete mode 100644 documentation/operators/mdbook-admonish.css diff --git a/documentation/operators/.gitignore b/documentation/operators/.gitignore index e84b38bdfb..7585238efe 100644 --- a/documentation/operators/.gitignore +++ b/documentation/operators/.gitignore @@ -1,27 +1 @@ -# mdbook files book -book/* -theme/index.hbs -theme/pagetoc.css -theme/pagetoc.js -theme/* -theme - -# --------------- -# Compiled assets -# --------------- -.sass-cache -_site - -# ---------- -# Developing -# ---------- -todo.md -.vscode - -# OSX -.DS_Store - -theme/ -theme -theme/* diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 4202abc3f9..45ffb514ae 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -1,125 +1,7 @@ [book] -title = "Nym Operators Guides" +title = "Nym Operators Guide" authors = ["Max Hampshire", "serinko"] description = "Guides to setup Nym infrastructure" language = "en" multilingual = false # for the moment - ideally work on chinese, brazillian, spanish next src = "src" - -################# -# PREPROCESSORS # -################# - -# Note if changing these fields: -# - make sure you aren't running `mdbook serve` -# - change value of `turn-off = true` to `false`. This is set to `true` usually to avoid a known constant-reload bug with `mdbook serve` and this preprocessor -# - delete `./theme/` dir -# - change the preprocessor values that you want to edit -# - run `mdbook build`: this will rebuild the `./theme` directory -# - change value of `turn-off` back to `true` -[preprocessor.theme] -pagetoc = true -# some variables related (defined in theme/css/variables.css) -pagetoc-width = "13%" -content-max-width = "70%" # 82 -pagetoc-fontsize = "14.5px" -sidebar-width = "300px" -menu-bar-height = "40px" # memu-bar = the bar on the top -page-padding = "20px" -mobile-content-max-width = "98%" - -# layout -content-padding = "0 10px" -content-main-margin-left = "10%" -content-main-margin-right = "10%" -nav-chapters-max-width = "auto" -nav-chapters-min-width = "auto" -chapter-line-height = "2em" -section-line-height = "1.5em" - -# if true, never read and touch the files in theme dir: this is used to stop the looping reload issue referred to in the readme -turn-off = false - -[preprocessor.admonish] -command = "mdbook-admonish" -assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` - -# variables preprocessor: import variables into files -# https://gitlab.com/tglman/mdbook-variables/ -[preprocessor.variables.variables] -minimum_rust_version = "1.66" -# vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.22" -wallet_release_version = "v1.2.5" - - -# [preprocessor.last-changed] -# command = "mdbook-last-changed" -# renderer = ["html"] - - -# used for grabbing output of binary commands for automation -# https://github.com/FauconFan/mdbook-cmdrun -[preprocessor.cmdrun] - -# more pre-processor plugins to look into from https://github.com/rust-lang/mdBook/wiki/Third-party-plugins & https://lib.rs/keywords/mdbook-preprocessor -# mdbook-i18n - -######### -# BUILD # -######### - -[build] -build-dir = "book" # the directory where the output is placed -create-missing = true # whether or not to create missing pages -use-default-preprocessors = true # use the default preprocessors -extra-watch-dirs = [] # directories to watch for triggering builds - -########## -# OUTPUT # -########## - -[output.html] -theme = "theme" # this is the default if not explicitly set -default-theme = "coal" -preferred-dark-theme = "coal" -curly-quotes = true -# mathjax-support = false # useful if we want to pull equations in -copy-fonts = true -no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css"] #,"last-changed.css"] -additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/nym" -git-repository-icon = "fa-github" -# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" -# site-url = "/docs/" -# cname = "nymtech.net" -# input-404 = "not-found.md" # todo make custom 404 page - -[output.html.fold] -enable = true # whether or not to enable section folding -level = 0 # the depth to start folding - -# controlling rust sample code blocks -[output.html.playground] -editable = false # allows editing the source code -copyable = true # include the copy button for copying code snippets -copy-js = true # includes the JavaScript for the code editor -line-numbers = false # displays line numbers for editable code -runnable = true # displays a run button for rust code - -# options for the built in text search -[output.html.search] -enable = true # enables the search feature -limit-results = 30 # maximum number of search results -teaser-word-count = 30 # number of words used for a search result teaser -use-boolean-and = true # multiple search terms must all match -boost-title = 2 # ranking boost factor for matches in headers -boost-hierarchy = 1 # ranking boost factor for matches in page names -boost-paragraph = 1 # ranking boost factor for matches in text -expand = true # partial words will match longer terms -heading-split-level = 3 # link results to heading levels -copy-js = true # include Javascript code for search - -# [output.linkcheck] -# warning-policy = "warn" diff --git a/documentation/operators/mdbook-admonish.css b/documentation/operators/mdbook-admonish.css deleted file mode 100644 index 5e360387df..0000000000 --- a/documentation/operators/mdbook-admonish.css +++ /dev/null @@ -1,352 +0,0 @@ -@charset "UTF-8"; -:root { - --md-admonition-icon--note: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--abstract: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--info: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--tip: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--success: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--question: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--warning: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--failure: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--danger: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--bug: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--example: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--quote: - url("data:image/svg+xml;charset=utf-8,"); - --md-details-icon: - url("data:image/svg+xml;charset=utf-8,"); -} - -:is(.admonition) { - display: flow-root; - margin: 1.5625em 0; - padding: 0 1.2rem; - color: var(--fg); - page-break-inside: avoid; - background-color: var(--bg); - border: 0 solid black; - border-inline-start-width: 0.4rem; - border-radius: 0.2rem; - box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); -} -@media print { - :is(.admonition) { - box-shadow: none; - } -} -:is(.admonition) > * { - box-sizing: border-box; -} -:is(.admonition) :is(.admonition) { - margin-top: 1em; - margin-bottom: 1em; -} -:is(.admonition) > .tabbed-set:only-child { - margin-top: 0; -} -html :is(.admonition) > :last-child { - margin-bottom: 1.2rem; -} - -a.admonition-anchor-link { - display: none; - position: absolute; - left: -1.2rem; - padding-right: 1rem; -} -a.admonition-anchor-link:link, a.admonition-anchor-link:visited { - color: var(--fg); -} -a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { - text-decoration: none; -} -a.admonition-anchor-link::before { - content: "§"; -} - -:is(.admonition-title, summary) { - position: relative; - margin-block: 0; - margin-inline: -1.6rem -1.2rem; - padding-block: 0.8rem; - padding-inline: 4.4rem 1.2rem; - font-weight: 700; - background-color: rgba(68, 138, 255, 0.1); - display: flex; -} -:is(.admonition-title, summary) p { - margin: 0; -} -html :is(.admonition-title, summary):last-child { - margin-bottom: 0; -} -:is(.admonition-title, summary)::before { - position: absolute; - top: 0.625em; - inset-inline-start: 1.6rem; - width: 2rem; - height: 2rem; - background-color: #448aff; - mask-image: url('data:image/svg+xml;charset=utf-8,'); - -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-size: contain; - content: ""; -} -:is(.admonition-title, summary):hover a.admonition-anchor-link { - display: initial; -} - -details.admonition > summary.admonition-title::after { - position: absolute; - top: 0.625em; - inset-inline-end: 1.6rem; - height: 2rem; - width: 2rem; - background-color: currentcolor; - mask-image: var(--md-details-icon); - -webkit-mask-image: var(--md-details-icon); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-size: contain; - content: ""; - transform: rotate(0deg); - transition: transform 0.25s; -} -details[open].admonition > summary.admonition-title::after { - transform: rotate(90deg); -} - -:is(.admonition):is(.note) { - border-color: #448aff; -} - -:is(.note) > :is(.admonition-title, summary) { - background-color: rgba(68, 138, 255, 0.1); -} -:is(.note) > :is(.admonition-title, summary)::before { - background-color: #448aff; - mask-image: var(--md-admonition-icon--note); - -webkit-mask-image: var(--md-admonition-icon--note); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.abstract, .summary, .tldr) { - border-color: #00b0ff; -} - -:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { - background-color: rgba(0, 176, 255, 0.1); -} -:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { - background-color: #00b0ff; - mask-image: var(--md-admonition-icon--abstract); - -webkit-mask-image: var(--md-admonition-icon--abstract); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.info, .todo) { - border-color: #00b8d4; -} - -:is(.info, .todo) > :is(.admonition-title, summary) { - background-color: rgba(0, 184, 212, 0.1); -} -:is(.info, .todo) > :is(.admonition-title, summary)::before { - background-color: #00b8d4; - mask-image: var(--md-admonition-icon--info); - -webkit-mask-image: var(--md-admonition-icon--info); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.tip, .hint, .important) { - border-color: #00bfa5; -} - -:is(.tip, .hint, .important) > :is(.admonition-title, summary) { - background-color: rgba(0, 191, 165, 0.1); -} -:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { - background-color: #00bfa5; - mask-image: var(--md-admonition-icon--tip); - -webkit-mask-image: var(--md-admonition-icon--tip); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.success, .check, .done) { - border-color: #00c853; -} - -:is(.success, .check, .done) > :is(.admonition-title, summary) { - background-color: rgba(0, 200, 83, 0.1); -} -:is(.success, .check, .done) > :is(.admonition-title, summary)::before { - background-color: #00c853; - mask-image: var(--md-admonition-icon--success); - -webkit-mask-image: var(--md-admonition-icon--success); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.question, .help, .faq) { - border-color: #64dd17; -} - -:is(.question, .help, .faq) > :is(.admonition-title, summary) { - background-color: rgba(100, 221, 23, 0.1); -} -:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { - background-color: #64dd17; - mask-image: var(--md-admonition-icon--question); - -webkit-mask-image: var(--md-admonition-icon--question); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.warning, .caution, .attention) { - border-color: #ff9100; -} - -:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { - background-color: rgba(255, 145, 0, 0.1); -} -:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { - background-color: #ff9100; - mask-image: var(--md-admonition-icon--warning); - -webkit-mask-image: var(--md-admonition-icon--warning); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.failure, .fail, .missing) { - border-color: #ff5252; -} - -:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { - background-color: rgba(255, 82, 82, 0.1); -} -:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { - background-color: #ff5252; - mask-image: var(--md-admonition-icon--failure); - -webkit-mask-image: var(--md-admonition-icon--failure); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.danger, .error) { - border-color: #ff1744; -} - -:is(.danger, .error) > :is(.admonition-title, summary) { - background-color: rgba(255, 23, 68, 0.1); -} -:is(.danger, .error) > :is(.admonition-title, summary)::before { - background-color: #ff1744; - mask-image: var(--md-admonition-icon--danger); - -webkit-mask-image: var(--md-admonition-icon--danger); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.bug) { - border-color: #f50057; -} - -:is(.bug) > :is(.admonition-title, summary) { - background-color: rgba(245, 0, 87, 0.1); -} -:is(.bug) > :is(.admonition-title, summary)::before { - background-color: #f50057; - mask-image: var(--md-admonition-icon--bug); - -webkit-mask-image: var(--md-admonition-icon--bug); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.example) { - border-color: #7c4dff; -} - -:is(.example) > :is(.admonition-title, summary) { - background-color: rgba(124, 77, 255, 0.1); -} -:is(.example) > :is(.admonition-title, summary)::before { - background-color: #7c4dff; - mask-image: var(--md-admonition-icon--example); - -webkit-mask-image: var(--md-admonition-icon--example); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.quote, .cite) { - border-color: #9e9e9e; -} - -:is(.quote, .cite) > :is(.admonition-title, summary) { - background-color: rgba(158, 158, 158, 0.1); -} -:is(.quote, .cite) > :is(.admonition-title, summary)::before { - background-color: #9e9e9e; - mask-image: var(--md-admonition-icon--quote); - -webkit-mask-image: var(--md-admonition-icon--quote); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -.navy :is(.admonition) { - background-color: var(--sidebar-bg); -} - -.ayu :is(.admonition), .coal :is(.admonition) { - background-color: var(--theme-hover); -} - -.rust :is(.admonition) { - background-color: var(--sidebar-bg); - color: var(--sidebar-fg); -} -.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { - color: var(--sidebar-fg); -} diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index faefd70b18..bc3c210352 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -1,20 +1,3 @@ - # Frequently Asked Questions ## Mixnet nodes diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 31cff54c22..026e7afde0 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -1,7 +1,3 @@ - # Gateways > The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 1cfee00e9b..049b139de6 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -1,7 +1,3 @@ - # Network Requesters > The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. diff --git a/documentation/operators/src/nodes/setup-guides.md b/documentation/operators/src/nodes/setup-guides.md index 37955a6549..ca86dd99f4 100644 --- a/documentation/operators/src/nodes/setup-guides.md +++ b/documentation/operators/src/nodes/setup-guides.md @@ -1,10 +1,3 @@ - # Node Setup Guides To setup any type of Nym's node, start with building [Nym's platform](../binaries/building-nym.md) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 1c843a4cab..9e233808d7 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -1,11 +1,3 @@ - # Validators > Nym has two main codebases: From 7ac3bb10cbcfbaf6b724d150fe792f6237c6e074 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:43:57 +0200 Subject: [PATCH 019/146] reinit the book, delete *.html in /src --- .../operators/src/binaries/building-nym.html | 350 ------------------ .../src/binaries/init-and-config.html | 290 --------------- .../src/binaries/pre-built-binaries.html | 286 -------------- 3 files changed, 926 deletions(-) delete mode 100644 documentation/operators/src/binaries/building-nym.html delete mode 100644 documentation/operators/src/binaries/init-and-config.html delete mode 100644 documentation/operators/src/binaries/pre-built-binaries.html diff --git a/documentation/operators/src/binaries/building-nym.html b/documentation/operators/src/binaries/building-nym.html deleted file mode 100644 index 2f73af4b4f..0000000000 --- a/documentation/operators/src/binaries/building-nym.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Building from Source - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Building from Source

-
-

Nym runs on Mac OS X, Linux, and Windows. All nodes except the Desktop Wallet and NymConnect on Windows should be considered experimental - it works fine if you’re an app developer but isn’t recommended for running nodes.

-
-

Building Nym

-

Nym has two main codebases:

-
    -
  • the Nym platform, written in Rust. This contains all of our code except for the validators.
  • -
  • the Nym validators, written in Go.
  • -
-
-

This page details how to build the main Nym platform code. If you want to build and run a validator, go here instead.

-
-

Prerequisites

-
    -
  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
  • -
-
apt install pkg-config build-essential libssl-dev curl jq git
-
-
    -
  • Arch/Manjaro: base-devel
  • -
-
pacman -S base-devel
-
-
    -
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git -Running the following the script installs Homebrew and the above dependencies:
  • -
-
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
-
-
    -
  • Rust & cargo >= 1.66
  • -
-

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

-

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

-

Download and build Nym binaries

-

The following commands will compile binaries into the nym/target/release directory:

-
rustup update
-git clone https://github.com/nymtech/nym.git
-cd nym
-
-git reset --hard # in case you made any changes on your branch
-git pull # in case you've checked it out before
-
-git checkout release/v1.1.22 # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks
-
-cargo build --release # build your binaries with **mainnet** configuration
-NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration
-
-

Quite a bit of stuff gets built. The key working parts are:

- -

The repository also contains Typescript applications which aren’t built in this process. These can be built by following the instructions on their respective docs pages.

- -
-

You cannot build from GitHub’s .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn’t a Git repository). Check the code out from github using git clone instead.

-
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/operators/src/binaries/init-and-config.html b/documentation/operators/src/binaries/init-and-config.html deleted file mode 100644 index 147c89cc2d..0000000000 --- a/documentation/operators/src/binaries/init-and-config.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - Binary Initialisation and Configuration - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Binary Initialisation and Configuration

-

All Nym binaries must first be initialised with init before being run.

-

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

-

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will not overwrite existing keypairs if they are present.

-

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

-

Once you have run init, you can start your binary with the run command, usually only accompanied by the id of the binary that you specified.

-

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/operators/src/binaries/pre-built-binaries.html b/documentation/operators/src/binaries/pre-built-binaries.html deleted file mode 100644 index 3497c15d85..0000000000 --- a/documentation/operators/src/binaries/pre-built-binaries.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - Pre-built Binaries - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Pre-built Binaries

-

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

-

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - From 974cee1f22b2d9f04463561c93b0531dbcd181a7 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:37:12 +0200 Subject: [PATCH 020/146] operators: book built, no {comments} left, cmdrun and admonish not working --- documentation/operators/book.toml | 118 + documentation/operators/last-changed.css | 6 + documentation/operators/mdbook-admonish.css | 352 ++ documentation/operators/theme/css/chrome.css | 538 +++ documentation/operators/theme/css/general.css | 203 + .../operators/theme/css/variables.css | 3257 +++++++++++++++++ documentation/operators/theme/index.hbs | 1063 ++++++ documentation/operators/theme/pagetoc.css | 47 + documentation/operators/theme/pagetoc.js | 68 + 9 files changed, 5652 insertions(+) create mode 100644 documentation/operators/last-changed.css create mode 100644 documentation/operators/mdbook-admonish.css create mode 100644 documentation/operators/theme/css/chrome.css create mode 100644 documentation/operators/theme/css/general.css create mode 100644 documentation/operators/theme/css/variables.css create mode 100644 documentation/operators/theme/index.hbs create mode 100644 documentation/operators/theme/pagetoc.css create mode 100644 documentation/operators/theme/pagetoc.js diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 45ffb514ae..3a0a9f722b 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -5,3 +5,121 @@ description = "Guides to setup Nym infrastructure" language = "en" multilingual = false # for the moment - ideally work on chinese, brazillian, spanish next src = "src" + +################# +# PREPROCESSORS # +################# + +# Note if changing these fields: +# - make sure you aren't running `mdbook serve` +# - change value of `turn-off = true` to `false`. This is set to `true` usually to avoid a known constant-reload bug with `mdbook serve` and this preprocessor +# - delete `./theme/` dir +# - change the preprocessor values that you want to edit +# - run `mdbook build`: this will rebuild the `./theme` directory +# - change value of `turn-off` back to `true` +[preprocessor.theme] +pagetoc = true +# some variables related (defined in theme/css/variables.css) +pagetoc-width = "13%" +content-max-width = "70%" # 82 +pagetoc-fontsize = "14.5px" +sidebar-width = "300px" +menu-bar-height = "40px" # memu-bar = the bar on the top +page-padding = "20px" +mobile-content-max-width = "98%" + +# layout +content-padding = "0 10px" +content-main-margin-left = "10%" +content-main-margin-right = "10%" +nav-chapters-max-width = "auto" +nav-chapters-min-width = "auto" +chapter-line-height = "2em" +section-line-height = "1.5em" + +# if true, never read and touch the files in theme dir: this is used to stop the looping reload issue referred to in the readme +turn-off = false + +[preprocessor.admonish] +command = "mdbook-admonish" +assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` + +# variables preprocessor: import variables into files +# https://gitlab.com/tglman/mdbook-variables/ +[preprocessor.variables.variables] +minimum_rust_version = "1.66" +# vars for links: TODO think on how to streamline updating +platform_release_version = "v1.1.22" +wallet_release_version = "v1.2.5" + + +# [preprocessor.last-changed] +# command = "mdbook-last-changed" +# renderer = ["html"] + + +# used for grabbing output of binary commands for automation +# https://github.com/FauconFan/mdbook-cmdrun +[preprocessor.cmdrun] + +# more pre-processor plugins to look into from https://github.com/rust-lang/mdBook/wiki/Third-party-plugins & https://lib.rs/keywords/mdbook-preprocessor +# mdbook-i18n + +######### +# BUILD # +######### + +[build] +build-dir = "book" # the directory where the output is placed +create-missing = true # whether or not to create missing pages +use-default-preprocessors = true # use the default preprocessors +extra-watch-dirs = [] # directories to watch for triggering builds + +########## +# OUTPUT # +########## + +[output.html] +theme = "theme" # this is the default if not explicitly set +default-theme = "coal" +preferred-dark-theme = "coal" +curly-quotes = true +# mathjax-support = false # useful if we want to pull equations in +copy-fonts = true +no-section-label = false +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./last-changed.css"] +additional-js = ["theme/pagetoc.js"] +git-repository-url = "https://github.com/nymtech/nym" +git-repository-icon = "fa-github" +# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" +# site-url = "/docs/" +# cname = "nymtech.net" +# input-404 = "not-found.md" # todo make custom 404 page + +[output.html.fold] +enable = true # whether or not to enable section folding +level = 0 # the depth to start folding + +# controlling rust sample code blocks +[output.html.playground] +editable = false # allows editing the source code +copyable = true # include the copy button for copying code snippets +copy-js = true # includes the JavaScript for the code editor +line-numbers = false # displays line numbers for editable code +runnable = true # displays a run button for rust code + +# options for the built in text search +[output.html.search] +enable = true # enables the search feature +limit-results = 30 # maximum number of search results +teaser-word-count = 30 # number of words used for a search result teaser +use-boolean-and = true # multiple search terms must all match +boost-title = 2 # ranking boost factor for matches in headers +boost-hierarchy = 1 # ranking boost factor for matches in page names +boost-paragraph = 1 # ranking boost factor for matches in text +expand = true # partial words will match longer terms +heading-split-level = 3 # link results to heading levels +copy-js = true # include Javascript code for search + +# [output.linkcheck] +# warning-policy = "warn" diff --git a/documentation/operators/last-changed.css b/documentation/operators/last-changed.css new file mode 100644 index 0000000000..0c4228de32 --- /dev/null +++ b/documentation/operators/last-changed.css @@ -0,0 +1,6 @@ +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 5px 0; + } \ No newline at end of file diff --git a/documentation/operators/mdbook-admonish.css b/documentation/operators/mdbook-admonish.css new file mode 100644 index 0000000000..5e360387df --- /dev/null +++ b/documentation/operators/mdbook-admonish.css @@ -0,0 +1,352 @@ +@charset "UTF-8"; +:root { + --md-admonition-icon--note: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--abstract: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--info: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--tip: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--success: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--question: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--warning: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--failure: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--danger: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--bug: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--example: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--quote: + url("data:image/svg+xml;charset=utf-8,"); + --md-details-icon: + url("data:image/svg+xml;charset=utf-8,"); +} + +:is(.admonition) { + display: flow-root; + margin: 1.5625em 0; + padding: 0 1.2rem; + color: var(--fg); + page-break-inside: avoid; + background-color: var(--bg); + border: 0 solid black; + border-inline-start-width: 0.4rem; + border-radius: 0.2rem; + box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); +} +@media print { + :is(.admonition) { + box-shadow: none; + } +} +:is(.admonition) > * { + box-sizing: border-box; +} +:is(.admonition) :is(.admonition) { + margin-top: 1em; + margin-bottom: 1em; +} +:is(.admonition) > .tabbed-set:only-child { + margin-top: 0; +} +html :is(.admonition) > :last-child { + margin-bottom: 1.2rem; +} + +a.admonition-anchor-link { + display: none; + position: absolute; + left: -1.2rem; + padding-right: 1rem; +} +a.admonition-anchor-link:link, a.admonition-anchor-link:visited { + color: var(--fg); +} +a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { + text-decoration: none; +} +a.admonition-anchor-link::before { + content: "§"; +} + +:is(.admonition-title, summary) { + position: relative; + margin-block: 0; + margin-inline: -1.6rem -1.2rem; + padding-block: 0.8rem; + padding-inline: 4.4rem 1.2rem; + font-weight: 700; + background-color: rgba(68, 138, 255, 0.1); + display: flex; +} +:is(.admonition-title, summary) p { + margin: 0; +} +html :is(.admonition-title, summary):last-child { + margin-bottom: 0; +} +:is(.admonition-title, summary)::before { + position: absolute; + top: 0.625em; + inset-inline-start: 1.6rem; + width: 2rem; + height: 2rem; + background-color: #448aff; + mask-image: url('data:image/svg+xml;charset=utf-8,'); + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; +} +:is(.admonition-title, summary):hover a.admonition-anchor-link { + display: initial; +} + +details.admonition > summary.admonition-title::after { + position: absolute; + top: 0.625em; + inset-inline-end: 1.6rem; + height: 2rem; + width: 2rem; + background-color: currentcolor; + mask-image: var(--md-details-icon); + -webkit-mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; + transform: rotate(0deg); + transition: transform 0.25s; +} +details[open].admonition > summary.admonition-title::after { + transform: rotate(90deg); +} + +:is(.admonition):is(.note) { + border-color: #448aff; +} + +:is(.note) > :is(.admonition-title, summary) { + background-color: rgba(68, 138, 255, 0.1); +} +:is(.note) > :is(.admonition-title, summary)::before { + background-color: #448aff; + mask-image: var(--md-admonition-icon--note); + -webkit-mask-image: var(--md-admonition-icon--note); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.abstract, .summary, .tldr) { + border-color: #00b0ff; +} + +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { + background-color: rgba(0, 176, 255, 0.1); +} +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { + background-color: #00b0ff; + mask-image: var(--md-admonition-icon--abstract); + -webkit-mask-image: var(--md-admonition-icon--abstract); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.info, .todo) { + border-color: #00b8d4; +} + +:is(.info, .todo) > :is(.admonition-title, summary) { + background-color: rgba(0, 184, 212, 0.1); +} +:is(.info, .todo) > :is(.admonition-title, summary)::before { + background-color: #00b8d4; + mask-image: var(--md-admonition-icon--info); + -webkit-mask-image: var(--md-admonition-icon--info); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.tip, .hint, .important) { + border-color: #00bfa5; +} + +:is(.tip, .hint, .important) > :is(.admonition-title, summary) { + background-color: rgba(0, 191, 165, 0.1); +} +:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { + background-color: #00bfa5; + mask-image: var(--md-admonition-icon--tip); + -webkit-mask-image: var(--md-admonition-icon--tip); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.success, .check, .done) { + border-color: #00c853; +} + +:is(.success, .check, .done) > :is(.admonition-title, summary) { + background-color: rgba(0, 200, 83, 0.1); +} +:is(.success, .check, .done) > :is(.admonition-title, summary)::before { + background-color: #00c853; + mask-image: var(--md-admonition-icon--success); + -webkit-mask-image: var(--md-admonition-icon--success); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.question, .help, .faq) { + border-color: #64dd17; +} + +:is(.question, .help, .faq) > :is(.admonition-title, summary) { + background-color: rgba(100, 221, 23, 0.1); +} +:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { + background-color: #64dd17; + mask-image: var(--md-admonition-icon--question); + -webkit-mask-image: var(--md-admonition-icon--question); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.warning, .caution, .attention) { + border-color: #ff9100; +} + +:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { + background-color: rgba(255, 145, 0, 0.1); +} +:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { + background-color: #ff9100; + mask-image: var(--md-admonition-icon--warning); + -webkit-mask-image: var(--md-admonition-icon--warning); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.failure, .fail, .missing) { + border-color: #ff5252; +} + +:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { + background-color: rgba(255, 82, 82, 0.1); +} +:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { + background-color: #ff5252; + mask-image: var(--md-admonition-icon--failure); + -webkit-mask-image: var(--md-admonition-icon--failure); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.danger, .error) { + border-color: #ff1744; +} + +:is(.danger, .error) > :is(.admonition-title, summary) { + background-color: rgba(255, 23, 68, 0.1); +} +:is(.danger, .error) > :is(.admonition-title, summary)::before { + background-color: #ff1744; + mask-image: var(--md-admonition-icon--danger); + -webkit-mask-image: var(--md-admonition-icon--danger); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.bug) { + border-color: #f50057; +} + +:is(.bug) > :is(.admonition-title, summary) { + background-color: rgba(245, 0, 87, 0.1); +} +:is(.bug) > :is(.admonition-title, summary)::before { + background-color: #f50057; + mask-image: var(--md-admonition-icon--bug); + -webkit-mask-image: var(--md-admonition-icon--bug); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.example) { + border-color: #7c4dff; +} + +:is(.example) > :is(.admonition-title, summary) { + background-color: rgba(124, 77, 255, 0.1); +} +:is(.example) > :is(.admonition-title, summary)::before { + background-color: #7c4dff; + mask-image: var(--md-admonition-icon--example); + -webkit-mask-image: var(--md-admonition-icon--example); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.quote, .cite) { + border-color: #9e9e9e; +} + +:is(.quote, .cite) > :is(.admonition-title, summary) { + background-color: rgba(158, 158, 158, 0.1); +} +:is(.quote, .cite) > :is(.admonition-title, summary)::before { + background-color: #9e9e9e; + mask-image: var(--md-admonition-icon--quote); + -webkit-mask-image: var(--md-admonition-icon--quote); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +.navy :is(.admonition) { + background-color: var(--sidebar-bg); +} + +.ayu :is(.admonition), .coal :is(.admonition) { + background-color: var(--theme-hover); +} + +.rust :is(.admonition) { + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { + color: var(--sidebar-fg); +} diff --git a/documentation/operators/theme/css/chrome.css b/documentation/operators/theme/css/chrome.css new file mode 100644 index 0000000000..febd1d40a6 --- /dev/null +++ b/documentation/operators/theme/css/chrome.css @@ -0,0 +1,538 @@ +/* CSS for UI elements (a.k.a. chrome) */ + +@import 'variables.css'; + +::-webkit-scrollbar { + background: var(--bg); +} +::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} +html { + scrollbar-color: var(--scrollbar) var(--bg); +} +#searchresults a, +.content a:link, +a:visited, +a > .hljs { + color: var(--links); +} + +/* Menu Bar */ + +#menu-bar, +#menu-bar-hover-placeholder { + z-index: 101; + margin: auto calc(0px - var(--page-padding)); +} +#menu-bar { + position: relative; + display: flex; + flex-wrap: wrap; + background-color: var(--bg); + border-bottom-color: var(--bg); + border-bottom-width: 1px; + border-bottom-style: solid; +} +#menu-bar.sticky, +.js #menu-bar-hover-placeholder:hover + #menu-bar, +.js #menu-bar:hover, +.js.sidebar-visible #menu-bar { + position: -webkit-sticky; + position: sticky; + top: 0 !important; +} +#menu-bar-hover-placeholder { + position: sticky; + position: -webkit-sticky; + top: 0; + height: var(--menu-bar-height); +} +#menu-bar.bordered { + border-bottom-color: var(--table-border-color); +} +#menu-bar i, #menu-bar .icon-button { + position: relative; + padding: 0 8px; + z-index: 10; + line-height: var(--menu-bar-height); + cursor: pointer; + transition: color 0.5s; +} +@media only screen and (max-width: 420px) { + #menu-bar i, #menu-bar .icon-button { + padding: 0 5px; + } +} + +.icon-button { + border: none; + background: none; + padding: 0; + color: inherit; +} +.icon-button i { + margin: 0; +} + +.right-buttons { + margin: 0 15px; +} +.right-buttons a { + text-decoration: none; +} + +.left-buttons { + display: flex; + margin: 0 5px; +} +.no-js .left-buttons { + display: none; +} + +.menu-title { + display: inline-block; + font-weight: 200; + font-size: 2.4rem; + line-height: var(--menu-bar-height); + text-align: center; + margin: 0; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.js .menu-title { + cursor: pointer; +} + +.menu-bar, +.menu-bar:visited, +.nav-chapters, +.nav-chapters:visited, +.mobile-nav-chapters, +.mobile-nav-chapters:visited, +.menu-bar .icon-button, +.menu-bar a i { + color: var(--icons); +} + +.menu-bar i:hover, +.menu-bar .icon-button:hover, +.nav-chapters:hover, +.mobile-nav-chapters i:hover { + color: var(--icons-hover); +} + +/* Nav Icons */ + +.nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + + position: fixed; + top: 0; + bottom: 0; + margin: 0; + max-width: auto; + min-width: auto; + + display: flex; + justify-content: center; + align-content: center; + flex-direction: column; + + transition: color 0.5s, background-color 0.5s; +} + +.nav-chapters:hover { + text-decoration: none; + background-color: var(--theme-hover); + transition: background-color 0.15s, color 0.15s; +} + +.nav-wrapper { + margin-top: 50px; + display: none; +} + +.mobile-nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + width: 90px; + border-radius: 5px; + background-color: var(--sidebar-bg); +} + +.previous { + float: left; +} + +.next { + float: right; + right: var(--page-padding); +} + +@media only screen and (max-width: 1080px) { + .nav-wide-wrapper { display: none; } + .nav-wrapper { display: block; } +} + +@media only screen and (max-width: 1380px) { + .sidebar-visible .nav-wide-wrapper { display: none; } + .sidebar-visible .nav-wrapper { display: block; } +} + +/* Inline code */ + +:not(pre) > .hljs { + display: inline; + padding: 0.1em 0.3em; + border-radius: 3px; +} + +:not(pre):not(a) > .hljs { + color: var(--inline-code-color); + overflow-x: initial; +} + +a:hover > .hljs { + text-decoration: underline; +} + +pre { + position: relative; +} +pre > .buttons { + position: absolute; + z-index: 100; + right: 0px; + top: 2px; + margin: 0px; + padding: 2px 0px; + + color: var(--sidebar-fg); + cursor: pointer; + visibility: hidden; + opacity: 0; + transition: visibility 0.1s linear, opacity 0.1s linear; +} +pre:hover > .buttons { + visibility: visible; + opacity: 1 +} +pre > .buttons :hover { + color: var(--sidebar-active); + border-color: var(--icons-hover); + background-color: var(--theme-hover); +} +pre > .buttons i { + margin-left: 8px; +} +pre > .buttons button { + cursor: inherit; + margin: 0px 5px; + padding: 3px 5px; + font-size: 14px; + + border-style: solid; + border-width: 1px; + border-radius: 4px; + border-color: var(--icons); + background-color: var(--theme-popup-bg); + transition: 100ms; + transition-property: color,border-color,background-color; + color: var(--icons); +} +@media (pointer: coarse) { + pre > .buttons button { + /* On mobile, make it easier to tap buttons. */ + padding: 0.3rem 1rem; + } +} +pre > code { + padding: 1rem; +} + +/* FIXME: ACE editors overlap their buttons because ACE does absolute + positioning within the code block which breaks padding. The only solution I + can think of is to move the padding to the outer pre tag (or insert a div + wrapper), but that would require fixing a whole bunch of CSS rules. +*/ +.hljs.ace_editor { + padding: 0rem 0rem; +} + +pre > .result { + margin-top: 10px; +} + +/* Search */ + +#searchresults a { + text-decoration: none; +} + +mark { + border-radius: 2px; + padding: 0 3px 1px 3px; + margin: 0 -3px -1px -3px; + background-color: var(--search-mark-bg); + transition: background-color 300ms linear; + cursor: pointer; +} + +mark.fade-out { + background-color: rgba(0,0,0,0) !important; + cursor: auto; +} + +.searchbar-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); +} + +#searchbar { + width: 100%; + margin: 5px auto 0px auto; + padding: 10px 16px; + transition: box-shadow 300ms ease-in-out; + border: 1px solid var(--searchbar-border-color); + border-radius: 3px; + background-color: var(--searchbar-bg); + color: var(--searchbar-fg); +} +#searchbar:focus, +#searchbar.active { + box-shadow: 0 0 3px var(--searchbar-shadow-color); +} + +.searchresults-header { + font-weight: bold; + font-size: 1em; + padding: 18px 0 0 5px; + color: var(--searchresults-header-fg); +} + +.searchresults-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); + border-bottom: 1px dashed var(--searchresults-border-color); +} + +ul#searchresults { + list-style: none; + padding-left: 20px; +} +ul#searchresults li { + margin: 10px 0px; + padding: 2px; + border-radius: 2px; +} +ul#searchresults li.focus { + background-color: var(--searchresults-li-bg); +} +ul#searchresults span.teaser { + display: block; + clear: both; + margin: 5px 0 0 20px; + font-size: 0.8em; +} +ul#searchresults span.teaser em { + font-weight: bold; + font-style: normal; +} + +/* Sidebar */ + +.sidebar { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: var(--sidebar-width); + font-size: 1em; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; + overscroll-behavior-y: contain; + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.sidebar-resizing { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} +.js:not(.sidebar-resizing) .sidebar { + transition: transform 0.3s; /* Animation: slide away */ +} +.sidebar code { + line-height: 2em; +} +.sidebar .sidebar-scrollbox { + overflow-y: auto; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + padding: 10px 10px; +} +.sidebar .sidebar-resize-handle { + position: absolute; + cursor: col-resize; + width: 0; + right: 0; + top: 0; + bottom: 0; +} +.js .sidebar .sidebar-resize-handle { + cursor: col-resize; + width: 5px; +} +.sidebar-hidden .sidebar { + transform: translateX(calc(0px - var(--sidebar-width))); +} +.sidebar::-webkit-scrollbar { + background: var(--sidebar-bg); +} +.sidebar::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} + +.sidebar-visible .page-wrapper { + transform: translateX(var(--sidebar-width)); +} +@media only screen and (min-width: 620px) { + .sidebar-visible .page-wrapper { + transform: none; + margin-left: var(--sidebar-width); + } +} + +.chapter { + list-style: none outside none; + padding-left: 0; + line-height: 2em; +} + +.chapter ol { + width: 100%; +} + +.chapter li { + display: flex; + color: var(--sidebar-non-existant); +} +.chapter li a { + display: block; + padding: 0; + text-decoration: none; + color: var(--sidebar-fg); +} + +.chapter li a:hover { + color: var(--sidebar-active); +} + +.chapter li a.active { + color: var(--sidebar-active); +} + +.chapter li > a.toggle { + cursor: pointer; + display: block; + margin-left: auto; + padding: 0 10px; + user-select: none; + opacity: 0.68; +} + +.chapter li > a.toggle div { + transition: transform 0.5s; +} + +/* collapse the section */ +.chapter li:not(.expanded) + li > ol { + display: none; +} + +.chapter li.chapter-item { + line-height: 1.5em; + margin-top: 0.6em; +} + +.chapter li.expanded > a.toggle div { + transform: rotate(90deg); +} + +.spacer { + width: 100%; + height: 3px; + margin: 5px 0px; +} +.chapter .spacer { + background-color: var(--sidebar-spacer); +} + +@media (-moz-touch-enabled: 1), (pointer: coarse) { + .chapter li a { padding: 5px 0; } + .spacer { margin: 10px 0; } +} + +.section { + list-style: none outside none; + padding-left: 20px; + line-height: 1.5em; +} + +/* Theme Menu Popup */ + +.theme-popup { + position: absolute; + left: 10px; + top: var(--menu-bar-height); + z-index: 1000; + border-radius: 4px; + font-size: 0.7em; + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); + margin: 0; + padding: 0; + list-style: none; + display: none; + /* Don't let the children's background extend past the rounded corners. */ + overflow: hidden; +} +.theme-popup .default { + color: var(--icons); +} +.theme-popup .theme { + width: 100%; + border: 0; + margin: 0; + padding: 2px 20px; + line-height: 25px; + white-space: nowrap; + text-align: left; + cursor: pointer; + color: inherit; + background: inherit; + font-size: inherit; +} +.theme-popup .theme:hover { + background-color: var(--theme-hover); +} + +.theme-selected::before { + display: inline-block; + content: "✓"; + margin-left: -14px; + width: 14px; +} diff --git a/documentation/operators/theme/css/general.css b/documentation/operators/theme/css/general.css new file mode 100644 index 0000000000..a06db43965 --- /dev/null +++ b/documentation/operators/theme/css/general.css @@ -0,0 +1,203 @@ +/* Base styles and content styles */ + +@import 'variables.css'; + +:root { + /* Browser default font-size is 16px, this way 1 rem = 10px */ + font-size: 70%; +} + +html { + font-family: "Open Sans", sans-serif; + color: var(--fg); + background-color: var(--bg); + text-size-adjust: none; + -webkit-text-size-adjust: none; +} + +body { + margin: 0; + font-size: 1.5rem; + overflow-x: hidden; +} + +code { + font-family: var(--mono-font) !important; + font-size: 0.9em; +} + +/* make long words/inline code not x overflow */ +main { + overflow-wrap: break-word; +} + +/* make wide tables scroll if they overflow */ +.table-wrapper { + overflow-x: auto; +} + +/* Don't change font size in headers. */ +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + font-size: unset; +} + +.left { float: left; } +.right { float: right; } +.boring { opacity: 0.6; } +.hide-boring .boring { display: none; } +.hidden { display: none !important; } + +h2, h3 { margin-top: 2.5em; } +h4, h5 { margin-top: 2em; } + +.header + .header h3, +.header + .header h4, +.header + .header h5 { + margin-top: 1em; +} + +h1:target::before, +h2:target::before, +h3:target::before, +h4:target::before, +h5:target::before, +h6:target::before { + display: inline-block; + content: "»"; + margin-left: -30px; + width: 30px; +} + +/* This is broken on Safari as of version 14, but is fixed + in Safari Technology Preview 117 which I think will be Safari 14.2. + https://bugs.webkit.org/show_bug.cgi?id=218076 +*/ +:target { + scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); +} + +.page { + outline: 0; + padding: 0 var(--page-padding); + margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ +} +.page-wrapper { + box-sizing: border-box; +} +.js:not(.sidebar-resizing) .page-wrapper { + transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ +} + +.content { + overflow-y: auto; + padding: 0 10px; +} +.content main { + margin-left: 10%; + margin-right: 10%; + max-width: var(--content-max-width); +} +.content p { line-height: 1.45em; } +.content ol { line-height: 1.45em; } +.content ul { line-height: 1.45em; } +.content a { text-decoration: none; } +.content a:hover { text-decoration: underline; } +.content img, .content video { max-width: 100%; } +.content .header:link, +.content .header:visited { + color: var(--fg); +} +.content .header:link, +.content .header:visited:hover { + text-decoration: none; +} + +table { + margin: 0 auto; + border-collapse: collapse; +} +table td { + padding: 3px 20px; + border: 1px var(--table-border-color) solid; +} +table thead { + background: var(--table-header-bg); +} +table thead td { + font-weight: 700; + border: none; +} +table thead th { + padding: 3px 20px; +} +table thead tr { + border: 1px var(--table-header-bg) solid; +} +/* Alternate background colors for rows */ +table tbody tr:nth-child(2n) { + background: var(--table-alternate-bg); +} + + +blockquote { + margin: 20px 0; + padding: 0 20px; + color: var(--fg); + background-color: var(--quote-bg); + border-top: .1em solid var(--quote-border); + border-bottom: .1em solid var(--quote-border); +} + +kbd { + background-color: var(--table-border-color); + border-radius: 4px; + border: solid 1px var(--theme-popup-border); + box-shadow: inset 0 -1px 0 var(--theme-hover); + display: inline-block; + font-size: var(--code-font-size); + font-family: var(--mono-font); + line-height: 10px; + padding: 4px 5px; + vertical-align: middle; +} + +:not(.footnote-definition) + .footnote-definition, +.footnote-definition + :not(.footnote-definition) { + margin-top: 2em; +} +.footnote-definition { + font-size: 0.9em; + margin: 0.5em 0; +} +.footnote-definition p { + display: inline; +} + +.tooltiptext { + position: absolute; + visibility: hidden; + color: #fff; + background-color: #333; + transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ + left: -8px; /* Half of the width of the icon */ + top: -35px; + font-size: 0.8em; + text-align: center; + border-radius: 6px; + padding: 5px 8px; + margin: 5px; + z-index: 1000; +} +.tooltipped .tooltiptext { + visibility: visible; +} + +.chapter li.part-title { + color: var(--sidebar-fg); + margin: 5px 0px; + font-weight: bold; +} + +.result-no-output { + font-style: italic; +} diff --git a/documentation/operators/theme/css/variables.css b/documentation/operators/theme/css/variables.css new file mode 100644 index 0000000000..8dfcf92239 --- /dev/null +++ b/documentation/operators/theme/css/variables.css @@ -0,0 +1,3257 @@ + +/* Globals */ + +:root { + --sidebar-width: 300px; + --page-padding: 20px; + --content-max-width: 70%; + --menu-bar-height: 40px; + --mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace; + --code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */ + --pagetoc-width: 13%; + --pagetoc-fontsize: 14.5px; +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +/* Themes */ + +.ayu { + --bg: hsl(210, 25%, 8%); + --fg: #c5c5c5; + + --sidebar-bg: #14191f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #5c6773; + --sidebar-active: #ffb454; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #0096cf; + + --inline-code-color: #ffb454; + + --theme-popup-bg: #14191f; + --theme-popup-border: #5c6773; + --theme-hover: #191f26; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(210, 25%, 13%); + --table-header-bg: hsl(210, 25%, 28%); + --table-alternate-bg: hsl(210, 25%, 11%); + + --searchbar-border-color: #848484; + --searchbar-bg: #424242; + --searchbar-fg: #fff; + --searchbar-shadow-color: #d4c89f; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #252932; + --search-mark-bg: #e3b171; +} + +.coal { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; +} + +.light { + --bg: hsl(0, 0%, 100%); + --fg: hsl(0, 0%, 0%); + + --sidebar-bg: #fafafa; + --sidebar-fg: hsl(0, 0%, 0%); + --sidebar-non-existant: #aaaaaa; + --sidebar-active: #1f1fff; + --sidebar-spacer: #f4f4f4; + + --scrollbar: #8F8F8F; + + --icons: #747474; + --icons-hover: #000000; + + --links: #1f1fff; + + --inline-code-color: #F42C4C; + + --theme-popup-bg: #fafafa; + --theme-popup-border: #cccccc; + --theme-hover: #e6e6e6; + + --quote-bg: hsl(197, 37%, 96%); + --quote-border: hsl(197, 37%, 91%); + + --table-border-color: hsl(0, 0%, 95%); + --table-header-bg: hsl(0, 0%, 80%); + --table-alternate-bg: hsl(0, 0%, 97%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #e4f2fe; + --search-mark-bg: #a2cff5; +} + +.navy { + --bg: hsl(226, 23%, 11%); + --fg: #bcbdd0; + + --sidebar-bg: #282d3f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505274; + --sidebar-active: #2b79a2; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #161923; + --theme-popup-border: #737480; + --theme-hover: #282e40; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(226, 23%, 16%); + --table-header-bg: hsl(226, 23%, 31%); + --table-alternate-bg: hsl(226, 23%, 14%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #aeaec6; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #5f5f71; + --searchresults-border-color: #5c5c68; + --searchresults-li-bg: #242430; + --search-mark-bg: #a2cff5; +} + +.rust { + --bg: hsl(60, 9%, 87%); + --fg: #262625; + + --sidebar-bg: #3b2e2a; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505254; + --sidebar-active: #e69f67; + --sidebar-spacer: #45373a; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #262625; + + --links: #2b79a2; + + --inline-code-color: #6e6b5e; + + --theme-popup-bg: #e1e1db; + --theme-popup-border: #b38f6b; + --theme-hover: #99908a; + + --quote-bg: hsl(60, 5%, 75%); + --quote-border: hsl(60, 5%, 70%); + + --table-border-color: hsl(60, 9%, 82%); + --table-header-bg: #b3a497; + --table-alternate-bg: hsl(60, 9%, 84%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #dec2a2; + --search-mark-bg: #e69f67; +} + +@media (prefers-color-scheme: dark) { + .light.no-js { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; + } +} diff --git a/documentation/operators/theme/index.hbs b/documentation/operators/theme/index.hbs new file mode 100644 index 0000000000..06a3731f33 --- /dev/null +++ b/documentation/operators/theme/index.hbs @@ -0,0 +1,1063 @@ + + + + + + {{ title }} + {{#if is_print }} + + {{/if}} + {{#if base_url}} + + {{/if}} + + + + {{> head}} + + + + + + {{#if favicon_svg}} + + {{/if}} + {{#if favicon_png}} + + {{/if}} + + + + {{#if print_enable}} + + {{/if}} + + + + {{#if copy_fonts}} + + {{/if}} + + + + + + + + {{#each additional_css}} + + {{/each}} + + {{#if mathjax_support}} + + + {{/if}} + + + + + + + + + + + + + + + + +
+ +
+ {{> header}} + + + + {{#if search_enabled}} + + {{/if}} + + + + +
+
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + {{{ content }}} +
+ + +
+
+ + + +
+ + {{#if live_reload_endpoint}} + + + {{/if}} + + {{#if google_analytics}} + + + {{/if}} + + {{#if playground_line_numbers}} + + {{/if}} + + {{#if playground_copyable}} + + {{/if}} + + {{#if playground_js}} + + + + + + {{/if}} + + {{#if search_js}} + + + + {{/if}} + + + + + + + {{#each additional_js}} + + {{/each}} + + {{#if is_print}} + {{#if mathjax_support}} + + {{else}} + + {{/if}} + {{/if}} + + + diff --git a/documentation/operators/theme/pagetoc.css b/documentation/operators/theme/pagetoc.css new file mode 100644 index 0000000000..a68e5b8e21 --- /dev/null +++ b/documentation/operators/theme/pagetoc.css @@ -0,0 +1,47 @@ +/* src: https://github.com/JorelAli/mdBook-pagetoc */ + +@media only screen and (max-width:1439px) { + .sidetoc { + display: none; + } +} + +@media only screen and (min-width:1440px) { + main { + position: relative; + } + .sidetoc { + margin-left: auto; + margin-right: auto; + /* left: calc(90% + (var(--content-min-width))/4 - 110px); */ + left: 101%; + position: absolute; + font-size: var(--pagetoc-fontsize); + } + .pagetoc { + position: fixed; + width: var(--pagetoc-width); + } + .pagetoc a { + border-left: 1px solid var(--sidebar-bg); + /* color: var(--fg); */ + /* color: var(--sidebar-fg); */ + color: var(--links); + display: block; + padding-bottom: 5px; + padding-top: 5px; + padding-left: 10px; + text-align: left; + text-decoration: none; + font-weight: normal; + background: var(--sidebar-bg); + } + .pagetoc a:hover, + .pagetoc a.active { + background: var(--sidebar-bg); + /* color: var(--sidebar-fg); */ + color: var(--sidebar-active); + font-weight: bold; + font-size: var(--pagetoc-fontsize); + } +} diff --git a/documentation/operators/theme/pagetoc.js b/documentation/operators/theme/pagetoc.js new file mode 100644 index 0000000000..b11052427e --- /dev/null +++ b/documentation/operators/theme/pagetoc.js @@ -0,0 +1,68 @@ +// src: https://github.com/JorelAli/mdBook-pagetoc + +// Un-active everything when you click it +Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el, i) { + el.addEventHandler("click", function() { + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el, i) { + el.classList.remove("active"); + }); + el.classList.add("active"); + }); +}); + +var updateFunction = function() { + + var id; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function(el, i) { + if (window.pageYOffset >= el.offsetTop) { + id = el; + } + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el, i) { + el.classList.remove("active"); + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el, i) { + if (id.href.localeCompare(el.href) == 0) { + el.classList.add("active"); + } + }); +}; + +// Populate sidebar on load +window.addEventListener('load', function() { + var pagetoc = document.getElementsByClassName("pagetoc")[0]; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function(el, i) { + var link = document.createElement("a"); + + // Indent shows hierarchy + var indent = ""; + switch (el.parentElement.tagName) { + case "H2": + indent = "20px"; + break; + case "H3": + indent = "40px"; + break; + case "H4": + indent = "60px"; + break; + default: + break; + } + + link.appendChild(document.createTextNode(el.text)); + link.style.paddingLeft = indent; + link.href = el.href; + pagetoc.appendChild(link); + }); + updateFunction.call(); +}); + + + +// Handle active elements on scroll +window.addEventListener("scroll", updateFunction); From 502a2d6a23c492197b9c9152a2521d2b5eb14c69 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 2 Aug 2023 08:04:57 +0200 Subject: [PATCH 021/146] operators: plugins work, ready for final review --- documentation/operators/book.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 3a0a9f722b..28efe62c57 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -53,9 +53,9 @@ platform_release_version = "v1.1.22" wallet_release_version = "v1.2.5" -# [preprocessor.last-changed] -# command = "mdbook-last-changed" -# renderer = ["html"] +[preprocessor.last-changed] +command = "mdbook-last-changed" +renderer = ["html"] # used for grabbing output of binary commands for automation From 6395303466174a4c13e4aaad08db8fa56385c66a Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 2 Aug 2023 10:40:26 +0200 Subject: [PATCH 022/146] #3674 feedback implemented --- .../docs/src/binaries/building-nym.html | 350 ------------------ .../docs/src/binaries/init-and-config.html | 290 --------------- .../docs/src/binaries/pre-built-binaries.html | 286 -------------- documentation/docs/src/introduction.md | 3 - documentation/operators/src/introduction.md | 15 +- .../operators/src/nodes/troubleshooting.md | 8 +- .../operators/src/preliminary-steps.md | 8 +- 7 files changed, 7 insertions(+), 953 deletions(-) delete mode 100644 documentation/docs/src/binaries/building-nym.html delete mode 100644 documentation/docs/src/binaries/init-and-config.html delete mode 100644 documentation/docs/src/binaries/pre-built-binaries.html diff --git a/documentation/docs/src/binaries/building-nym.html b/documentation/docs/src/binaries/building-nym.html deleted file mode 100644 index 2f73af4b4f..0000000000 --- a/documentation/docs/src/binaries/building-nym.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Building from Source - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Building from Source

-
-

Nym runs on Mac OS X, Linux, and Windows. All nodes except the Desktop Wallet and NymConnect on Windows should be considered experimental - it works fine if you’re an app developer but isn’t recommended for running nodes.

-
-

Building Nym

-

Nym has two main codebases:

-
    -
  • the Nym platform, written in Rust. This contains all of our code except for the validators.
  • -
  • the Nym validators, written in Go.
  • -
-
-

This page details how to build the main Nym platform code. If you want to build and run a validator, go here instead.

-
-

Prerequisites

-
    -
  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
  • -
-
apt install pkg-config build-essential libssl-dev curl jq git
-
-
    -
  • Arch/Manjaro: base-devel
  • -
-
pacman -S base-devel
-
-
    -
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git -Running the following the script installs Homebrew and the above dependencies:
  • -
-
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
-
-
    -
  • Rust & cargo >= 1.66
  • -
-

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

-

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

-

Download and build Nym binaries

-

The following commands will compile binaries into the nym/target/release directory:

-
rustup update
-git clone https://github.com/nymtech/nym.git
-cd nym
-
-git reset --hard # in case you made any changes on your branch
-git pull # in case you've checked it out before
-
-git checkout release/v1.1.22 # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks
-
-cargo build --release # build your binaries with **mainnet** configuration
-NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration
-
-

Quite a bit of stuff gets built. The key working parts are:

- -

The repository also contains Typescript applications which aren’t built in this process. These can be built by following the instructions on their respective docs pages.

- -
-

You cannot build from GitHub’s .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn’t a Git repository). Check the code out from github using git clone instead.

-
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/docs/src/binaries/init-and-config.html b/documentation/docs/src/binaries/init-and-config.html deleted file mode 100644 index 147c89cc2d..0000000000 --- a/documentation/docs/src/binaries/init-and-config.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - Binary Initialisation and Configuration - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Binary Initialisation and Configuration

-

All Nym binaries must first be initialised with init before being run.

-

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

-

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will not overwrite existing keypairs if they are present.

-

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

-

Once you have run init, you can start your binary with the run command, usually only accompanied by the id of the binary that you specified.

-

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/docs/src/binaries/pre-built-binaries.html b/documentation/docs/src/binaries/pre-built-binaries.html deleted file mode 100644 index 3497c15d85..0000000000 --- a/documentation/docs/src/binaries/pre-built-binaries.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - Pre-built Binaries - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Pre-built Binaries

-

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

-

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/docs/src/introduction.md b/documentation/docs/src/introduction.md index a6cf38aae7..9e245497f4 100644 --- a/documentation/docs/src/introduction.md +++ b/documentation/docs/src/introduction.md @@ -4,9 +4,6 @@ This is Nym's technical documentation, containing information and setup guides a If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). -If you are looking for information on grants and beta-release Nym apps, check out the [Shipyard](https://shipyard.nymtech.net) site. - - ## Popular pages **Network Architecture:** * [Network Overview](./architecture/network-overview.md) diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index 48b5984eef..acf29f9363 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -4,9 +4,7 @@ This is Nym's operators guide, containing information and setup tutorials about If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). -If you want to go deeper into Nym architecture and various software such as different, application clients, existing applications like the desktop wallet, mixnet explorer or SDKs, visit [Nym's technical documentation](https://nymtech.net/docs/). - -If you are looking for information on grants and beta-release Nym apps, check out the [Shipyard](https://shipyard.nymtech.net) site. +If you want to dive deeper into Nym architecture and such as different clients, existing applications like the desktop wallet, explorers or SDKs, visit [Nym's technical documentation](https://nymtech.net/docs/). ## Popular pages @@ -28,14 +26,3 @@ If you are looking for information on grants and beta-release Nym apps, check ou * [Troubleshooting](./nodes/troubleshooting.md) * [FAQ](./faq.md) - diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index e5333bcfe4..f063d985e0 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -1,9 +1,3 @@ - - # Troubleshooting ## Binary Build Problems @@ -73,6 +67,8 @@ There are 2 community explorers currently, which have been created by [Nodes Gur * [Mainnet](https://mixnet.explorers.guru/) * [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) +[Here](https://github.com/cosmos/chain-registry/blob/master/nyx/chain.json#L158-L187) is a dictionary with Nyx chain registry entry regarding all explorers. + If you want more information, or if your node isn't showing up on the explorer of your choice and you want to double-check, here are some examples on how to check if the node is configured properly. #### Check from your VPS diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index 5cb76d8e19..53f5383838 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,12 +1,12 @@ # Preliminary Steps -> The Nym mixnode, gateway and network requester binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym `mixnode`, `gateway` and `network-requester` binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ## Preliminary steps There are a couple of steps that need completing before starting to set up your mixnode, gateway or a network requester: -- preparing your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) +- preparing your [desktop wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) or [CLI wallet](https://nymtech.net/docs/wallet/cli-wallet.html). - requisitioning a VPS (Virtual Private Server) ### Wallet preparation @@ -32,12 +32,12 @@ For now, see the below rough specs: - Processors: 2 cores are fine. Get the fastest CPUs you can afford. -#### For Nym Mixnode +#### For Mixnode - RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. - Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. -#### For Nym Gateway +#### For Gateway - RAM: Memory requirements depend on the amount of users your Gateway will be serving at any one time. If you're just going to be using it yourself, then minimal RAM is fine. **If you're running your Gateway as part of a Service Grant, get something with at least 4GB RAM.** - Disks: much like the amount of RAM your Gateway could use, the amount of disk space required will vary with the amount of users your Gateway is serving. **If you're running your Gateway as part of a Service Grant, get something with at least 40GB storage.** From 10696ae4dc8701d672e25cba777dde5ac6ec4958 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 16:31:45 +0200 Subject: [PATCH 023/146] tweaked intro page --- documentation/operators/src/introduction.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index acf29f9363..dc160825d6 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -1,19 +1,17 @@ # Introduction -This is Nym's operators guide, containing information and setup tutorials about the various pieces of Nym mixnet infrastructure nodes, such as mix node, gateway and network requester as well as Nyx chain validators. +This is Nym's Operators guide, containing information and setup guides for the various pieces of Nym mixnet infrastructure (mix node, gateway and network requester) and Nyx blockchain validators. -If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). +If you are new to Nym and want to learn about the mixnet, explore quickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/). -If you want to dive deeper into Nym architecture and such as different clients, existing applications like the desktop wallet, explorers or SDKs, visit [Nym's technical documentation](https://nymtech.net/docs/). +If you want to dive deeper into Nym's architecture, clients, nodes, and SDK examples visit the [technical docs](https://nymtech.net/docs/). ## Popular pages - - - -**Network Architecture:** -* [Network Overview](https://nymtech.net/docs/architecture/network-overview.html) -* [Mixnet Traffic Flow](https://nymtech.net/docs/architecture/traffic-flow.html) +**Binary Information** +* [Building Nym](./binaries/building-nym.md) +* [Pre-built Binaries](./binaries/pre-built-binaries.md) +* [Init & Configuration](./binaries/init-and-config.md) **Node setup and usage guides:** * [Mix nodes](./nodes/mix-node-setup.md) From 0b6eb177937fef01e4d458502fa9bfaf97242c99 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 16:43:58 +0200 Subject: [PATCH 024/146] * removed old `wallet-address` flag * 'mixnode' -> 'mix node' for consistency in non-code / non-binary references --- documentation/operators/src/faq.md | 6 +-- .../operators/src/nodes/maintenance.md | 32 ++++++------- .../operators/src/nodes/mix-node-setup.md | 18 ++++---- .../operators/src/nodes/troubleshooting.md | 46 +++++++++---------- .../operators/src/preliminary-steps.md | 12 ++--- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index bc3c210352..a42af22825 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -2,7 +2,7 @@ ## Mixnet nodes -### What determines the rewards when running a mixnode? +### What determines the rewards when running a mix node? The stake required for a mix node to achieve maximum rewards is called mix node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. @@ -16,7 +16,7 @@ For more detailed calculation, read our blog post [Nym Token Economics update](h Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. - + ### What's the Sphinx packet size? @@ -32,7 +32,7 @@ Right now only mix nodes are rewarded. We're working on gateway and service paym ### Are mixnodes whitelisted? -Nope, anyone can run a mixnode. Purely reliant on the node's reputation (self stake + delegations) & routing score. +Nope, anyone can run a mix node. Purely reliant on the node's reputation (self stake + delegations) & routing score. ## Validators and tokens diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 26d5375a7d..7ffe1d6d58 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -2,7 +2,7 @@ ``` -The `nym-mixnode` binary is currently one point version ahead of the rest of the platform binaries due to a patch applied between releases. +The `nym-mix node` binary is currently one point version ahead of the rest of the platform binaries due to a patch applied between releases. ## Preliminary steps -Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your mixnode. +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your mix node. ## Mix node setup -Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mix node` binary, you can set up your mix node with the instructions below. -To begin, move to `/taget/release` directory from which you run the node commands: +To begin, move to `/target/release` directory from which you run the node commands: ``` cd target/release @@ -63,10 +63,10 @@ To check available configuration options for initializing your node use: ``` ~~~ -Initalise your mixnode with the following command, replacing the value of `--id` with the moniker you wish to give your mixnode, and the `--wallet-address` with the Nym address you created earlier. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. +Initalise your mix node with the following command, replacing the value of `--id` with the moniker you wish to give your mix node. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. ``` -./nym-mixnode init --id --host $(curl ifconfig.me) --wallet-address +./nym-mixnode init --id --host $(curl ifconfig.me) ``` @@ -105,7 +105,7 @@ During the `init` process you will have the option to change the `http_api`, `ve ### Bonding your mix node ```admonish caution -From `v1.1.3`, if you unbond your mixnode that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. +From `v1.1.3`, if you unbond your mix node that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. ``` #### Bond via the Desktop wallet (recommended) @@ -183,7 +183,7 @@ Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see mo ## Node Description (optional) -In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mixnode with the following command: +In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mix node with the following command: ``` ./nym-mixnode describe --id @@ -311,5 +311,5 @@ For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) ## Maintenance -For mixnode upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) +For mix node upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index f063d985e0..d8fb566b58 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -78,7 +78,7 @@ Additional details can be obtained via various methods after you connect to your ##### Socket statistics with `ss` ``` -sudo ss -s -t | grep 1789 # if you have specified a different port in your mixnode config, change accordingly +sudo ss -s -t | grep 1789 # if you have specified a different port in your mix node config, change accordingly ``` This command should return a lot of data containing `ESTAB`. This command should work on every unix based system. @@ -90,7 +90,7 @@ This command should return a lot of data containing `ESTAB`. This command should lsof -v # install if not installed sudo apt install lsof -# run against mixnode port +# run against mix node port sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly ``` @@ -110,7 +110,7 @@ nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3: sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed" ``` -If you have created `nym-mixnode.service` file (i.e. you are running your mixnode via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: +If you have created `nym-mixnode.service` file (i.e. you are running your mix node via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: ``` 2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets! @@ -140,7 +140,7 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu nmap -p 1789 -Pn ``` -If your mixnode is configured properly it should output something like this: +If your mix node is configured properly it should output something like this: ``` bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn @@ -164,7 +164,7 @@ You can query gateways by replacing `mixnodes` with `gateways` in the above comm #### Check with Network API -We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mixnode, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). +We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mix node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). ### Why is my node not mixing any packets? @@ -172,24 +172,24 @@ If you are still unable to see your node on the dashboard, or your node is decla - The firewall on your host machine is not configured properly. Checkout the [instructions](./maintenance.md#configure-your-firewall). - You provided incorrect information when bonding your node. -- You are running your mixnode from a VPS without IPv6 support. -- You did not use the `--announce-host` flag while running the mixnode from your local machine behind NAT. -- You did not configure your router firewall while running the mixnode from your local machine behind NAT, or you are lacking IPv6 support. -- Your mixnode is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). +- You are running your mix node from a VPS without IPv6 support. +- You did not use the `--announce-host` flag while running the mix node from your local machine behind NAT. +- You did not configure your router firewall while running the mix node from your local machine behind NAT, or you are lacking IPv6 support. +- Your mix node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). ```admonish caution -Your mixnode **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! +Your mix node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! ``` #### Incorrect bonding information -Check that you have provided the correct information when bonding your mixnode in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, un-bond and then re-bond your node! +Check that you have provided the correct information when bonding your mix node in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, un-bond and then re-bond your node! -> All delegated stake will be lost when un-bonding! However the mixnode must be operational in the first place for the delegation to have any effect. +> All delegated stake will be lost when un-bonding! However the mix node must be operational in the first place for the delegation to have any effect. #### Missing `announce-host` flag -On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mixnode host. +On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mix node host. If the difference between the two is unclear, contact the help desk of your VPS provider. @@ -222,15 +222,15 @@ bob@nym:~$ hostname -I ### Running on a local machine behind NAT with no fixed IP address -Your ISP has to be IPv6 ready if you want to run a mixnode on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. +Your ISP has to be IPv6 ready if you want to run a mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! -If all goes well and you have IPv6 available, then you will need to `init` the mixnode with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). +If all goes well and you have IPv6 available, then you will need to `init` the mix node with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support. -Here is a sample of the `init` command example to create the mixnode config. +Here is a sample of the `init` command example to create the mix node config. ``` ./nym-mixnode init --id --host 0.0.0.0 --announce-host 85.160.12.13 @@ -244,7 +244,7 @@ Make sure you check if your node is really mixing. We are aiming to improve the ### Accidentally killing your node process on exiting session -When you close your current terminal session, you need to make sure you don't kill the mixnode process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). +When you close your current terminal session, you need to make sure you don't kill the mix node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). ### Common errors and warnings @@ -273,24 +273,24 @@ Rocket runs on port `8000` by default. Although at this stage we need Rocket to #### `failed to receive reply to our echo packet within 1.5s. Stopping the test` -This relates to the VerLoc implementation that appeared in `0.10.1`, which has a particularly high log sensitivity. This warning means that the echo packet sent to the mixnode was received, but not sent back. _This will not affect the rate of rewards or performance metrics of your mixnode in the testnet at this point._ +This relates to the VerLoc implementation that appeared in `0.10.1`, which has a particularly high log sensitivity. This warning means that the echo packet sent to the mix node was received, but not sent back. _This will not affect the rate of rewards or performance metrics of your mix node in the testnet at this point._ #### `Connection to :1789 seems to be dead` -This warning is normal at the moment, and is _nothing to do with your mixnode!_ It is simply a warning that your node is unable to connect to other peoples' mixnodes for some reason, most likely because they are offline or poorly configured. +This warning is normal at the moment, and is _nothing to do with your mix node!_ It is simply a warning that your node is unable to connect to other peoples' mixnodes for some reason, most likely because they are offline or poorly configured. ---> ### Can I use a port other than 1789 ? Yes! Here is what you will need to do: -Assuming you would like to use port `1337` for your mixnode, you need to open the new port (and close the old one): +Assuming you would like to use port `1337` for your mix node, you need to open the new port (and close the old one): ``` sudo ufw allow 1337 sudo ufw deny 1789 ``` -And then edit the mixnode's config. +And then edit the mix node's config. > If you want to change the port for an already running node, you need to stop the process before editing your config file. @@ -304,9 +304,9 @@ nano ~/.nym/mixnodes/alice-node/config/config.toml You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. -Finally, restart your node. You should see if the mixnode is using the port you have changed in the config.toml file right after you run the node. +Finally, restart your node. You should see if the mix node is using the port you have changed in the config.toml file right after you run the node. -### What is `verloc` and do I have to configure my mixnode to implement it? +### What is `verloc` and do I have to configure my mix node to implement it? `verloc` is short for _verifiable location_. Mixnodes and gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fakeable and trustworthy manner. diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index 53f5383838..d36ca76da4 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,23 +1,23 @@ # Preliminary Steps -> The Nym `mixnode`, `gateway` and `network-requester` binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym `mix node`, `gateway` and `network-requester` binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ## Preliminary steps -There are a couple of steps that need completing before starting to set up your mixnode, gateway or a network requester: +There are a couple of steps that need completing before starting to set up your mix node, gateway or a network requester: - preparing your [desktop wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) or [CLI wallet](https://nymtech.net/docs/wallet/cli-wallet.html). - requisitioning a VPS (Virtual Private Server) ### Wallet preparation #### Mainnet -Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). +Before you initialise and run your mix node, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). -If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. +If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mix node is 100 `NYM`, but make sure you have a bit more to account for gas costs. `NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several [exchanges](https://www.coingecko.com/en/coins/nym#markets). -> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. +> Remember that you can **only** use Cosmos `NYM` tokens to bond your mix node. You **cannot** use ERC20 representations of `NYM` to run a node. #### Sandbox testnet @@ -32,7 +32,7 @@ For now, see the below rough specs: - Processors: 2 cores are fine. Get the fastest CPUs you can afford. -#### For Mixnode +#### For mix node - RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. - Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. From c1e8ebd46a26e3389b2700bae49ae01b91cd63cc Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 16:46:05 +0200 Subject: [PATCH 025/146] typo fix --- documentation/operators/src/nodes/gateway-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 026e7afde0..f1cb589756 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -17,7 +17,7 @@ Make sure you do the preparation listed in the [preliminary steps page](../preli ## Gateway setup Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-gateway` binary, you can set up your gateway with the instructions below. -To begin, move to `/taget/release` directory from which you run the node commands: +To begin, move to `/target/release` directory from which you run the node commands: ``` cd target/release From e18c541400b3220a36c73bb9027466f3c1a94e8b Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 19:28:13 +0200 Subject: [PATCH 026/146] added custom 404 + updated platform version --- documentation/docs/book.toml | 6 +++--- documentation/docs/src/not-found.md | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 documentation/docs/src/not-found.md diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index b70997a556..f507798295 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -49,8 +49,8 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` [preprocessor.variables.variables] minimum_rust_version = "1.66" # vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.22" -wallet_release_version = "v1.2.5" +platform_release_version = "v1.1.26" +wallet_release_version = "v1.2.7" [preprocessor.last-changed] command = "mdbook-last-changed" @@ -92,7 +92,7 @@ git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" # site-url = "/docs/" # cname = "nymtech.net" -# input-404 = "not-found.md" # todo make custom 404 page +input-404 = "not-found.md" [output.html.fold] enable = true # whether or not to enable section folding diff --git a/documentation/docs/src/not-found.md b/documentation/docs/src/not-found.md new file mode 100644 index 0000000000..3d203a9bb8 --- /dev/null +++ b/documentation/docs/src/not-found.md @@ -0,0 +1,11 @@ +# Page Not Found + +You seem to have followed a link to a page that no longer exists. Our documentation is changing and growing over time, so this page has most likely been moved somewhere else. + +For node setup guides, see the [Operators Guides book](https://nymtech.net/operators). + +For developer tutorials, app guides, and demo and community apps, see the [Developer Portal](https://nymtech.net/developers). + +If you are looking for information on network architecture traffic flow, clients, the SDKs, or interacting with the Nyx blockchain, check the sitemap on the left hand side of the screen. + +If you still can't find what you're looking for get in touch with us via [Matrix](TODO). \ No newline at end of file From cc65236085b1b2a668773ee24ad3afc3d2795b50 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 19:28:37 +0200 Subject: [PATCH 027/146] * deleted old setup guides * added new info on operator guides * adding stubs for in-depth node pages --- documentation/docs/src/SUMMARY.md | 13 +- documentation/docs/src/nodes/gateway-setup.md | 262 ------- documentation/docs/src/nodes/gateway.md | 1 + .../docs/src/nodes/mix-node-setup.md | 566 --------------- documentation/docs/src/nodes/mixnode.md | 17 + .../docs/src/nodes/network-requester-setup.md | 255 ------- .../docs/src/nodes/network-requester.md | 1 + documentation/docs/src/nodes/overview.md | 9 + documentation/docs/src/nodes/setup-guides.md | 8 - .../docs/src/nodes/troubleshooting.md | 368 ---------- .../docs/src/nodes/validator-setup.md | 669 ------------------ documentation/docs/src/nodes/validator.md | 12 + 12 files changed, 46 insertions(+), 2135 deletions(-) delete mode 100644 documentation/docs/src/nodes/gateway-setup.md create mode 100644 documentation/docs/src/nodes/gateway.md delete mode 100644 documentation/docs/src/nodes/mix-node-setup.md create mode 100644 documentation/docs/src/nodes/mixnode.md delete mode 100644 documentation/docs/src/nodes/network-requester-setup.md create mode 100644 documentation/docs/src/nodes/network-requester.md create mode 100644 documentation/docs/src/nodes/overview.md delete mode 100644 documentation/docs/src/nodes/setup-guides.md delete mode 100644 documentation/docs/src/nodes/troubleshooting.md delete mode 100644 documentation/docs/src/nodes/validator-setup.md create mode 100644 documentation/docs/src/nodes/validator.md diff --git a/documentation/docs/src/SUMMARY.md b/documentation/docs/src/SUMMARY.md index 8d9c174f5a..c9fc9c6d1d 100644 --- a/documentation/docs/src/SUMMARY.md +++ b/documentation/docs/src/SUMMARY.md @@ -14,12 +14,11 @@ # Nodes -- [Node Setup Guides](nodes/setup-guides.md) - - [Mix Node](nodes/mix-node-setup.md) - - [Gateway](nodes/gateway-setup.md) - - [Network Requester](nodes/network-requester-setup.md) - - [Validator](nodes/validator-setup.md) -- [Troubleshooting](nodes/troubleshooting.md) +- [Node Types (Previously Setup Guides)](nodes/overview.md) + - [Mix Node](nodes/mixnode.md) + - [Gateway](nodes/gateway.md) + - [Network Requester](nodes/network-requester.md) + - [Validator](nodes/validator.md) # Clients - [Clients Overview](clients/overview.md) @@ -40,7 +39,7 @@ - [Mixnet Explorer](explorers/mixnet-explorer.md) # Nyx Blockchain - +- [Interacting with Nyx Chain and Smart Contracts](nyx/interacting-with-chain.md) - [Smart Contracts](nyx/smart-contracts.md) - [Mixnet Contract](nyx/mixnet-contract.md) - [Vesting Contract](nyx/vesting-contract.md) diff --git a/documentation/docs/src/nodes/gateway-setup.md b/documentation/docs/src/nodes/gateway-setup.md deleted file mode 100644 index fe48fc8566..0000000000 --- a/documentation/docs/src/nodes/gateway-setup.md +++ /dev/null @@ -1,262 +0,0 @@ -# Gateways - -> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. - -## Current version -``` - -``` - - -## Preliminary steps -There are a couple of steps that need completing before starting to set up your gateway: - -- preparing your wallet -- requisitioning a VPS (Virtual Private Server) - -### Wallet preparation -#### Mainnet -Before you initialise and run your gateway, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't availiable, you can build the wallet yourself with instructions [here](../wallet/desktop-wallet.md). - -If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a gateway is 100 `NYM`, but make sure you have a bit more to account for gas costs. - -`NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several exchanges. - -> Remember that you can **only** use native Cosmos `NYM` tokens to bond your gateway. You **cannot** use ERC20 representations of `NYM` to run a node. - - -#### Sandbox testnet -Make sure to download a wallet and create an account as outlined above. Then head to our [token faucet](https://faucet.nymtech.net/) and get some tokens to use to bond it. - -### VPS Hardware Specs -You will need to rent a VPS to run your mix node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol. - -We currently have these _rough_ specs for VPS hardware: - -- Processors: 2 cores are fine. Get the fastest CPUs you can afford. -- RAM: Memory requirements depend on the amount of users your Gateway will be serving at any one time. If you're just going to be using it yourself, then minimal RAM is fine. **If you're running your Gateway as part of a Service Grant, get something with at least 4GB RAM.** -- Disks: much like the amount of RAM your Gateway could use, the amount of disk space required will vary with the amount of users your Gateway is serving. **If you're running your Gateway as part of a Service Grant, get something with at least 40GB storage.** - -## Gateway setup -Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-gateway` binary, you can set up your gateway with the instructions below. - -### Viewing command help -You can check that your binaries are properly compiled with: - -``` -./nym-gateway --help -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -You can also check the various arguments required for individual commands with: - -``` -./nym-gateway --help -``` - -### Initialising your gateway -To check available configuration options use: - -``` - ./nym-gateway init --help -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -The following command returns a gateway on your current IP with the `id` of `supergateway`: - -``` -./nym-gateway init --id supergateway --host $(curl ifconfig.me) --wallet-address n1eufxdlgt0puwrwptgjfqne8pj4nhy2u5ft62uq -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -The `$(curl ifconfig.me)` command above returns your IP automatically using an external service. Alternatively, you can enter your IP manually wish. If you do this, remember to enter your IP **without** any port information. - -### Bonding your gateway -#### Via the Desktop wallet -You can bond your gateway via the Desktop wallet. - -* Open your wallet, and head to the `Bond` page, then select the node type and input your node details. Press `continue` - -* You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it. It will look something like this: - -~~~admonish example collapsible=true title="Console output" -``` -./nym-gateway sign --id upgrade_test --contract-msg 2Mf8xYytgEeyJke9LA7TjhHoGQWNBEfgHZtTyy2krFJfGHSiqy7FLgTnauSkQepCZTqKN5Yfi34JQCuog9k6FGA2EjsdpNGAWHZiuUGDipyJ6UksNKRxnFKhYW7ri4MRduyZwbR98y5fQMLAwHne1Tjm9cXYCn8McfigNt77WAYwBk5bRRKmC34BJMmWcAxphcLES2v9RdSR68tkHSpy2C8STfdmAQs3tZg8bJS5Qa8pQdqx14TnfQAPLk3QYCynfUJvgcQTrg29aqCasceGRpKdQ3Tbn81MLXAGAs7JLBbiMEAhCezAr2kEN8kET1q54zXtKz6znTPgeTZoSbP8rzf4k2JKHZYWrHYF9JriXepuZTnyxAKAxvGFPBk8Z6KAQi33NRQkwd7MPyttatHna6kG9x7knffV6ebGzgRBf7NV27LurH8x4L1uUXwm1v1UYCA1WSBQ9Pp2JW69k5v5v7G9gBy8RUcZnMbeL26Qqb8WkuGcmuHhaFfoqSfV7PRHPpPT4M8uRqUyR4bjUtSJJM1yh6QSeZk9BEazzoJqPeYeGoiFDZ3LMj2jesbJweQR4caaYuRczK92UGSSqu9zBKmE45a - - - _ __ _ _ _ __ ___ - | '_ \| | | | '_ \ _ \ - | | | | |_| | | | | | | - |_| |_|\__, |_| |_| |_| - |___/ - - (nym-gateway - version {{platform_release_version}}) - - ->>> attempting to sign 2Mf8xYytgEeyJke9LA7TjhHoGQWNBEfgHZtTyy2krFJfGHSiqy7FLgTnauSkQepCZTqKN5Yfi34JQCuog9k6FGA2EjsdpNGAWHZiuUGDipyJ6UksNKRxnFKhYW7ri4MRduyZwbR98y5fQMLAwHne1Tjm9cXYCn8McfigNt77WAYwBk5bRRKmC34BJMmWcAxphcLES2v9RdSR68tkHSpy2C8STfdmAQs3tZg8bJS5Qa8pQdqx14TnfQAPLk3QYCynfUJvgcQTrg29aqCasceGRpKdQ3Tbn81MLXAGAs7JLBbiMEAhCezAr2kEN8kET1q54zXtKz6znTPgeTZoSbP8rzf4k2JKHZYWrHYF9JriXepuZTnyxAKAxvGFPBk8Z6KAQi33NRQkwd7MPyttatHna6kG9x7knffV6ebGzgRBf7NV27LurH8x4L1uUXwm1v1UYCA1WSBQ9Pp2JW69k5v5v7G9gBy8RUcZnMbeL26Qqb8WkuGcmuHhaFfoqSfV7PRHPpPT4M8uRqUyR4bjUtSJJM1yh6QSeZk9BEazzoJqPeYeGoiFDZ3LMj2jesbJweQR4caaYuRczK92UGSSqu9zBKmE45a ->>> decoding the message... ->>> message to sign: {"nonce":0,"algorithm":"ed25519","message_type":"gateway-bonding","content":{"sender":"n1ewmme88q22l8syvgshqma02jv0vqrug9zq9dy8","proxy":null,"funds":[{"denom":"unym","amount":"100000000"}],"data":{"gateway":{"host":"62.240.134.189","mix_port":1789,"clients_port":9000,"location":"62.240.134.189","sphinx_key":"FKbuN7mPdoCG9jA3CkAfXxC5X4rHhqeMVtmfRtJ3cFZd","identity_key":"3RoAhR8gEdfBETMjm2vbMFzKddxXDdE9ygBAnJHWqSzD","version":"1.1.13"}}}} -``` -~~~ - -* Copy the resulting signature: - -``` ->>> The base58-encoded signature is: -2SPDjLjX4b6XEtkgG7yD8Znsb1xycL1edFvRK4JcVnPsM9k6HXEUUeVS6rswRiYxoj1bMgiRKyPDwiksiuyxu8Xi -``` - -* And paste it into the wallet nodal, then confirm the transaction. - -![Paste Signature](../images/wallet-sign.png) - -* Your gateway is now bonded. - -> You are asked to `sign` a transaction on bonding so that the mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. - -#### Via the CLI (power users) -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#bond-a-gateway) docs. - -### Running your gateway -The `run` command starts the gateway: - -``` -./nym-gateway run --id supergateway -``` - -### Upgrading your gateway -Upgrading your node is a two-step process: -* Updating the binary and `config.toml` on your VPS -* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. - ->These instructions are specifically regarding upgrading your gateway binary from one version to another. If you want to change node information such as the listening port, you can do this by clicking the `node settings` tab in the `bond` page of the wallet. - -#### Step 1: upgrading your binary -Follow these steps to upgrade your binary and update its config file: -* pause your gateway process. -* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your gateway process with the new binary. - -> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. - -#### Step 2: updating your node information in the smart contract -Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). - -You can either do this graphically via the Desktop Wallet, or the CLI. - -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -![Bonding page](../images/wallet-screenshots/bonding.png) - -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -![Node Settings Page](../images/wallet-screenshots/node_settings.png) - -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. - -## VPS Setup and Automation -### Configure your firewall -Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: - -``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status -``` - -Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: - -``` -sudo ufw allow 1789,22,9000/tcp -# check the status of the firewall -sudo ufw status -``` - -For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. - -### Automating your gateway with systemd -Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: - -```ini -[Unit] -Description=Nym Gateway ({{platform_release_version}}) -StartLimitInterval=350 -StartLimitBurst=10 - -[Service] -User=nym -LimitNOFILE=65536 -ExecStart=/home/nym/nym-gateway run --id supergateway -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 - -[Install] -WantedBy=multi-user.target -``` - -Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. - -Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. - -If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: - -`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` - - -Then run: - -``` -systemctl enable nym-gateway.service -``` - -Start your node: - -``` -service nym-gateway start -``` - -This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. - -You can also do `service nym-gateway stop` or `service nym-gateway restart`. - -Note: if you make any changes to your systemd script after you've enabled it, you will need to run: - -``` -systemctl daemon-reload -``` - -This lets your operating system know it's ok to reload the service configuration. - -## Gateway related Validator API endpoints -Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. - -## Ports -All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. - -### Gateway port reference -| Default port | Use | -|--------------|---------------------------| -| 1789 | Listen for Mixnet traffic | -| 9000 | Listen for Client traffic | diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md new file mode 100644 index 0000000000..f4ee68e242 --- /dev/null +++ b/documentation/docs/src/nodes/gateway.md @@ -0,0 +1 @@ +# Gateway diff --git a/documentation/docs/src/nodes/mix-node-setup.md b/documentation/docs/src/nodes/mix-node-setup.md deleted file mode 100644 index 408ef20b99..0000000000 --- a/documentation/docs/src/nodes/mix-node-setup.md +++ /dev/null @@ -1,566 +0,0 @@ -# Mix Nodes - -> The Nym mix node binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. - -## Current version -``` - -``` - -The `nym-mixnode` binary is currently one point version ahead of the rest of the platform binaries due to a patch applied between releases. - -## Preliminary steps - -There are a couple of steps that need completing before starting to set up your mix node: - -- preparing your wallet -- requisitioning a VPS (Virtual Private Server) - -### Wallet preparation - -#### Mainnet - -Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't availiable, you can build the wallet yourself with instructions [here](../wallet/desktop-wallet.md). - -If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. - -`NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several exchanges. - -> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. - -#### Sandbox testnet - -Make sure to download a wallet and create an account as outlined above. Then head to our [token faucet](https://faucet.nymtech.net/) and get some tokens to use to bond it. - -### VPS Hardware Specs - -You will need to rent a VPS to run your mix node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol). - -For the moment, we haven't put a great amount of effort into optimizing concurrency to increase throughput, so don't bother provisioning a beastly server with multiple cores. This will change when we get a chance to start doing performance optimizations in a more serious way. Sphinx packet decryption is CPU-bound, so once we optimise, more fast cores will be better. - -For now, see the below rough specs: - -- Processors: 2 cores are fine. Get the fastest CPUs you can afford. -- RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. -- Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. - -## Mix node setup - -Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. - -### Viewing command help - -You can check that your binaries are properly compiled with: - -``` -./nym-mixnode --help -``` - -Which should return a list of all avaliable commands. - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -You can also check the various arguments required for individual commands with: - -``` -./nym-mixnode --help -``` - -### Initialising your mix node - -To check available configuration options for initializing your node use: - -``` -./nym-mixnode init --help -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -Initalise your mixnode with the following command, replacing the value of `--id` with the moniker you wish to give your mixnode, and the `--wallet-address` with the Nym address you created earlier. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. - -``` -./nym-mixnode init --id winston-smithnode --host $(curl ifconfig.me) --wallet-address n1eufxdlgt0puwrwptgjfqne8pj4nhy2u5ft62uq -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -> The `init` command will refuse to destroy existing mix node keys. - -During the `init` process you will have the option to change the `http_api`, `verloc` and `mixnode` ports from their default settings. If you wish to change these in the future you can edit their values in the `config.toml` file created by the initialization process, which is located at `~/.nym/mixnodes//`. - -### Bonding your mix node - -```admonish caution -From `v1.1.3`, if you unbond your mixnode that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. -``` - -#### Bond via the Desktop wallet (recommended) - -You can bond your mix node via the Desktop wallet. - -* Open your wallet, and head to the `Bond` page, then select the node type and input your node details. Press `continue` - -* You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it. It will look something like this: - -~~~admonish example collapsible=true title="Console output" -``` -./nym-mixnode sign --id upgrade_test --contract-msg 5XrvVEMzRJk2AcT2h1o6ErZNb8z1ZzD3h7teipBW3NUtrtYq7vu4DRMgzZRTPVPnyr2YWCxpmKCMFaEXvksnJ -4jt7np3NMLxsLMrFjEBhh67Crtjy4868vCzAivUqzdc365RiqxQQKtv4r9eTk9mTbE9JY8U3TxzKJCSGcBqbrb9JX3HrZVWm6tqbUYbsnku9pqnfeyeUiaYKY44Lm72TYrkZfRrMAZLMATiXT1ntmiKqT37HzRxNZjiH8qHeQEoRHkgDsmXDXRbfppGTpPrN7R4sjynJzehzUBZ8Ug7ovT9FoAHb8kuVQhUiMs1js6tdwtthzQMbPi9vwxUtVvjYknN2fnJgMnckEhzJJpJDCNdH7YhpPaWQnGVVS334mskiuqkbRVrFPJN2nnwArHr3L2cLxSMk9toKfw7ViKJ2p5E5JxiSmKY1cFGZ7uRLsuQ833PJN9JE8crPtkBNefqkbFNz68S5jPmzUShSvAc4TqXKeovDASFmmhKaPqLUrfsSWm7nzuKnzJSMADF6xSuwr9cknMoirqkRkLe7ybJ2ERwSdf5cUxMjF7yjS8tW9hZudnTUb1uPNDuSmPPVrCR12XZyFzBvVgxH51ZNJTym46nqnfA881LQcmFMnCwJf39rVJ4ASLnzEzmuwXj75QoB9ce9kiLmoBNLYe4QKSB6gDd858VnBtBNQELVuCCZbrTYuSCeNdUFhvMwD4kryc1pBYUa8Ro81F3QVfiKN - - _ __ _ _ _ __ ___ - | '_ \| | | | '_ \ _ \ - | | | | |_| | | | | | | - |_| |_|\__, |_| |_| |_| - |___/ - - (nym-mixnode - version {{mix_node_release_version}}) - - ->>> attempting to sign 5XrvVEMzRJk2AcT2h1o6ErZNb8z1ZzD3h7teipBW3NUtrtYq7vu4DRMgzZRTPVPnyr2YWCxpmKCMFaEXvksnJ4jt7np3NMLxsLMrFjEBhh67Crtjy4868vCzAivUqzdc365RiqxQQKtv4r9eTk9mTbE9JY8U3TxzKJCSGcBqbrb9JX3HrZVWm6tqbUYbsnku9pqnfeyeUiaYKY44Lm72TYrkZfRrMAZLMATiXT1ntmiKqT37HzRxNZjiH8qHeQEoRHkgDsmXDXRbfppGTpPrN7R4sjynJzehzUBZ8Ug7ovT9FoAHb8kuVQhUiMs1js6tdwtthzQMbPi9vwxUtVvjYknN2fnJgMnckEhzJJpJDCNdH7YhpPaWQnGVVS334mskiuqkbRVrFPJN2nnwArHr3L2cLxSMk9toKfw7ViKJ2p5E5JxiSmKY1cFGZ7uRLsuQ833PJN9JE8crPtkBNefqkbFNz68S5jPmzUShSvAc4TqXKeovDASFmmhKaPqLUrfsSWm7nzuKnzJSMADF6xSuwr9cknMoirqkRkLe7ybJ2ERwSdf5cUxMjF7yjS8tW9hZudnTUb1uPNDuSmPPVrCR12XZyFzBvVgxH51ZNJTym46nqnfA881LQcmFMnCwJf39rVJ4ASLnzEzmuwXj75QoB9ce9kiLmoBNLYe4QKSB6gDd858VnBtBNQELVuCCZbrTYuSCeNdUFhvMwD4kryc1pBYUa8Ro81F3QVfiKN ->>> decoding the message... ->>> message to sign: {"nonce":0,"algorithm":"ed25519","message_type":"mixnode-bonding","content":{"sender":"n1eufxdlgt0puwrwptgjfqne8pj4nhy2u5ft62uq","proxy":null,"funds":[{"denom":"unym","amount":"100000000"}],"data":{"mix_node":{"host":"62.240.134.189","mix_port":1789,"verloc_port":1790,"http_api_port":8000,"sphinx_key":"CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z","identity_key":"DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"1.1.14"},"cost_params":{"profit_margin_percent":"0.1","interval_operating_cost":{"denom":"unym","amount":"40000000"}}}}} -``` -~~~ - -* Copy the resulting signature: - -``` ->>> The base58-encoded signature is: -2GbKcZVKFdpi3sR9xoJWzwPuGdj3bvd7yDtDYVoKfbTWdpjqAeU8KS5bSftD5giVLJC3gZiCg2kmEjNG5jkdjKUt -``` - -* And paste it into the wallet nodal, then confirm the transaction. - -![Paste Signature](../images/wallet-sign.png) - -* Your node will now be bonded and ready to mix at the beginning of the next epoch (at most 1 hour). - -> You are asked to `sign` a transaction on bonding so that the mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. - -#### Bond via the CLI (power users) -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#bond-a-mix-node) docs. - -### Running your mix node - -Now you've bonded your mix node, run it with: - -``` -./nym-mixnode run --id winston-smithnode -``` - -If everything worked, you'll see your node running on the either the [Sandbox testnet network explorer](https://sandbox-explorer.nymtech.net) or the [mainnet network explorer](https://explorer.nymtech.net), depending on which network you're running. - -Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list. - -Keep reading to find out more about configuration options or troubleshooting if you're having issues. There are also some tips for running on AWS and other cloud providers, some of which require minor additional setup. - -Also have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. - -### Describe your mix node (optional) - -In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mixnode with the following command: - -``` -./nym-mixnode describe --id winston-smithnode -``` - -> Remember to restart your mix node process in order for the new description to be propogated. - -### Upgrading your mix node - -Upgrading your node is a two-step process: -* Updating the binary and `config.toml` on your VPS -* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. - -#### Step 1: upgrading your binary -Follow these steps to upgrade your mix node binary and update its config file: -* pause your mix node process. -* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your mix node process with the new binary. - -> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. - -#### Step 2: updating your node information in the smart contract -Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). - -You can either do this graphically via the Desktop Wallet, or the CLI. - -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -![Bonding page](../images/wallet-screenshots/bonding.png) - -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -![Node Settings Page](../images/wallet-screenshots/node_settings.png) - -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. - -### Displaying mix node information - -You can always check the details of your mix node with the `node-details` command: - -``` -./nym-mixnode node-details --id winston-smithnode -``` - -## VPS Setup and Automation -### Configure your firewall -The following commands will allow you to set up a firewall using `ufw`. - -``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status -``` - -Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: - -``` -sudo ufw allow 1789,1790,8000,22/tcp -# check the status of the firewall -sudo ufw status -``` - -For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. - -### Automating your mix node with systemd - -It's useful to have the mix node automatically start at system boot time. Here's a systemd service file to do that: - -```ini -[Unit] -Description=Nym Mixnode ({{mix_node_release_version}}) -StartLimitInterval=350 -StartLimitBurst=10 - -[Service] -User=nym -LimitNOFILE=65536 -ExecStart=/home/nym/nym-mixnode run --id mix0100 -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 - -[Install] -WantedBy=multi-user.target -``` - -Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. - -Change the path in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `User` so it is the user you are running as. - -If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: - -`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` - -Then run: - -``` -systemctl enable nym-mixnode.service -``` - -Start your node: - -``` -service nym-mixnode start -``` - -This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. - -You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. - -Note: if you make any changes to your systemd script after you've enabled it, you will need to run: - -``` -systemctl daemon-reload -``` - -This lets your operating system know it's ok to reload the service configuration. - -#### Setting the ulimit - -Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. - -`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes. - -If you see errors such as: - -``` -Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } -``` - -This means that the operating system is preventing network connections from being made. - -##### Set the ulimit via `systemd` service file - -Query the `ulimit` of your mix node with: - -``` -grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits -``` - -You'll get back the hard and soft limits, which looks something like this: - -``` -Max open files 65536 65536 files -``` - -If your output is **the same as above**, your node will not encounter any `ulimit` related issues. - -However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: - -``` -LimitNOFILE=65536 -``` - -Reload the daemon: - -``` -systemctl daemon-reload -``` - -or execute this as root for system-wide setting of `ulimit`: - -``` -echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf -``` - -Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. - -##### Set the ulimit on `non-systemd` based distributions - -Edit `etc/security/conf` and add the following lines: - -``` -# Example hard limit for max opened files -username hard nofile 4096 -# Example soft limit for max opened files -username soft nofile 4096 -``` - -Then reboot your server and restart your mixnode. - -## Node Description -Node description is a short text that describes your node. It is displayed in the `nym-mixnode list` command and in the `nym-mixnode node-details` command. it also shows up in the node explorer to let people know what your node is about and link to your website. - -To set your node description, create a file called `description.toml` and put it in the same directory as your `config.toml` file. The file should look like this: - -```toml -name = "Winston Smith" -description = "I am the Sphinx" -link = "https://nymtech.net" -location = "Giza, Egypt" -``` - -you will need to restart your node for the changes to take effect. - -## Node Families - -Node family involves setting up a group of mix nodes that work together to provide greater privacy and security for network communications. This is achieved by having the nodes in the family share information and routes, creating a decentralized network that makes it difficult for third parties to monitor or track communication traffic. - -### Create a Node Family - -To create a Node family, you will need to install and configure multiple mix nodes, and then use the CLI to link them together into a family. Once your Node family is up and running, you can use it to route your network traffic through a series of nodes, obscuring the original source and destination of the communication. - -You can use either `nym-cli` which can be downloaded from the [release page](https://github.com/nymtech/nym/releases) or compiling `nyxd`. - - -`/path/to/the/release` and run the following on the family head to obtain the signature for the member: - -``` -./nym-mixnode sign --id winston-smithnode --text -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -Using `nym-cli`: - -> `--mnemonic` is the mnemonic of the member wanting to be the head of family. - -``` -/nym-cli cosmwasm execute '{"create_family": {"signature": "","family_head": "","owner_signature":"","label": ""}}' --mnemonic -``` - -Using `nyxd`: - -> `--from` is mnemonic of the member wanting to join the family. - -``` -./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block -``` - -To get the node owner signature, use: - -`./nym-mixnode node-details --id ` - -### Joining a Node Family - -`/path/to/the/release` and run the following on the family head to obtain the signature for the member: - -``` -./nym-mixnode sign --id mixnode --text -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -Using `nym-cli`: - -``` -./nym-cli cosmwasm execute '{"join_family": {"signature": "","family_head": "","owner_signautre": "", "label":""}}' --mnemonic -``` - -Using `nyxd`: - -``` -./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block -``` - - -To get the node owner signature, use: - -`./nym-mixnode node-details --id ` - - -### Leaving a family -If wanting to leave, run the same initial command as above, followed by: - -Using `nym-cli`: - -``` -./nym-cli cosmwasm execute n17srjznxl9dvzdkpwpw24gg668wc73val88a6m5ajg6ankwvz9wtst0cznr '{"leave_family": {"signature": "","family_head": "","owner_signautre": ""}}' --mnemonic -``` - -Using `nyxd`: - -``` -./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block -``` - -## Checking that your node is mixing correctly -### Network explorers -Once you've started your mix node and it connects to the validator, your node will automatically show up in the 'Mix nodes' section of either the Nym Network Explorers: - -- [Mainnet](https://explorer.nymtech.net/overview) -- [Sandbox testnet](https://sandbox-explorer.nymtech.net/) - -Enter your **identity key** to find your node. There are numerous statistics about your node on that page that are useful for checking your uptime history, packets mixed, and any delegations your node may have. - -There are also 2 community explorers which have been created by [Nodes Guru](https://nodes.guru): - -- [Mainnet](https://mixnet.explorers.guru/) -- [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) - -For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) - -### Virtual IPs and hosting via Google & AWS -On some services (AWS, Google, etc), the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `ifconfig`, but also specify `--announce-host` with the public IP. Please make sure that you pass the correct, routable `--announce-host`. - -For example, on a Google machine, you may see the following output from the `ifconfig` command: - -``` -ens4: flags=4163 mtu 1460 - inet 10.126.5.7 netmask 255.255.255.255 broadcast 0.0.0.0 - ... -``` - -The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. - -`nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. - -Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. - -The right thing to do in this situation is `nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18`. - -This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. - -## Metrics / API endpoints -The mix node binary exposes several API endpoints that can be pinged in order to gather information about the node, and the Nym API (previously 'Validator API') exposes numerous mix node related endpoints which provide network-wide information about mix nodes, the network topology (the list of avaliable mix nodes for packet routing), and information regarding uptime monitoring and rewarding history. - -### Mix node API endpoints -Since the mix node binary exposes several API endpoints itself, you can ping these easily via curl: - -| Endpoint | Description | Command | -| -------------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -| `/description` | Returns the description of the node set with the `describe` command | `curl :8000/description` | -| `/hardware` | Returns the hardware information of the node | `curl :8000/hardware` | -| `/verloc` | Returns the verloc information of the node, updated every 12 hours | `curl :8000/verloc` | - -The code for exposed API endpoints can be found [here](https://github.com/nymtech/nym/tree/release/{{platform_release_version}}/mixnode/src/node/http). - -> You can get more detailed info by appending `?debug` to the URL, like so: `curl http://:8000/stats?debug` - -### Mix node related Nym API (previously 'Validator API') endpoints -Numerous endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. - -#### Mix node Reward Estimation API endpoint - -The Reward Estimation API endpoint allows mix node operators to estimate the rewards they could earn for running a Nym mixnode with a specific `mix_id`. - -> The `{mix_id}` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). - -The endpoint is a particularly common for mix node operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mixnode, the quality of the mix node's performance, and the overall demand for mix nodes in the network. This information can be useful for mix node operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability. - -Using this API endpoint returns information about the Reward Estimation: - -``` -/status/mixnode/{mix_id}/reward-estimation -``` - -Query Response: - -``` - "estimation": { - "total_node_reward": "942035.916721770541325331", - "operator": "161666.263307386408152071", - "delegates": "780369.65341438413317326", - "operating_cost": "54444.444444444444444443" - }, -``` - -> The unit of value is measured in `uNYM`. - -- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node. - -- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network. - -- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network. - -- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. - -- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. - -## Ports -All mix node-specific port configuration can be found in `$HOME/.nym/mixnodes//config/config.toml`. If you do edit any port configs, remember to restart your mix node. - -### Mix node port reference -| Default port | Use | -| ------------ | ------------------------- | -| `1789` | Listen for mixnet traffic | -| `1790` | Listen for VerLoc traffic | -| `8000` | Metrics http API endpoint | diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md new file mode 100644 index 0000000000..159251ad3e --- /dev/null +++ b/documentation/docs/src/nodes/mixnode.md @@ -0,0 +1,17 @@ +# Mix Node + +> The mix node setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). + +Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing' or performing the 'poisson mix'. + +Mix nodes perform one task: receiving packets, decrypting their outer 'layer', and holding them for a variable amount of time before passing them to their next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were recieved. + +The aim of this mixing is to protect against timing-based deanonymisation attempts by a global adversary able to monitor the entire network with a 'God's Eye View'. + +## (Coming soon) Mixing: a Step-by-Step Breakdown + +## Further reading +TODO +*
+* +* diff --git a/documentation/docs/src/nodes/network-requester-setup.md b/documentation/docs/src/nodes/network-requester-setup.md deleted file mode 100644 index 6ee560b5b4..0000000000 --- a/documentation/docs/src/nodes/network-requester-setup.md +++ /dev/null @@ -1,255 +0,0 @@ -# Network Requesters - -> The Nym network requester 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 -``` - -``` - - -## Network Requester Whitelist -If you have access to a server, you can run the network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. - -By default the network requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester//`) as a whitelist for outbound requests. - -Any request to a URL which is not on this list will be blocked. - -On startup, if this file is not present, the requester will grab the default whitelist from [here](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) automatically. - -This default whitelist is useful for knowing that the majority of network requesters are able to support certain apps 'out of the box'. - -**Operators of a network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. - -The domains and IPs on the default whitelist can be broken down by application as follows: - -``` -# Keybase -keybaseapi.com -s3.amazonaws.com -amazonaws.com -twitter.com -keybase.io -gist.githubusercontent.com - -# Used to for uptime healthcheck (see the section on testing your requester below for more) -nymtech.net - -# Blockstream Green Bitcoin Wallet -blockstream.info -blockstream.com -greenaddress.it - -# Electrum Bitcoin Wallet -electrum.org - -# Helios Ethereum Client -alchemy.com -lightclientdata.org -p2pify.com - -# Telegram - these IPs have been copied from https://core.telegram.org/resources/cidr.txt as Telegram does -# not seem to route by domain as the other apps on this list do -91.108.56.0/22 -91.108.4.0/22 -91.108.8.0/22 -91.108.16.0/22 -91.108.12.0/22 -149.154.160.0/20 -91.105.192.0/23 -91.108.20.0/22 -185.76.151.0/24 -2001:b28:f23d::/48 -2001:b28:f23f::/48 -2001:67c:4e8::/48 -2001:b28:f23c::/48 -2a0a:f280::/32 -``` - -## Network Requester Directory -You can find a list of Network Requesters running the default whitelist [here](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. - -> We are currently working on a smart-contract based solution more in line with how Mix nodes and Gateways announce themselves to the network. - -## Viewing command help - -The `./nym-network-requester --help ` command can be used to show a list of available parameters. - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - -You can check the required parameters for available commands by running: - -``` -./nym-network-requester --help -``` - -## Initializing and running your network requester - -The network-requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `id` using the `--id` command and give it a value of your choosing. The following command will achieve that: - -``` - ./nym-network-requester init --id example -``` - -~~~admonish example collapsible=true title="Console output" -``` - -``` -~~~ - - -Now that we have initialized our network-requester, we can start it with the following command: - -``` - ./nym-network-requester run --id example -``` - -## Upgrading your network requester -You can upgrade your network requester by following these steps: - -* stop your network requester service -* replace the old binary with the new binary -* restart your service using the commands in the previous section of the document - -### Upgrading to >= v1.1.10 from -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 - -[Install] -WantedBy=multi-user.target -``` - -Now enable and start your requester: - -``` -systemctl enable nym-network-requester.service -systemctl start nym-network-requester.service - -# you can always check your requester has succesfully started with: -systemctl status nym-network-requester.service -``` - -## VPS Setup -### Configure your firewall -Although your requester is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: - -``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status -``` - -Finally open your requester's p2p port, as well as ports for ssh and incoming traffic connections: - -``` -sudo ufw allow 22,9000/tcp -# check the status of the firewall -sudo ufw status -``` - -For more information about your requester's port configuration, check the [requester port reference table](./network-requester-setup.md#requester-port-reference) below. - -## Using your network requester - -The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make network requests to any system on the internet. - -To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list`. - -### Supporting custom domains with your network requester -It is easy to add new domains and services to your network requester - simply find out which endpoints (both URLs and raw IP addresses are supported) you need to whitelist, and then add these endpoints to your `allowed.list`. - -How to go about this? Have a look in your nym-network-requester config directory: - -``` -ls $HOME/.nym/service-providers/network-requester/ - -# returns: allowed.list unknown.list -``` - -We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](../clients/socks5-client.md) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to restart your network requester! - -> If you are adding custom domains, please note that whilst they may appear in the logs of your network-requester as something like `api-0.core.keybaseapi.com:443`, you **only need** to include the main domain name, in this instance `keybaseapi.com` - -### Running an open proxy -If you *really* want to run an open proxy, perhaps for testing purposes for your own use or among a small group of trusted friends, it is possible to do so. You can disable network checks by passing the flag `--open-proxy` flag when you run it. If you run in this configuration, you do so at your own risk. - -## Testing your network requester -1. Add `nymtech.net` to your `allowed.list` (remember to restart your network requester). - -2. Ensure that your network-requester is initialized and running. - -3. In another terminal window, run the following: - -``` -curl -x socks5h://localhost:1080 https://nymtech.net/.wellknown/connect/healthcheck.json -``` - -This command should return the following: - -``` -{ "status": "ok" } -``` - - -## Ports -### Requester port reference - -All network-requester-specific port configuration can be found in `$HOME/.nym/service-providers/network-requester//config/config.toml`. If you do edit any port configs, remember to restart your client and requester processes. - -| Default port | Use | -|--------------|---------------------------| -| 9000 | Listen for Client traffic | diff --git a/documentation/docs/src/nodes/network-requester.md b/documentation/docs/src/nodes/network-requester.md new file mode 100644 index 0000000000..797dfd7795 --- /dev/null +++ b/documentation/docs/src/nodes/network-requester.md @@ -0,0 +1 @@ +# Network Requester diff --git a/documentation/docs/src/nodes/overview.md b/documentation/docs/src/nodes/overview.md new file mode 100644 index 0000000000..497a347365 --- /dev/null +++ b/documentation/docs/src/nodes/overview.md @@ -0,0 +1,9 @@ +# Node Types + +> This section was previously the node setup guides. These have been migrated to their own [**Operator Guides**](https://nymtech.net/operators) book. +> +> For setup and maintenance guides, go to the Operators book linked above. +> +> This section is a little spartan for the moment, but we will be adding detailed information about how exactly each node functions, as well as references to any literature and technical specs in the near future. + +This section contains information on the different node types of the mixnet and blockchain. \ No newline at end of file diff --git a/documentation/docs/src/nodes/setup-guides.md b/documentation/docs/src/nodes/setup-guides.md deleted file mode 100644 index 02a23ebff6..0000000000 --- a/documentation/docs/src/nodes/setup-guides.md +++ /dev/null @@ -1,8 +0,0 @@ -# Node Setup Guides - -This section contains setup guides for the following node types: -* [Mix node](./mix-node-setup.md) -* [Gateway](./gateway-setup.md) -* [Network Requester](./network-requester-setup.md) -* [Validator](./validator-setup.md) - diff --git a/documentation/docs/src/nodes/troubleshooting.md b/documentation/docs/src/nodes/troubleshooting.md deleted file mode 100644 index e832edbc39..0000000000 --- a/documentation/docs/src/nodes/troubleshooting.md +++ /dev/null @@ -1,368 +0,0 @@ -# Troubleshooting - - -## Binary Build Problems - -### I am trying to build from the GitHub archive files and the build fails - -GitHub automatically includes .zip and tar.gz files of the Nym repository in its release. You cannot extract these and build - you'll see something like this: - -``` - process didn't exit successfully: `/build/nym/src/nym-0.12.1/target/release/build/nym-socks5-client-c1d0f76a8c7d7e9a/build-script-build` (exit status: 101) - --- stderr - thread 'main' panicked at 'failed to extract build metadata: could not find repository from '/build/nym/src/nym-0.12.1/clients/socks5'; class=Repository (6); code=NotFound (-3)', clients/socks5/build.rs:7:31 - note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -warning: build failed, waiting for other jobs to finish... -error: build failed -``` - -Why does this happen? - -We have scripts which automatically include the Git commit hash and Git tag in the binary for easier debugging later. If you download a .zip and try building from that, it's not a Git repository and build will fail as above. - -## General Node Config - -### Where can I find my private and public keys and config? - -All config and keys files are stored in a directory named after your `id` which you chose during the `init` process, and can be found at the following PATH: `$HOME/.nym//` where `$HOME` is a home directory of the user (your current user in this case) that launched the node or client. - -The directory structure for each node will be roughly as follows: - -``` -bob@nym:~$ tree /home/nym/.nym/mixnodes/ -/home/nym/.nym/mixnodes/ -|-- nym010 -| |-- config -| | `-- config.toml -| `-- data -| |-- private_identity.pem -| |-- private_sphinx.pem -| |-- public_identity.pem -| `-- public_sphinx.pem -``` - -> If you `cat` the `public_sphinx.pem key`, the output will be different from the public key you will see on Nym [dashboard](https://sandbox-explorer.nymtech.net/). The reason for this is that `.pem` files are encoded in **base64**, however on the web they are in **base58**. Don't be confused if your keys look different. They are the same keys, just with different encoding :) - - -## Mix Nodes - -### How can I tell my node is up and running and mixing traffic? - -First of all check the 'Mixnodes' section of either the Nym Network Explorers: -* [Mainnet](https://explorer.nymtech.net/overview) -* [Sandbox testnet](https://sandbox-explorer.nymtech.net/) - -Enter your **identity key** to find your node. Check the contents of the 'mixnode stats' and 'uptime story' sections. - -There are 2 community explorers currently, which have been created by [Nodes Guru](https://nodes.guru): -* [Mainnet](https://mixnet.explorers.guru/) -* [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) - -If you want more information, or if your node isn't showing up on the explorer of your choice and you want to double-check, here are some examples on how to check if the node is configured properly. - -#### Check from your VPS - -Additional details can be obtained via various methods after you connect to your VPS: - -##### Socket statistics with `ss` - -``` -sudo ss -s -t | grep 1789 # if you have specified a different port in your mixnode config, change accordingly -``` - -This command should return a lot of data containing `ESTAB`. This command should work on every unix based system. - -##### List open files and reliant processes with `lsof` - -``` -# check if lsof is installed: -lsof -v -# install if not installed -sudo apt install lsof -# run against mixnode port -sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly -``` - -This command should return something like this: - -``` -nym-mixno 103349 root 53u IPv6 1333229972 0t0 TCP [2a03:b0c0:3:d0::ff3:f001]:57844->[2a01:4f9:c011:38ae::5]:1789 (ESTABLISHED) -nym-mixno 103349 root 54u IPv4 1333229973 0t0 TCP nym:57104->194.5.78.73:1789 (ESTABLISHED) -nym-mixno 103349 root 55u IPv4 1333229974 0t0 TCP nym:48130->static.236.109.119.168.clients.your-server.de:1789 (ESTABLISHED) -nym-mixno 103349 root 56u IPv4 1333229975 0t0 TCP nym:52548->vmi572614.contaboserver.net:1789 (ESTABLISHED) -nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3:f001]:43244->[2600:1f18:1031:2401:c04b:2f25:ca79:fef3]:1789 (ESTABLISHED) -``` - -##### Query `systemd` journal with `journalctl` - -``` -sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed" -``` - -If you have created `nym-mixnode.service` file (i.e. you are running your mixnode via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: - -``` -2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets! -2021-05-18T12:38:02.178Z INFO nym_mixnode::node::metrics > Since startup mixed 233739 packets! -2021-05-18T12:40:32.344Z INFO nym_mixnode::node::metrics > Since startup mixed 233837 packets! -2021-05-18T12:46:08.549Z INFO nym_mixnode::node::metrics > Since startup mixed 234081 packets! -2021-05-18T12:56:57.129Z INFO nym_mixnode::node::metrics > Since startup mixed 234491 packets! -``` - -You can add ` | tail` to the end of the command to watch for new entries in real time if needed. - -#### Check from your local machine - -##### Scan ports with `nmap`: - -``` -nmap -p 1789 -Pn -``` - -If your mixnode is configured properly it should output something like this: - -``` -bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn - -Host is up (0.053s latency). - -PORT STATE SERVICE -1789/tcp open hello -``` - -##### Query online nodes: - -``` -curl --location --request GET 'https://validator.nymtech.net/api/v1/mixnodes/' -``` - -Will return a list all nodes currently online. - -You can query gateways by replacing `mixnodes` with `gateways` in the above command, and can query for the mixnodes and gatways on the Sandbox testnet by replacing `validator` with `sandbox-validator`. - - -#### Check with Network API - -We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mixnode, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](../nodes/mix-node-setup.md#metrics--api-endpoints). - -### Why is my node not mixing any packets? - -If you are still unable to see your node on the dashboard, or your node is declaring it has not mixed any packets, there are several potential issues: - -- The firewall on your host machine is not configured properly. -- You provided incorrect information when bonding your node. -- You are running your mixnode from a VPS without IPv6 support. -- You did not use the `--announce-host` flag while running the mixnode from your local machine behind NAT. -- You did not configure your router firewall while running the mixnode from your local machine behind NAT, or you are lacking IPv6 support. -- Your mixnode is not running at all, it has either exited / panicked or you closed the session without making the node persistent. - -```admonish caution -Your mixnode **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! -``` - -#### Incorrectly configured firewall - -The most common reason your mixnode might not be mixing packets is due to a poorly configured firewall. The following commands will allow you to set up a firewall using `ufw`. - -``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status -``` - -Finally open your mixnode's p2p port, as well as ports for ssh, http, and https connections, and ports `8000` and `1790` for verloc and measurement pings: - -``` -sudo ufw allow 1789,1790,8000,22,80,443/tcp -# check the status of the firewall -sudo ufw status -``` - -#### Incorrect bonding information - -Check that you have provided the correct information when bonding your mixnode in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, unbond and then rebond your node! - -#### Missing `announce-host` flag - -On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mixnode host. - -#### No IPv6 connectivity - -Make sure that your VPS has IPv6 connectivity available with whatever provider you are using. - -To get all ip addresses of your host, try following commands: - -``` -hostname -i -``` - -Will return your **local ip** address. - -``` -hostname -I -``` - -Will return all of the ip addresses of your host. This output should look something like this: - -``` -bob@nym:~$ hostname -I -88.36.11.23 172.18.0.1 2a01:28:ca:102::1:641 -``` - -- The first **ipv4** is the public ip you need to use for the `--announce-host` flag. -- The second **ipv4** is the local ip you need to use for the `--host` flag. -- The 3rd output should confirm if your machine has ipv6 available. - -### Running on a local machine behind NAT with no fixed IP address - -Your ISP has to be IPv6 ready if you want to run a mixnode on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. - -Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! - -If all goes well and you have IPv6 available, then you will need to `init` the mixnode with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. - -Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support. - -Here is a sample of the `init` command to create the mixnode config. - -``` -./target/release/nym-mixnode init --id nym-nat --host 0.0.0.0 --announce-host 85.160.12.13 --layer 3 -``` - -- `--host 0.0.0.0` should work everytime even if your local machine IPv4 address changes. For example on Monday your router gives your machine an address `192.168.0.13` and on Wednesday, the DHCP lease will end and you will be asigned `192.168.0.14`. Using `0.0.0.0` should avoid this without having to set any static ip in your router`s configuration. - -- you can get your current IPv4 address by either using `curl ipinfo.io` if you're on MacOS or Linux or visiting [whatsmyip site](https://www.whatsmyip.org/). Simply copy it and use it as `--anounce-host` address. - -Make sure you check if your node is really mixing. You will need a bit of luck to set this up from your home behind NAT. - -### Accidentally killing your node process on exiting session - -When you close your current terminal session, you need to make sure you don't kill the mixnode process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `nohup`, and the more elegant solution is to run the node with `systemd`. - -### Running your mixnode as a background process with `nohup` - -`nohup` is a command with which your terminal is told to ignore the `HUP` or 'hangup' signal. This will stop the mixnode process ending if you kill your session. - -``` -nohup ./nym-mixnode run --id NYM # where `--id NYM` is the id you set during the `init` command. -``` - -### Running your mixnode as a background process with `systemd` - -The most reliable and elegant solution is to create a `systemd.service` file and run the nym-mixnode with `systemctl` command. - -Create a file with `nano` at `/etc/systemd/system/nym-mixnode.service` containing the following: - -```ini -[Unit] -Description=nym mixnode service -After=network.target - -[Service] -Type=simple -User=nym # change as appropriate -LimitNOFILE=65536 -ExecStart=/home/nym/nym-mixnode run --id nym # change as appropriate -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 -Restart=on-abort -[Install] -WantedBy=multi-user.target -``` - -``` -# enable the service -sudo systemctl enable nym-mixnode -# start the service -sudo systemctl start nym-mixnode -# check if the service is running properly and mixnode is mixing -sudo systemctl status nym-mixnode -``` - -Now your node should be mixing all the time, and restart if you reboot your server! - -Anytime you change your `systemd` service file you need to `sudo systemctl daemon-reload` in order to restart the service. - -### Network configuration seems fine but log still claims `Since startup mixed 0 packets!` - -This behavior is most likely caused by a mismatch between your node configuration and the bonding information. Unbond and then rebond your node. - -Also make sure to enter all the information in the web wallet exactly as it appears in the log when you start the mixnode process. In particular, the `host` field must contain the _port_ on which your mixnode will listen: - -- correct host: `34.12.3.43:1789` -- incorrect host:`34.12.3.43` - -### Common errors and warnings - -Most of the `ERROR` and `WARN` messages in your node logs are benign - as long as your node outputs `since startup mixed X packets!` in your logs (and this number increases over time), your node is mixing packets. If you want to be sure, check the Nym [dashboard](https://sandbox-explorer.nymtech.net/) or see other ways on how to check if your node is mixing properly as outlined in the section **How can I tell my node is up and running and mixing traffic?** above. - -More specific errors and warnings are covered below. - -#### `tokio runtime worker` error - -If you are running into issues with an error including the following: - -``` -thread 'tokio-runtime-worker' panicked at 'Failed to create TCP listener: Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }' -``` - -Then you need to `--announce-host ` and ``--host ` on startup. This issue arises because of your use of a provider like AWS or Google Cloud, and the fact that your VPS' available bind address is not the same as the public IP address (see [Virtual IPs and hosting via Google and AWS](../nodes/mix-node-setup.md#virtual-ips-and-hosting-via-google--aws) for more information on this issue). - -#### `rocket::launch` warnings -These warnings are not an issue, please ignore them. Rocket is a web framework for rust which we are using to provide mixnodes with `/verloc` and `/description` http APIs. - -Find more information about this in the [Mixnodes metrics documentation](../nodes/mix-node-setup.md#metrics--api-endpoints). - -Rocket runs on port `8000` by default. Although at this stage of the testnet we need Rocket to be reachable via this port, in the future customization of the particular port it uses will be possible. - -#### `failed to receive reply to our echo packet within 1.5s. Stopping the test` - -This relates to the VerLoc implementation that appeared in `0.10.1`, which has a particularly high log sensitivity. This warning means that the echo packet sent to the mixnode was received, but not sent back. _This will not affect the rate of rewards or performance metrics of your mixnode in the testnet at this point._ - -#### `Connection to :1789 seems to be dead` - -This warning is normal at the moment, and is _nothing to do with your mixnode!_ It is simply a warning that your node is unable to connect to other peoples' mixnodes for some reason, most likely because they are offline or poorly configured. - -### Can I use a port other than 1789 ? - -Yes! Here is what you will need to do: - -Assuming you would like to use port `1337` for your mixnode, you need to open the new port (and close the old one): - -``` -sudo ufw allow 1337 -sudo ufw deny 1789 -``` - -And then edit the mixnode's config. - -> If you want to change the port for an already running node, you need to stop the process before editing your config file. - -Assuming your node name is `nym`, the config file is located at `~/.nym/mixnodes/nym/config/config.toml`. - -``` -nano ~/.nym/mixnodes/nym/config/config.toml -``` - -You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. - -Finally, restart your node. You should see if the mixnode is using the port you have changed in the config.toml file right after you run the node. - -### What is `verloc` and do I have to configure my mixnode to implement it? - -`verloc` is short for _verifiable location_. Mixnodes and gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fakeable and trustworthy manner. - -You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet from version `0.10.1` onwards. - - -### Where can I get more help? - -The fastest way to reach one of us or get a help from the community, visit our [Telegram help chat](https://t.me/nymchan_help_chat) or head to our [Discord](https://Discord.gg/nym) - -For more tech heavy questions join our Keybase channel. Get Keybase [here](https://keybase.io/), then click Teams -> Join a team. Type nymtech.friends into the team name and hit continue. For general chat, hang out in the #general channel. diff --git a/documentation/docs/src/nodes/validator-setup.md b/documentation/docs/src/nodes/validator-setup.md deleted file mode 100644 index 053a19253d..0000000000 --- a/documentation/docs/src/nodes/validator-setup.md +++ /dev/null @@ -1,669 +0,0 @@ -# Validators - -The validator is built using [Cosmos SDK](https://cosmos.network) and [Tendermint](https://tendermint.com), with a [CosmWasm](https://cosmwasm.com) smart contract controlling the directory service, node bonding, and delegated mixnet staking. - -## Building your validator -### Prerequisites -#### `git`, `gcc`, `jq` -* Debian-based systems: -``` -apt install git build-essential jq - -# optional additional manual pages can be installed with: -apt-get install manpages-dev -``` - -* Arch-based systems: -Install `git`, `gcc` and `jq` with the following: -``` -pacman -S git gcc jq -``` - -#### `Go` -`Go` can be installed via the following commands (taken from the [Agoric SDK docs](https://github.com/Agoric/agoric-sdk/wiki/Validator-Guide-for-Incentivized-Testnet#install-go)): - -``` -# First remove any existing old Go installation -sudo rm -rf /usr/local/go - -# Install correct Go version -curl https://dl.google.com/go/go1.20.4.linux-amd64.tar.gz | sudo tar -C/usr/local -zxvf - - -# Update environment variables to include go -cat <<'EOF' >>$HOME/.profile -export GOROOT=/usr/local/go -export GOPATH=$HOME/go -export GO111MODULE=on -export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin -EOF -source $HOME/.profile -``` - -Verify `Go` is installed with: - -``` -go version -# Should return something like: -go version go1.20.4 linux/amd64 -``` - -### Download a precompiled validator binary -You can find pre-compiled binaries for Ubuntu `22.04` and `20.04` [here](https://github.com/nymtech/nyxd/releases). - -```admonish caution title="" -There are seperate releases for Mainnet and the Sandbox testnet - make sure to download the correct binary to avoid `bech32Prefix` mismatches. -``` - -### Manually compiling your validator binary -The codebase for the Nyx validators can be found [here](https://github.com/nymtech/nyxd). - -The validator binary can be compiled by running the following commands: -``` -git clone https://github.com/nymtech/nyxd.git -cd nyxd -git checkout release/ - -# Mainnet -make build - -# Sandbox testnet -BECH32_PREFIX=nymt make build -``` - -At this point, you will have a copy of the `nyxd` binary in your `build/` directory. Test that it's compiled properly by running: - -``` -./build/nyxd -``` - -You should see help text print out. - -### Linking `nyxd` to `libwasmvm.so` - -`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1`. - -If you downloaded your `nyxd` binary from Github, you will have seen this file when un-`tar`-ing the `.tar.gz` file from the releases page. - -If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.so` file to correct location. - -Simply `cp` or `mv` that file to `/lib/x86_64-linux-gnu/` and re-run `nyxd`. - -### Adding `nyxd` to your `$PATH` -You'll need to set `LD_LIBRARY_PATH` in your user's `~/.bashrc` file, and add that to our path. Replace `/home/youruser/path/to/nym/binaries` in the command below to the locations of `nyxd` and `libwasmvm.so` and run it. If you have compiled these on the server, they will be in the `build/` folder: - -``` -NYX_BINARIES=/home/youruser/path/to/validator/binary - -# if you are using another shell like zsh replace '.bashrc' with the relevant config file -echo 'export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:'NYX_BINARIES >> ~/.bashrc -echo 'export PATH=$PATH:'${NYX_BINARIES} >> ~/.bashrc -source ~/.bashrc -``` - -Test everything worked: - -``` -nyxd -``` - -This should return the regular help text. - -## Initialising your validator -### Prerequisites: - -- FQDN Domain name -- IPv4 and IPv6 connectivity - -Choose a name for your validator and use it in place of `` in the following command: - -``` -# Mainnet -nyxd init --chain-id=nyx - -# Sandbox testnet -nyxd init --chain-id=sandbox -``` - -```admonish caution title="" -`init` generates `priv_validator_key.json` and `node_key.json`. - -If you have already set up a validator on a network, **make sure to back up the key located at** -`~/.nyxd/config/priv_validator_key.json`. - -If you don't save the validator key, then it can't sign blocks and will be jailed all the time, and -there is no way to deterministically (re)generate this key. -``` - -At this point, you have a new validator, with its own genesis file located at `$HOME/.nyxd/config/genesis.json`. You will need to replace the contents of that file that with either the Nyx Mainnet or Sandbox Testnet genesis file. - -You can use the following command to download them for the correct network: - -``` -# Mainnet -wget -O $HOME/.nyxd/config/genesis.json https://nymtech.net/genesis/genesis.json - -# Sandbox testnet -wget -O $HOME/.nyxd/config/genesis.json https://sandbox-validator1.nymtech.net/snapshots/genesis.json -``` - -### `config.toml` configuration - -Edit the following config options in `$HOME/.nyxd/config/config.toml` to match the information below for your network: - -``` -# Mainnet -persistent_peers = "ee03a6777fb76a2efd0106c3769daaa064a3fcb5@51.79.21.187:26656" -create_empty_blocks = false -laddr = "tcp://0.0.0.0:26656" -``` - -``` -# Sandbox testnet -cors_allowed_origins = ["*"] -persistent_peers = "8421c0a3d90d490e27e8061f2abcb1276c8358b6@sandbox-validator1.nymtech.net:26666" -create_empty_blocks = false -laddr = "tcp://0.0.0.0:26656" -``` - -These affect the following: -* `persistent_peers = "@.nymtech.net:26666"` allows your validator to start pulling blocks from other validators. **The main sandbox validator listens on `26666` instead of the default `26656` for debugging**. It is recommended you do not change your port from `26656`. -* `create_empty_blocks = false` will save space -* `laddr = "tcp://0.0.0.0:26656"` is in your p2p configuration options - -Optionally, if you want to enable [Prometheus](https://prometheus.io/) metrics then the following must also match in the `config.toml`: - -- `prometheus = true` -- `prometheus_listen_addr = ":26660"` - -> Remember to enable metrics in the 'Configuring Prometheus metrics' section below as well. - -And if you wish to add a human-readable moniker to your node: - -- `moniker = "yourname"` - -Finally, if you plan on using [Cockpit](https://cockpit-project.org/documentation.html) on your server, change the `grpc` port from `9090` as this is the port used by Cockpit. - -### `app.toml` configuration -In the file `$HOME/nyxd/config/app.toml`, set the following values: - -``` -# Mainnet -minimum-gas-prices = "0.025unym,0.025unyx" -enable = true in the `[api]` section to get the API server running -``` -``` -# Sandbox Testnet -minimum-gas-prices = "0.025unymt,0.025unyxt" -enable = true` in the `[api]` section to get the API server running -``` - -### Setting up your validator's admin user -You'll need an admin account to be in charge of your validator. Set that up with: - -``` -nyxd keys add nyxd-admin -``` - -This will add keys for your administrator account to your system's keychain and log your name, address, public key, and mnemonic. As the instructions say, remember to **write down your mnemonic**. - -You can get the admin account's address with: - -``` -nyxd keys show nyxd-admin -a -``` - -Type in your keychain **password**, not the mnemonic, when asked. - -## Starting your validator - -```admonish caution title="" -If you are running a Sandbox testnet validator, please skip the `validate-genesis` command: it will fail due to the size of the genesis file as this is a fork of an existing chain state. -``` - -Everything should now be ready to go. You've got the validator set up, all changes made in `config.toml` and `app.toml`, the Nym genesis file copied into place (replacing the initial auto-generated one). Now let's validate the whole setup: - -``` -nyxd validate-genesis -``` - -If this check passes, you should receive the following output: - -``` -File at /path/to/genesis.json is a valid genesis file -``` - -> If this test did not pass, check that you have replaced the contents of `/path/to/.nymd/config/genesis.json` with that of the correct genesis file. - -Before starting the validator, we will need to open the firewall ports: - -``` -# if ufw is not already installed: -sudo apt install ufw -sudo ufw enable -sudo ufw allow 1317,26656,26660,22,80,443/tcp -# to check everything worked -sudo ufw status -``` - -Ports `22`, `80`, and `443` are for ssh, http, and https connections respectively. The rest of the ports are documented [here](https://docs.cosmos.network/v0.42/core/grpc_rest.html). - -For more information about your validator's port configuration, check the [validator port reference table](#validator-port-reference) below. - -> If you are planning to use [Cockpit](https://cockpit-project.org/) on your validator server then you will have defined a different `grpc` port in your `config.toml` above: remember to open this port as well. - -Start the validator: - -``` -nyxd start -``` - -Once your validator starts, it will start requesting blocks from other validators. This may take several hours. Once it's up to date, you can issue a request to join the validator set with the command below. - -### Syncing from a snapshot -If you wish to sync from a snapshot on **mainnet** use Polkachu's [mainnet](https://polkachu.com/networks/nym) resources. - -If you wish to sync from a snapshot on **Sandbox testnet** use the below commands, which are a modified version of Polkachu's excellent resources. These commands assume you are running an OS with `apt` as the package manager: - -``` -# install lz4 if necessary -sudo apt install snapd -y -sudo snap install lz4 - -# download the snapshot -wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://sandbox-validator1.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4 - -# reset your validator state -nyxd tendermint unsafe-reset-all - -# unpack the snapshot -lz4 -c -d nyxd-sandbox-snapshot-data.tar.lz4 | tar -x -C $HOME/.nyxd -``` - -You can then restart `nyxd` - it should start syncing from a block > 2000000. - -### Joining Consensus -```admonish caution title="" -When joining consensus, make sure that you do not disrupt (or worse - halt) the network by coming in with a disproportionately large amount of staked tokens. - -Please initially stake a small amount of tokens compared to existing validators, then delegate to yourself in tranches over time. -``` - -Once your validator has synced and you have received tokens, you can join consensus and produce blocks. - -``` -# Mainnet -nyxd tx staking create-validator - --amount=10000000unyx - --fees=0unyx - --pubkey=$(/home/youruser/path/to/nyxd/binaries/nyxd tendermint show-validator) - --moniker="whatever you called your validator" - --chain-id=nyx - --commission-rate="0.10" - --commission-max-rate="0.20" - --commission-max-change-rate="0.01" - --min-self-delegation="1" - --gas="auto" - --gas-adjustment=1.15 - --from="KEYRING_NAME" - --node https://rpc-1.nyx.nodes.guru:443 -``` -``` -# Sandbox Testnet -nyxd tx staking create-validator - --amount=10000000unyxt - --fees=5000unyxt - --pubkey=$(/home/youruser/path/to/nym/binaries/nyxd tendermint show-validator) - --moniker="whatever you called your validator" - --chain-id=sandbox - --commission-rate="0.10" - --commission-max-rate="0.20" - --commission-max-change-rate="0.01" - --min-self-delegation="1" - --gas="auto" - --gas-adjustment=1.15 - --from="KEYRING_NAME" - --node https://sandbox-validator1.nymtech.net:443 -``` - -You'll need either `unyxt` tokens on Sandbox, or `unyx` tokens on mainnet to perform this command. - -> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. - -If you want to edit some details for your node you will use a command like this: - -``` -# Mainnet -nyxd tx staking edit-validator - --chain-id=nyx - --moniker="whatever you called your validator" - --details="Nyx validator" - --security-contact="your email" - --identity="your identity" - --gas="auto" - --gas-adjustment=1.15 - --from="KEYRING_NAME" - --fees 2000unyx -``` -``` -# Sandbox testnet -nyxd tx staking edit-validator - --chain-id=sandbox - --moniker="whatever you called your validator" - --details="Sandbox testnet validator" - --security-contact="your email" - --identity="your identity" - --gas="auto" - --gas-adjustment=1.15 - --from="KEYRING_NAME" - --fees 2000unyxt -``` - -With above command you can specify the `gpg` key last numbers (as used in `keybase`) as well as validator details and your email for security contact. - -### Automating your validator with systemd -You will most likely want to automate your validator restarting if your server reboots. Below is a systemd unit file to place at `/etc/systemd/system/nymd.service`: - -```ini -[Unit] -Description=Nyxd -StartLimitInterval=350 -StartLimitBurst=10 - -[Service] -User=nyx # change to your user -Type=simple -Environment="LD_LIBRARY_PATH=/home/youruser/path/to/nyx/binaries" # change to correct path -ExecStart=/home/youruser/path/to/nyx/binaries/nymd start # change to correct path -Restart=on-failure -RestartSec=30 -LimitNOFILE=infinity - -[Install] -WantedBy=multi-user.target -``` - -Proceed to start it with: - -``` -systemctl daemon-reload # to pickup the new unit file -systemctl enable nymd # to enable the service -systemctl start nymd # to actually start the service -journalctl -f # to monitor system logs showing the service start -``` - -### Installing and configuring nginx for HTTPS -#### Setup -[Nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.) is an open source software used for operating high-performance web servers. It allows us to set up reverse proxying on our validator server to improve performance and security. - -Install `nginx` and allow the 'Nginx Full' rule in your firewall: - -``` -sudo ufw allow 'Nginx Full' -``` - -Check nginx is running via systemctl: - -``` -systemctl status nginx -``` - -Which should return: - -``` -● nginx.service - A high performance web server and a reverse proxy server - Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) - Active: active (running) since Fri 2018-04-20 16:08:19 UTC; 3 days ago - Docs: man:nginx(8) - Main PID: 2369 (nginx) - Tasks: 2 (limit: 1153) - CGroup: /system.slice/nginx.service - ├─2369 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; - └─2380 nginx: worker process -``` - -#### Configuration - -Proxying your validator's port `26657` to nginx port `80` can then be done by creating a file with the following at `/etc/nginx/conf.d/validator.conf`: - -``` -server { - listen 80; - listen [::]:80; - server_name "domain_name"; - - location / { - proxy_pass http://127.0.0.1:26657; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } -} -``` - -Followed by: - -``` -sudo apt install certbot nginx python3 -certbot --nginx -d nym-validator.yourdomain.com -m you@yourdomain.com --agree-tos --noninteractive --redirect -``` - -```admonish caution title="" -If using a VPS running Ubuntu 20: replace `certbot nginx python3` with `python3-certbot-nginx` -``` - -These commands will get you an https encrypted nginx proxy in front of the API. - -### Configuring Prometheus metrics (optional) - -Configure Prometheus with the following commands (adapted from NodesGuru's [Agoric setup guide](https://nodes.guru/agoric/setup-guide/en)): - -``` -echo 'export OTEL_EXPORTER_PROMETHEUS_PORT=9464' >> $HOME/.bashrc -source ~/.bashrc -sed -i '/\[telemetry\]/{:a;n;/enabled/s/false/true/;Ta}' $HOME/.nymd/config/app.toml -sed -i "s/prometheus-retention-time = 0/prometheus-retention-time = 60/g" $HOME/.nymd/config/app.toml -sudo ufw allow 9464 -echo 'Metrics URL: http://'$(curl -s ifconfig.me)':26660/metrics' -``` - -Your validator's metrics will be available to you at the returned 'Metrics URL'. - -~~~admonish example collapsible=true title="Console output" -``` -# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles. -# TYPE go_gc_duration_seconds summary -go_gc_duration_seconds{quantile="0"} 6.7969e-05 -go_gc_duration_seconds{quantile="0.25"} 7.864e-05 -go_gc_duration_seconds{quantile="0.5"} 8.4591e-05 -go_gc_duration_seconds{quantile="0.75"} 0.000115919 -go_gc_duration_seconds{quantile="1"} 0.001137591 -go_gc_duration_seconds_sum 0.356555301 -go_gc_duration_seconds_count 2448 -# HELP go_goroutines Number of goroutines that currently exist. -# TYPE go_goroutines gauge -go_goroutines 668 -# HELP go_info Information about the Go environment. -# TYPE go_info gauge -go_info{version="go1.15.7"} 1 -# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use. -# TYPE go_memstats_alloc_bytes gauge -go_memstats_alloc_bytes 1.62622216e+08 -# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed. -# TYPE go_memstats_alloc_bytes_total counter -go_memstats_alloc_bytes_total 2.09341707264e+11 -# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table. -# TYPE go_memstats_buck_hash_sys_bytes gauge -go_memstats_buck_hash_sys_bytes 5.612319e+06 -# HELP go_memstats_frees_total Total number of frees. -# TYPE go_memstats_frees_total counter -go_memstats_frees_total 2.828263344e+09 -# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started. -# TYPE go_memstats_gc_cpu_fraction gauge -go_memstats_gc_cpu_fraction 0.03357798610671518 -# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata. -# TYPE go_memstats_gc_sys_bytes gauge -go_memstats_gc_sys_bytes 1.3884192e+07 -``` -~~~ - -### Setting the ulimit -Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. - -`ulimit` is 1024 by default on most systems. It needs to be set higher, because validators make and receive a lot of connections to other nodes. - -If you see errors such as: - -``` -Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } -``` - -This means that the operating system is preventing network connections from being made. - -##### Set the ulimit via `systemd` service file -Query the `ulimit` of your validator with: - -``` -grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nymd | grep -v grep |head -n 1 | awk '{print $1}')/limits -``` - -You'll get back the hard and soft limits, which looks something like this: - -``` -Max open files 65536 65536 files -``` - -If your output is **the same as above**, your node will not encounter any `ulimit` related issues. - -However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: - -``` -LimitNOFILE=65536 -``` - -Reload the daemon: - -``` -systemctl daemon-reload -``` - -or execute this as root for system-wide setting of `ulimit`: - -``` -echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf -``` - -Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-validator)/limits | grep "Max open files"` to make sure the limit has changed to 65535. - -##### Set the ulimit on `non-systemd` based distributions -Edit `etc/security/conf` and add the following lines: - -``` -# Example hard limit for max opened files -username hard nofile 4096 -# Example soft limit for max opened files -username soft nofile 4096 -``` - -Then reboot your server and restart your validator. - -## Using your validator -### Unjailing your validator -If your validator gets jailed, you can fix it with the following command: - -``` -# Mainnet -nyxd tx slashing unjail - --broadcast-mode=block - --from="KEYRING_NAME" - --chain-id=nyx - --gas=auto - --gas-adjustment=1.4 - --fees=7000unyx -``` -``` -# Sandbox Testnet -nyxd tx slashing unjail - --broadcast-mode=block - --from="KEYRING_NAME" - --chain-id=sandbox - --gas=auto - --gas-adjustment=1.4 - --fees=7000unyxt -``` - -### Upgrading your validator - -Upgrading from `v0.31.1` -> `v0.32.0` process is fairly simple. Grab the `v0.32.0` release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files: - -- the new validator (`nyxd`) v0.32.0 -- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`) - -Wait for the upgrade height to be reached and the chain to halt awaiting upgrade, then: - -* copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`) replacing your existing file with the same name. -* swap in your new `nyxd` binary and restart. - -You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/9). - -Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. - -#### Common reasons for your validator being jailed - -The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. - -Running the command `df -H` will return the size of the various partitions of your VPS. - -If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. - -### Day 2 operations with your validator - -You can check your current balances with: - -``` -nymd query bank balances ${ADDRESS} -``` - -For example, on the Sanbox testnet this would return: - -```yaml -balances: -- amount: "919376" -denom: unymt -pagination: -next_key: null -total: "0" -``` - -You can, of course, stake back the available balance to your validator with the following command. - -> Remember to save some tokens for gas costs! - -``` -# Mainnet -nyxd tx staking delegate VALOPERADDRESS AMOUNTunym - --from="KEYRING_NAME" - --keyring-backend=os - --chain-id=nyx - --gas="auto" - --gas-adjustment=1.15 - --fees 5000unyx -``` -``` -# Sandbox Testnet -nyxd tx staking delegate VALOPERADDRESS AMOUNTunymt - --from="KEYRING_NAME" - --keyring-backend=os - --chain-id=sandbox - --gas="auto" - --gas-adjustment=1.15 - --fees 5000unyxt -``` - -## Validator port reference -All validator-specific port configuration can be found in `$HOME/.nymd/config/config.toml`. If you do edit any port configs, remember to restart your validator. - -| Default port | Use | -|--------------|--------------------------------------| -| 1317 | REST API server endpoint | -| 26656 | Listen for incoming peer connections | -| 26660 | Listen for Prometheus connections | diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md new file mode 100644 index 0000000000..6b7af1913a --- /dev/null +++ b/documentation/docs/src/nodes/validator.md @@ -0,0 +1,12 @@ +# Validator + +> The validator setup and maintenance guide has moved to the [Operator Guides book](TO_DO). + +Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. + +The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` token used to incentivise node operators is one of two native tokens of the chain, and the chain is where the [Mixnet](../nyx/mixnet-contract.md) and [Vesting](../nyx/vesting-contract.md) smart contracts are deployed. + +## Further Reading +* TODO section of whitepaper +* TODO blogpost +* TODO gaiad link(s) \ No newline at end of file From 84741f20203ab2db6cd17ed3c47532f5a10ccd4e Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 19:51:03 +0200 Subject: [PATCH 028/146] cont. --- documentation/docs/src/nodes/gateway.md | 13 ++++++++++++- documentation/docs/src/nodes/mixnode.md | 7 +++++-- documentation/docs/src/nodes/validator.md | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md index f4ee68e242..ad2da8e8ca 100644 --- a/documentation/docs/src/nodes/gateway.md +++ b/documentation/docs/src/nodes/gateway.md @@ -1 +1,12 @@ -# Gateway +# Gateways + +> The gateway setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). + +Gateways are key to both the usability of the mixnet, and the operation of the mixnet's tokenomics. They serve two main functions: +* (When the mixnet is no longer in 'free' mode) to act literally as gateways; checking for zkNym credentials (previously referred to as [Coconut Credentials](../bandwidth-credentials.md)) that prove a user has 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 (because of their quality of service) the higher the rewards. 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 egress point for mixnet traffic, and always receive mixnet traffic from it (see the [mixnet traffic flow page](../architecture/traffic-flow.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 +* TODO whitepaper section +* TODO loopix paper section +* TODO blogpost \ No newline at end of file diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index 159251ad3e..14e42a54b9 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -1,4 +1,4 @@ -# Mix Node +# Mix Nodes > The mix node setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). @@ -8,10 +8,13 @@ Mix nodes perform one task: receiving packets, decrypting their outer 'layer', a The aim of this mixing is to protect against timing-based deanonymisation attempts by a global adversary able to monitor the entire network with a 'God's Eye View'. +Mix nodes are rewarded according to their quality of service, and their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) affected by this (as well as their delegation-based reputation - see [further reading](#further-reading) for more on this). + ## (Coming soon) Mixing: a Step-by-Step Breakdown ## Further reading TODO -*
+* TODO SECTION OF WHITEPAPER +* TODO LOOPIX PAPER SECTION * * diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index 6b7af1913a..0ef86744a8 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -1,4 +1,4 @@ -# Validator +# Validators > The validator setup and maintenance guide has moved to the [Operator Guides book](TO_DO). From a8ddaddaf4beee8fa05d5b359e80b13b78ce920e Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 21:15:58 +0200 Subject: [PATCH 029/146] skeleton of NR page --- documentation/docs/src/nodes/network-requester.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/documentation/docs/src/nodes/network-requester.md b/documentation/docs/src/nodes/network-requester.md index 797dfd7795..747efbe62a 100644 --- a/documentation/docs/src/nodes/network-requester.md +++ b/documentation/docs/src/nodes/network-requester.md @@ -1 +1,9 @@ -# Network Requester +# Network Requesters + +> The network requester setup and maintenance guide has moved to the [Operator Guides book](TO_DO). + +Network requesters are the first instance of the catch-all term 'service', or 'service providers'. In essence, think of services as being the part of the mixnet infrastructure that let you _do_ something, such as access emails, messaging service backends, or blockchains via the mixnet. + +Network requesters, in essence, act as a form of proxy (somewhat analagous to a Tor exit node) + + From f26f159bb0e22d1b0c45ea96c62898a43efadac8 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 4 Aug 2023 13:18:12 +0200 Subject: [PATCH 030/146] filled/docs/validators.md --- .../docs/src/images/nym-token-flow.png | Bin 0 -> 174671 bytes documentation/docs/src/nodes/gateway.md | 4 +-- documentation/docs/src/nodes/mixnode.md | 2 +- .../docs/src/nodes/network-requester.md | 2 +- documentation/docs/src/nodes/validator.md | 23 ++++++++++++++---- .../operators/src/nodes/maintenance.md | 3 ++- .../operators/src/preliminary-steps.md | 2 +- 7 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 documentation/docs/src/images/nym-token-flow.png diff --git a/documentation/docs/src/images/nym-token-flow.png b/documentation/docs/src/images/nym-token-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..eb026e23258efb6830022aef1b5af8566c8ecec1 GIT binary patch literal 174671 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

rAqPF^d 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 U$$MSzw1{bxnWbsjCAZ)H1LKK-6#xJL literal 0 HcmV?d00001 diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md index ad2da8e8ca..ebdae64574 100644 --- a/documentation/docs/src/nodes/gateway.md +++ b/documentation/docs/src/nodes/gateway.md @@ -1,6 +1,6 @@ # Gateways -> The gateway setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). +> The gateway setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/operators/nodes/gateway-setup.html). Gateways are key to both the usability of the mixnet, and the operation of the mixnet's tokenomics. They serve two main functions: * (When the mixnet is no longer in 'free' mode) to act literally as gateways; checking for zkNym credentials (previously referred to as [Coconut Credentials](../bandwidth-credentials.md)) that prove a user has 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 (because of their quality of service) the higher the rewards. 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. @@ -9,4 +9,4 @@ Gateways are key to both the usability of the mixnet, and the operation of the m ## Further Reading * TODO whitepaper section * TODO loopix paper section -* TODO blogpost \ No newline at end of file +* TODO blogpost diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index 14e42a54b9..2d1911a990 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -1,6 +1,6 @@ # Mix Nodes -> The mix node setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). +> The mix node setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/developers/nodes/mix-node-setup.html). Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing' or performing the 'poisson mix'. diff --git a/documentation/docs/src/nodes/network-requester.md b/documentation/docs/src/nodes/network-requester.md index 747efbe62a..83778e18a4 100644 --- a/documentation/docs/src/nodes/network-requester.md +++ b/documentation/docs/src/nodes/network-requester.md @@ -1,6 +1,6 @@ # Network Requesters -> The network requester setup and maintenance guide has moved to the [Operator Guides book](TO_DO). +> The network requester setup and maintenance guide has moved to the [Operator Guides book](https://nymtech.net/developers/nodes/network-requester-setup.html). Network requesters are the first instance of the catch-all term 'service', or 'service providers'. In essence, think of services as being the part of the mixnet infrastructure that let you _do_ something, such as access emails, messaging service backends, or blockchains via the mixnet. diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index 0ef86744a8..ac3d896bca 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -1,12 +1,25 @@ +- [x] TODO section of whitepaper +- [x] TODO blogpost +- [ ] TODO gaias link(s) + # Validators -> The validator setup and maintenance guide has moved to the [Operator Guides book](TO_DO). +> The validator setup and maintenance guide has moved to the [Operator Guides book](https://nymtech.net/operators/nodes/validator-setup.html). -Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. +> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. + + +Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx blockchain records the ledger of NYM transactions and executes the smart contracts for distributing NYM rewards. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` token used to incentivise node operators is one of two native tokens of the chain, and the chain is where the [Mixnet](../nyx/mixnet-contract.md) and [Vesting](../nyx/vesting-contract.md) smart contracts are deployed. +![Nym Token Flow](../images/nym-token-flow.png) + ## Further Reading -* TODO section of whitepaper -* TODO blogpost -* TODO gaiad link(s) \ No newline at end of file + +* Detailed info on Nyx Validators and token flow can be found in [Nym Reward Sharing for Mixnets document](https://nymtech.net/nym-cryptoecon-paper.pdf) in section 2.3 and 2.4. +* For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). +* More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). +* [Here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. +* Our [quarterly update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. + diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 7ffe1d6d58..05723461f2 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -7,7 +7,8 @@ TODO - copy that dir over to the new vps - re-run init - remember that init doesn't overwrite existing keys - to generate a config with the new listening address etc - change the node info via the wallet - - Since otherwise their keys will point to the old IP address in the smart contract, and their node will (a) not be able to be connected to, and (b) fail uptime checks + - Since otherwise their keys will point to the old IP address in the smart contract, and their node will (a) not be able to be connected to, and (b) fail uptime checks +- [ ] Test the scp -3 command in the moving a node section ---> ## Useful commands diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index d36ca76da4..ec13e7ea59 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,6 +1,6 @@ # Preliminary Steps -> The Nym `mix node`, `gateway` and `network-requester` binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym `mix node`, `gateway` and `network-requester` binaries were built in the [building nym](./binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ## Preliminary steps From 0b29e28e3f094ca571a6d9594d244f1af7ea18a6 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 4 Aug 2023 13:19:29 +0200 Subject: [PATCH 031/146] remove reduntant nym/docs/ --- docs/src/binaries/building-nym.html | 242 ---------------------- docs/src/binaries/building-nym.md | 1 - docs/src/binaries/init-and-config.html | 242 ---------------------- docs/src/binaries/init-and-config.md | 1 - docs/src/binaries/pre-built-binaries.html | 242 ---------------------- docs/src/binaries/pre-built-binaries.md | 1 - 6 files changed, 729 deletions(-) delete mode 100644 docs/src/binaries/building-nym.html delete mode 100644 docs/src/binaries/building-nym.md delete mode 100644 docs/src/binaries/init-and-config.html delete mode 100644 docs/src/binaries/init-and-config.md delete mode 100644 docs/src/binaries/pre-built-binaries.html delete mode 100644 docs/src/binaries/pre-built-binaries.md diff --git a/docs/src/binaries/building-nym.html b/docs/src/binaries/building-nym.html deleted file mode 100644 index 90e9c937cc..0000000000 --- a/docs/src/binaries/building-nym.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - Building from Source - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Building from Source

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/src/binaries/building-nym.md b/docs/src/binaries/building-nym.md deleted file mode 100644 index f195be32f9..0000000000 --- a/docs/src/binaries/building-nym.md +++ /dev/null @@ -1 +0,0 @@ -# Building from Source diff --git a/docs/src/binaries/init-and-config.html b/docs/src/binaries/init-and-config.html deleted file mode 100644 index 2a9390a316..0000000000 --- a/docs/src/binaries/init-and-config.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - Binary Initialisation and Configuration - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Binary Initialisation and Configuration

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/src/binaries/init-and-config.md b/docs/src/binaries/init-and-config.md deleted file mode 100644 index 9087d5cf00..0000000000 --- a/docs/src/binaries/init-and-config.md +++ /dev/null @@ -1 +0,0 @@ -# Binary Initialisation and Configuration diff --git a/docs/src/binaries/pre-built-binaries.html b/docs/src/binaries/pre-built-binaries.html deleted file mode 100644 index a02f51d2bd..0000000000 --- a/docs/src/binaries/pre-built-binaries.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - Pre-built Binaries - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Pre-built Binaries

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/src/binaries/pre-built-binaries.md b/docs/src/binaries/pre-built-binaries.md deleted file mode 100644 index 8c52595ce9..0000000000 --- a/docs/src/binaries/pre-built-binaries.md +++ /dev/null @@ -1 +0,0 @@ -# Pre-built Binaries From a67092ad172058437eb4bda328f2d78eda4a62c8 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:08:18 +0200 Subject: [PATCH 032/146] correct go installation - guide finished --- .../operators/src/nodes/validator-setup.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 9e233808d7..4726b4c11c 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -41,19 +41,6 @@ rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.6.linux-amd64.tar.gz export PATH=$PATH:/usr/local/go/bin source $HOME/.profile ``` - Verify `Go` is installed with: From d44b88842e579268e8ebebe3821539db52a9d338 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:19:34 +0200 Subject: [PATCH 033/146] scp automation tested - doc finished --- documentation/operators/src/nodes/maintenance.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 05723461f2..a9a90ccaa6 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -1,15 +1,5 @@ # Maintenance - ## Useful commands > Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. From 913095ee6061a4576ff2c0e1fde961752d3105d6 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:36:19 +0200 Subject: [PATCH 034/146] old typos edits --- documentation/docs/src/sdk/rust.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/docs/src/sdk/rust.md b/documentation/docs/src/sdk/rust.md index 1408d85faa..e82cfc7b99 100644 --- a/documentation/docs/src/sdk/rust.md +++ b/documentation/docs/src/sdk/rust.md @@ -66,12 +66,12 @@ You can read more about how SURBs function under the hood [here](../architecture ### 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 peforming 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`). +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 ususally do (under the hood): +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}} @@ -102,4 +102,4 @@ The following code shows how you can use the SDK to create and use a [credential {{#include ../../../../sdk/rust/nym-sdk/examples/bandwidth.rs}} ``` -You can read more about Coconut credentials (also referred to as `zk-Nym`) [here](../cococnut.md). +You can read more about Coconut credentials (also referred to as `zk-Nym`) [here](../coconut.md). From f8b9bb7e78d0167acda62426242db111624e0baf Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:38:10 +0200 Subject: [PATCH 035/146] correcting links, typos - doc finished --- documentation/operators/src/nodes/troubleshooting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index d8fb566b58..50f9406ff3 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -183,7 +183,7 @@ Your mix node **must speak both IPv4 and IPv6** in order to cooperate with other #### Incorrect bonding information -Check that you have provided the correct information when bonding your mix node in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, un-bond and then re-bond your node! +Check that you have provided the correct information when bonding your mix node in the web wallet interface. When in doubt, un-bond and then re-bond your node! > All delegated stake will be lost when un-bonding! However the mix node must be operational in the first place for the delegation to have any effect. @@ -222,7 +222,7 @@ bob@nym:~$ hostname -I ### Running on a local machine behind NAT with no fixed IP address -Your ISP has to be IPv6 ready if you want to run a mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. +Your ISP has to be IPv6 ready if you want to run a mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it. Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! From bff806e5f568743c1d80602f0ab7559124d2f087 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:40:28 +0200 Subject: [PATCH 036/146] correction of typos --- documentation/docs/src/tools/nym-cli.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/documentation/docs/src/tools/nym-cli.md b/documentation/docs/src/tools/nym-cli.md index f516190002..b6ed36bfa7 100644 --- a/documentation/docs/src/tools/nym-cli.md +++ b/documentation/docs/src/tools/nym-cli.md @@ -4,14 +4,14 @@ This is a CLI tool for interacting with: * the Nyx blockchain (account management, querying the chain state, etc) -* the smart contracts deployed on Nyx (bonding and unbonding mixnodes, collecting rewards, etc) +* the smart contracts deployed on Nyx (bonding and un-bonding mixnodes, collecting rewards, etc) It provides a convenient wrapper around the `nymd` client, and has similar functionality to the `nyxd` binary for querying the chain or executing smart contract methods. ## Building The `nym-cli` binary can be built by running `cargo build --release` in the `nym/tools/nym-cli` directory. -### Useage +### Usage You can see all available commands with: ``` @@ -225,9 +225,9 @@ Bonding a mix node is a process that takes a few steps due to the need to sign a ./nym-cli --mnemonic mixnet operators gateway bond --amount 100000000 --mix-port 1789 --version "1.1.13" --host "85.163.111.99" --identity-key "B6pWscxYb8sPAdKTci8zPy5AgMzn5Zx8KpWwQNCyUSU7" --location "nym-town" --sphinx-key "o6MmKHzRewpNzVwaV37ZX9G3BfK4AmfYvsQfyoyAFRk" --signature "2TujBZfer8r5QM639Yb8coD9xH6f5eXzjAT5dD7wMom9fH8D1u36d7UpPdVaaZrWsCynmYpobwMWqiMKr5kM6CprD" ``` -### Unbond a node +### Un-bond a node -Unbond a mix node or gateway. +Un-bond a mix node or gateway. ``` ./nym-cli mixnet operators gateway unbound --mnemonic ``` @@ -270,7 +270,7 @@ Delegate to a mix node. ./nym-cli mixnet delegators delegate --amount –mix-id --mnemonic ``` -### Undelegate Stake +### Un-delegate Stake Remove stake from a mix node. ``` @@ -321,10 +321,10 @@ Query for vesting schedule in the [vesting smart contract](../nyx/vesting-contra ## Staking on someone's behalf (for custodians) -There is a limitation the the staking address can only perform the following actions (and are visible via the Nym Wallet: +There is a limitation the staking address can only perform the following actions (and are visible via the Nym Wallet: -- Bond on the gaƒteway's or mix node's behalf. -- Delegate or Undelegate (to a mix node in order to begin receiving rewards) +- Bond on the gateway's or mix node's behalf. +- Delegate or Un-delegate (to a mix node in order to begin receiving rewards) - Claiming the rewards on the account ```admonish note title="" @@ -333,7 +333,7 @@ The staking address has no ability to withdraw any coins from the parent's accou The staking address must maintain the same level of security as the parent mnemonic; while the parent mnemonic's delegations and bonding events will be visible to the parent owner, the staking address will be the only account capable of undoing the bonding and delegating from the mix nodes or gateway. -Query for staking on behlaf of someone else +Query for staking on behalf of someone else ``` ./nym-cli --mnemonic mixnet delegators delegate --mix-id --identity-key --amount ``` From 860ec74b596706674552905a165758c4188af1c3 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:47:29 +0200 Subject: [PATCH 037/146] operators-guides final review of links and typos --- documentation/operators/src/faq.md | 2 +- documentation/operators/src/introduction.md | 2 +- documentation/operators/src/nodes/mix-node-setup.md | 8 +------- .../operators/src/nodes/network-requester-setup.md | 4 ++-- documentation/operators/src/nodes/troubleshooting.md | 2 +- documentation/operators/src/nodes/validator-setup.md | 4 ++-- 6 files changed, 8 insertions(+), 14 deletions(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index a42af22825..9bb2c6dec9 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -14,7 +14,7 @@ For more detailed calculation, read our blog post [Nym Token Economics update](h ### Which VPS providers would you recommend? -Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. +Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We receive some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index dc160825d6..4050fe141c 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -2,7 +2,7 @@ This is Nym's Operators guide, containing information and setup guides for the various pieces of Nym mixnet infrastructure (mix node, gateway and network requester) and Nyx blockchain validators. -If you are new to Nym and want to learn about the mixnet, explore quickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/). +If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/). If you want to dive deeper into Nym's architecture, clients, nodes, and SDK examples visit the [technical docs](https://nymtech.net/docs/). diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 2dccc52258..1c70383a61 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -173,12 +173,6 @@ If everything worked, you'll see your node running on the either the [Sandbox te Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list. - - Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. ## Node Description (optional) @@ -298,7 +292,7 @@ Once you've started your mix node and it connects to the validator, your node wi - [Mainnet](https://explorer.nymtech.net/overview) - [Sandbox testnet](https://sandbox-explorer.nymtech.net/) -Enter your **identity key** to find your node. There are numerous statistics about your node on that page that are useful for checking your uptime history, packets mixed, and any delegations your node may have. +Enter your **identity key** to find your node. There are numerous statistics about your node on that page that are useful for checking your up-time history, packets mixed, and any delegations your node may have. There are also 2 community explorers which have been created by [Nodes Guru](https://nodes.guru): diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 049b139de6..15cacd3266 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -22,7 +22,7 @@ Any request to a URL which is not on this list will be blocked. On startup, if this file is not present, the requester will grab the default whitelist from [Nym's default list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) automatically. -This default whitelist is useful for knowing that the majority of network requesters are able to support certain apps 'out of the box'. +This default whitelist is useful for knowing that the majority of Network requesters are able to support certain apps 'out of the box'. **Operators of a network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. @@ -77,7 +77,7 @@ matrix.org ``` ## Network Requester Directory -You can find a list of Network Requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. +You can find a list of Network requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. > We are currently working on a smart-contract based solution more in line with how Mix nodes and Gateways announce themselves to the network. diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index 50f9406ff3..20b98970df 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -236,7 +236,7 @@ Here is a sample of the `init` command example to create the mix node config. ./nym-mixnode init --id --host 0.0.0.0 --announce-host 85.160.12.13 ``` -- `--host 0.0.0.0` should work every time even if your local machine IPv4 address changes. For example on Monday your router gives your machine an address `192.168.0.13` and on Wednesday, the DHCP lease will end and you will be asigned `192.168.0.14`. Using `0.0.0.0` should avoid this without having to set any static ip in your router`s configuration. +- `--host 0.0.0.0` should work every time even if your local machine IPv4 address changes. For example on Monday your router gives your machine an address `192.168.0.13` and on Wednesday, the DHCP lease will end and you will be assigned `192.168.0.14`. Using `0.0.0.0` should avoid this without having to set any static IP in your router`s configuration. - you can get your current IPv4 address by either using `curl ipinfo.io` if you're on MacOS or Linux or visiting [whatsmyip site](https://www.whatsmyip.org/). Simply copy it and use it as `--anounce-host` address. diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 4726b4c11c..ca35c0b2b9 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -455,7 +455,7 @@ If you want to set up a reverse proxying on the validator server to improve secu Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](./maintenance.md#Setting-the-ulimit) to change the `ulimit` value for validators. ## Using your validator -### Unjailing your validator +### Un-jailing your validator If your validator gets jailed, you can fix it with the following command: ``` @@ -499,7 +499,7 @@ You can check your current balances with: nymd query bank balances ${ADDRESS} ``` -For example, on the Sanbox testnet this would return: +For example, on the Sandbox testnet this would return: ```yaml balances: From 2dd3e031bd51aead056911e765cebfa4fab17519 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:13:11 +0200 Subject: [PATCH 038/146] socks5: new commands from #3699 --- documentation/docs/src/clients/socks5-client.md | 12 +++++++++++- documentation/operators/src/nodes/maintenance.md | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/documentation/docs/src/clients/socks5-client.md b/documentation/docs/src/clients/socks5-client.md index e7163347cb..e8bce0e948 100644 --- a/documentation/docs/src/clients/socks5-client.md +++ b/documentation/docs/src/clients/socks5-client.md @@ -82,7 +82,7 @@ You can check that your binaries are properly compiled with: You can check the necessary parameters for the available commands by running: ``` -./nym-client --help +./nym-client --help ``` ### Initialising a new client instance @@ -169,3 +169,13 @@ 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. diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index a9a90ccaa6..911a6825af 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -661,7 +661,7 @@ All ``-specific port configuration can be found in `$HOME/.nym// Date: Mon, 7 Aug 2023 15:52:48 +0200 Subject: [PATCH 039/146] added links --- documentation/docs/src/nodes/gateway.md | 9 ++++----- documentation/docs/src/nodes/mixnode.md | 15 ++++++--------- documentation/docs/src/nodes/validator.md | 6 +----- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md index ebdae64574..814c550d4c 100644 --- a/documentation/docs/src/nodes/gateway.md +++ b/documentation/docs/src/nodes/gateway.md @@ -3,10 +3,9 @@ > The gateway setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/operators/nodes/gateway-setup.html). Gateways are key to both the usability of the mixnet, and the operation of the mixnet's tokenomics. They serve two main functions: -* (When the mixnet is no longer in 'free' mode) to act literally as gateways; checking for zkNym credentials (previously referred to as [Coconut Credentials](../bandwidth-credentials.md)) that prove a user has 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 (because of their quality of service) the higher the rewards. 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 egress point for mixnet traffic, and always receive mixnet traffic from it (see the [mixnet traffic flow page](../architecture/traffic-flow.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. +* 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. 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 egress point for mixnet traffic, and always receive mixnet traffic from it (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. ## Further Reading -* TODO whitepaper section -* TODO loopix paper section -* TODO blogpost +* [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 4.2 +* [Nym Blog: Gateways to Privacy](https://blog.nymtech.net/gateways-to-privacy-51196005bf5) diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index 2d1911a990..e849b141b1 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -2,19 +2,16 @@ > The mix node setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/developers/nodes/mix-node-setup.html). -Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing' or performing the 'poisson mix'. +Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing'. -Mix nodes perform one task: receiving packets, decrypting their outer 'layer', and holding them for a variable amount of time before passing them to their next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were recieved. - -The aim of this mixing is to protect against timing-based deanonymisation attempts by a global adversary able to monitor the entire network with a 'God's Eye View'. +Mix nodes, after receiving a packet, decrypt its outer 'layer', and hold them for a variable amount of time before passing them to their next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were received. Mix nodes are rewarded according to their quality of service, and their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) affected by this (as well as their delegation-based reputation - see [further reading](#further-reading) for more on this). ## (Coming soon) Mixing: a Step-by-Step Breakdown ## Further reading -TODO -* TODO SECTION OF WHITEPAPER -* TODO LOOPIX PAPER SECTION -* -* +* [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 4 +* [Nym Blog: Mix node deepdive](https://blog.nymtech.net/nym-mixnodes-deep-dive-d2b91917f097) +* [Mixnet Traffic Flow overview](../architecture/traffic-flow.md) +* [Reward Sharing for Mixnets](https://nymtech.net/nym-cryptoecon-paper.pdf) \ No newline at end of file diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index ac3d896bca..ceb0abdf8a 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -1,6 +1,4 @@ - [x] TODO section of whitepaper -- [x] TODO blogpost -- [ ] TODO gaias link(s) # Validators @@ -8,7 +6,6 @@ > We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. - Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx blockchain records the ledger of NYM transactions and executes the smart contracts for distributing NYM rewards. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` token used to incentivise node operators is one of two native tokens of the chain, and the chain is where the [Mixnet](../nyx/mixnet-contract.md) and [Vesting](../nyx/vesting-contract.md) smart contracts are deployed. @@ -16,10 +13,9 @@ The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` ![Nym Token Flow](../images/nym-token-flow.png) ## Further Reading - * Detailed info on Nyx Validators and token flow can be found in [Nym Reward Sharing for Mixnets document](https://nymtech.net/nym-cryptoecon-paper.pdf) in section 2.3 and 2.4. * For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). * More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). * [Here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. * Our [quarterly update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. - +* [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 3.1 \ No newline at end of file From f954ce5c97fc4a113b6ad9790c258d85ad502ac9 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 7 Aug 2023 16:06:39 +0200 Subject: [PATCH 040/146] more links, fleshed out intro --- documentation/docs/src/introduction.md | 23 +++++++++++++-------- documentation/docs/src/wallet/cli-wallet.md | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/documentation/docs/src/introduction.md b/documentation/docs/src/introduction.md index 9e245497f4..9964ec5b75 100644 --- a/documentation/docs/src/introduction.md +++ b/documentation/docs/src/introduction.md @@ -2,24 +2,29 @@ This is Nym's technical documentation, containing information and setup guides about the various pieces of Nym software such as different mixnet infrastructure nodes, application clients, and existing applications like the desktop wallet and mixnet explorer. -If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). +If you are looking for information and setup guides for the various pieces of Nym mixnet infrastructure (mix nodes, gateways and network requesters) and Nyx blockchain validators see the **new [Operators Guides](https://nymtech.net/operators)** book. + +If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/). ## Popular pages **Network Architecture:** * [Network Overview](./architecture/network-overview.md) * [Mixnet Traffic Flow](./architecture/traffic-flow.md) -**Node setup and usage guides:** -* [Mix nodes](./nodes/mix-node-setup.md) -* [Gateways](./nodes/gateway-setup.md) -* [Network requesters](./nodes/network-requester-setup.md) -* [Validators](./nodes/validator-setup.md) +**SDK examples:** +* [Typescript SDK](./sdk/typescript.md) +* [Rust SDK](./sdk/rust.md) + +**Nyx** +* [Interacting with the Nyx chain](./nyx/interacting-with-chain.md) +* [Ledger Live setup](./nyx/ledger-live.md) +* [RPC Node](./nyx/rpc-node.md) **Client setup and usage guides:** * [Websocket client](./clients/websocket-client.md) * [Socks5 client](./clients/socks5-client.md) * [Webassembly client](./clients/webassembly-client.md) -**SDK guides:** -* [Typescript SDK](./sdk/typescript.md) -* [Rust SDK](./sdk/rust.md) +**Wallets** +* [Desktop](./wallet/desktop-wallet.md) +* [CLI](./wallet/cli-wallet.md) \ No newline at end of file diff --git a/documentation/docs/src/wallet/cli-wallet.md b/documentation/docs/src/wallet/cli-wallet.md index e4d2468068..3f713b1937 100644 --- a/documentation/docs/src/wallet/cli-wallet.md +++ b/documentation/docs/src/wallet/cli-wallet.md @@ -5,4 +5,4 @@ If you have already read our validator setup and maintenance [documentation](../ ### Using `nyxd` binary as a CLI wallet You can use the `nyxd` as a minimal CLI wallet if you want to set up an account (or multiple accounts). Just compile the binary as per the documentation, **stopping after** the [building your validator](../nodes/validator-setup.md#building-your-validator) step is complete. You can then run `nyxd keys --help` to see how you can set up and store different keypairs with which to interact with the Nyx blockchain. - +For more on interacting with the chain, see the [Interacting with Nyx Chain and Smart Contracts](../nyx/interacting-with-chain.md) page. From 2565716816c21829b4cd9255a4097fbace18a192 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 7 Aug 2023 16:38:02 +0200 Subject: [PATCH 041/146] typo fix --- documentation/operators/src/nodes/network-requester-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 15cacd3266..e840bb357a 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -83,7 +83,7 @@ You can find a list of Network requesters running the default whitelist in the [ ## Viewing command help -To begin, move to `/taget/release` directory from which you run the node commands: +To begin, move to `/target/release` directory from which you run the node commands: ``` cd target/release From 2eeb8bb590cef6fd125370051fc88000e64e1940 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 7 Aug 2023 16:38:13 +0200 Subject: [PATCH 042/146] NR page --- .../docs/src/nodes/network-requester.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/documentation/docs/src/nodes/network-requester.md b/documentation/docs/src/nodes/network-requester.md index 83778e18a4..ac083a3143 100644 --- a/documentation/docs/src/nodes/network-requester.md +++ b/documentation/docs/src/nodes/network-requester.md @@ -1,9 +1,22 @@ -# Network Requesters +# Network Requester > The network requester setup and maintenance guide has moved to the [Operator Guides book](https://nymtech.net/developers/nodes/network-requester-setup.html). Network requesters are the first instance of the catch-all term 'service', or 'service providers'. In essence, think of services as being the part of the mixnet infrastructure that let you _do_ something, such as access emails, messaging service backends, or blockchains via the mixnet. -Network requesters, in essence, act as a form of proxy (somewhat analagous to a Tor exit node) +## Domain filtering +Network requesters, in essence, act as a form of proxy (somewhat analagous to a Tor exit node). If you have access to a server, you can run the network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. +By default the network requester is **not** an open proxy (although it can be used as one). It uses a whitelist for outbound requests. +Any request to a URL which is not on this local list (modified by the node operator) or [Nym's default list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) will be blocked. + +This default whitelist is useful for knowing that the majority of Network requesters are able to support certain apps 'out of the box', and the local whitelist allows operators to include their own whitelisted domains. + +> Substantial changes are on the horizon concerning how Network Requesters manage incoming requests - if you are an operator and have experience running software such as Tor exit nodes or p2p nodes get in touch via our [Matrix server](https://matrix.to/#/#dev:nymtech.chat). + +## (Coming soon) Consuming credentials for anonymous service payment + +## Further reading +* [Nym Blog: Network Requester deepdive](https://blog.nymtech.net/tech-deepdive-network-requesters-e5359a6cc31c) +* [Nym Blog: Choose Your Character](https://blog.nymtech.net/choose-your-character-an-overview-of-nym-network-actors-19e6a9808540) \ No newline at end of file From 7e27413a12232c49afeee6483f4c78204daaf1ae Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 8 Aug 2023 13:59:53 +0200 Subject: [PATCH 043/146] added custom 404 page for all books --- documentation/dev-portal/book.toml | 2 +- documentation/dev-portal/src/not-found.md | 11 +++++++++++ documentation/docs/src/not-found.md | 4 ++-- documentation/operators/book.toml | 4 ++-- documentation/operators/src/not-found.md | 11 +++++++++++ 5 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 documentation/dev-portal/src/not-found.md create mode 100644 documentation/operators/src/not-found.md diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index 3b81f82751..216492690a 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -84,7 +84,7 @@ git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" site-url = "/developers/" # cname = "nymtech.net" -# input-404 = "not-found.md" # todo make custom 404 page +input-404 = "not-found.md" [output.html.fold] enable = true # whether or not to enable section folding diff --git a/documentation/dev-portal/src/not-found.md b/documentation/dev-portal/src/not-found.md new file mode 100644 index 0000000000..704da5ec19 --- /dev/null +++ b/documentation/dev-portal/src/not-found.md @@ -0,0 +1,11 @@ +# Page Not Found + +You seem to have followed a link to a page that no longer exists. Our documentation is changing and growing over time, so this page has most likely been moved somewhere else. + +For node setup guides, see the [Operator Guides book](https://nymtech.net/operators). + +For information on network architecture traffic flow, clients, the SDKs, or interacting with the Nyx blockchain see the [Technical Documentation](https://nymtech.net/docs). + +If you are looking for information on developer tutorials, app guides, and demo and community apps, check the sitemap on the left hand side of the screen. + +If you still can't find what you're looking for get in touch with us via [Matrix](https://matrix.to/#/#nym-community:nymtech.chat). \ No newline at end of file diff --git a/documentation/docs/src/not-found.md b/documentation/docs/src/not-found.md index 3d203a9bb8..af87d6dd59 100644 --- a/documentation/docs/src/not-found.md +++ b/documentation/docs/src/not-found.md @@ -2,10 +2,10 @@ You seem to have followed a link to a page that no longer exists. Our documentation is changing and growing over time, so this page has most likely been moved somewhere else. -For node setup guides, see the [Operators Guides book](https://nymtech.net/operators). +For node setup guides, see the [Operator Guides book](https://nymtech.net/operators). For developer tutorials, app guides, and demo and community apps, see the [Developer Portal](https://nymtech.net/developers). If you are looking for information on network architecture traffic flow, clients, the SDKs, or interacting with the Nyx blockchain, check the sitemap on the left hand side of the screen. -If you still can't find what you're looking for get in touch with us via [Matrix](TODO). \ No newline at end of file +If you still can't find what you're looking for get in touch with us via [Matrix](https://matrix.to/#/#nym-community:nymtech.chat). \ No newline at end of file diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 28efe62c57..2ce49e37bb 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -92,9 +92,9 @@ additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" -# site-url = "/docs/" +site-url = "/operators/" # cname = "nymtech.net" -# input-404 = "not-found.md" # todo make custom 404 page +input-404 = "not-found.md" [output.html.fold] enable = true # whether or not to enable section folding diff --git a/documentation/operators/src/not-found.md b/documentation/operators/src/not-found.md new file mode 100644 index 0000000000..aafb70cba5 --- /dev/null +++ b/documentation/operators/src/not-found.md @@ -0,0 +1,11 @@ +# Page Not Found + +You seem to have followed a link to a page that no longer exists. Our documentation is changing and growing over time, so this page has most likely been moved somewhere else. + +For node setup guides, see the [Operator Guides book](https://nymtech.net/operators). + +For developer tutorials, app guides, and demo and community apps, see the [Developer Portal](https://nymtech.net/developers). + +If you are looking for information on setting up and maintaining infrastructure nodes, check the sitemap on the left hand side of the screen. + +If you still can't find what you're looking for get in touch with us via [Matrix](https://matrix.to/#/#nym-community:nymtech.chat). \ No newline at end of file From 85c22525cf99b5f99cd7d345f322a923b389f062 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 8 Aug 2023 14:10:44 +0200 Subject: [PATCH 044/146] * tweaked mixnode doc * removed token diagram from nyx validator doc --- documentation/docs/src/nodes/mixnode.md | 2 +- documentation/docs/src/nodes/validator.md | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index e849b141b1..44dc924d86 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -4,7 +4,7 @@ Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing'. -Mix nodes, after receiving a packet, decrypt its outer 'layer', and hold them for a variable amount of time before passing them to their next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were received. +Mix nodes, after receiving a packet, decrypt its outer 'layer' and hold it for a variable amount of time before passing it to its next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were received. Mix nodes are rewarded according to their quality of service, and their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) affected by this (as well as their delegation-based reputation - see [further reading](#further-reading) for more on this). diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index ceb0abdf8a..eba1666351 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -1,17 +1,11 @@ -- [x] TODO section of whitepaper - # Validators > The validator setup and maintenance guide has moved to the [Operator Guides book](https://nymtech.net/operators/nodes/validator-setup.html). -> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. - -Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx blockchain records the ledger of NYM transactions and executes the smart contracts for distributing NYM rewards. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. +Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx blockchain records the ledger of `NYM` transactions and executes the smart contracts for distributing `NYM` rewards. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` token used to incentivise node operators is one of two native tokens of the chain, and the chain is where the [Mixnet](../nyx/mixnet-contract.md) and [Vesting](../nyx/vesting-contract.md) smart contracts are deployed. -![Nym Token Flow](../images/nym-token-flow.png) - ## Further Reading * Detailed info on Nyx Validators and token flow can be found in [Nym Reward Sharing for Mixnets document](https://nymtech.net/nym-cryptoecon-paper.pdf) in section 2.3 and 2.4. * For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). From 88d2592a4eee329b1c05e280b1b220127ebb5879 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 8 Aug 2023 14:16:48 +0200 Subject: [PATCH 045/146] added notes to ws and socks client subsections re: rust sdk --- documentation/docs/src/clients/overview.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/documentation/docs/src/clients/overview.md b/documentation/docs/src/clients/overview.md index 4bfc125b5c..c8d2db1503 100644 --- a/documentation/docs/src/clients/overview.md +++ b/documentation/docs/src/clients/overview.md @@ -23,19 +23,23 @@ At present, there are three Nym clients: 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 runs as a persistent process on a desktop or server machine. You can connect to it with **any language that supports websockets**. +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.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 [sdk](../sdk/typescript.md). +_The webassembly client is most easily used via the [Typescript SDK](../sdk/typescript.md)_. ### The SOCKS5 client -This client (`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). +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). -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. +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.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. From 23a669c4de89c87deffc1d4f100a1dec1d1ce61f Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 8 Aug 2023 14:19:29 +0200 Subject: [PATCH 046/146] updated vars in all books for next release version --- documentation/dev-portal/book.toml | 2 +- documentation/docs/book.toml | 2 +- documentation/operators/book.toml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index 216492690a..73fdb0d4fa 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -50,7 +50,7 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` # code prerequisites versions minimum_rust_version = "1.66" # TODO remove this in place of develop in next release -platform_release_version = "v1.1.21" +platform_release_version = "v1.1.27" [preprocessor.last-changed] command = "mdbook-last-changed" diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index f507798295..d4097f4456 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -49,7 +49,7 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` [preprocessor.variables.variables] minimum_rust_version = "1.66" # vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.26" +platform_release_version = "v1.1.27" wallet_release_version = "v1.2.7" [preprocessor.last-changed] diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 2ce49e37bb..c39af18a65 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -49,8 +49,8 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` [preprocessor.variables.variables] minimum_rust_version = "1.66" # vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.22" -wallet_release_version = "v1.2.5" +platform_release_version = "v1.1.27" +wallet_release_version = "v1.2.7" [preprocessor.last-changed] From 4f05169361819353ed8a887ce902f1bf9baaa205 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 11:29:34 +0200 Subject: [PATCH 047/146] added coc and license --- documentation/operators/src/SUMMARY.md | 5 +++++ documentation/operators/src/coc.md | 17 +++++++++++++++++ documentation/operators/src/licensing.md | 5 +++++ 3 files changed, 27 insertions(+) create mode 100644 documentation/operators/src/coc.md create mode 100644 documentation/operators/src/licensing.md diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index a3f55376c8..82345c6f49 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -20,3 +20,8 @@ - [Troubleshooting](./nodes/troubleshooting.md) - [FAQ](./faq.md) +--- +# Misc. +- [Code of Conduct](coc.md) +- [Licensing](licensing.md) +--- diff --git a/documentation/operators/src/coc.md b/documentation/operators/src/coc.md new file mode 100644 index 0000000000..f8771a73bf --- /dev/null +++ b/documentation/operators/src/coc.md @@ -0,0 +1,17 @@ +# Code of Conduct + +We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. + +Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all. + +Please be kind and courteous. There’s no need to be mean or rude. + +Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. + +Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. + +We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behaviour that excludes people in socially marginalized groups. + +Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the Rust moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back. + +Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome. diff --git a/documentation/operators/src/licensing.md b/documentation/operators/src/licensing.md new file mode 100644 index 0000000000..2e8612d4d4 --- /dev/null +++ b/documentation/operators/src/licensing.md @@ -0,0 +1,5 @@ +# Licensing + +Nym is Free Software released under the Apache License V2. + +All of the contributions of the Nym core developers are © Nym Technologies SA. If you are interested in talking to us about other licenses, please get in touch. From 432f6a006f4416660c57cf766e5df7bc6a7d4e06 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 11:29:57 +0200 Subject: [PATCH 048/146] removed glossary file: needs rework --- documentation/dev-portal/src/SUMMARY.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/dev-portal/src/SUMMARY.md b/documentation/dev-portal/src/SUMMARY.md index be35e9c30a..d31adbade3 100644 --- a/documentation/dev-portal/src/SUMMARY.md +++ b/documentation/dev-portal/src/SUMMARY.md @@ -44,10 +44,9 @@ - [Community Guides](community-resources/community-guides.md) - [Change Service Grantee Information](info-request.md) - [Rewards FAQ](community-resources/rewards-faq.md) ---- +--- # Misc. -- [Glossary](glossary.md) - [Code of Conduct](coc.md) - [Licensing](licensing.md) --- From e9d10caaf862e412fc0c4c8589c2203ea367cda0 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 11:30:12 +0200 Subject: [PATCH 049/146] final tweaks --- documentation/docs/src/nodes/gateway.md | 4 ++-- documentation/docs/src/nodes/mixnode.md | 2 +- documentation/docs/src/nodes/validator.md | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md index 814c550d4c..3634c36652 100644 --- a/documentation/docs/src/nodes/gateway.md +++ b/documentation/docs/src/nodes/gateway.md @@ -3,8 +3,8 @@ > The gateway setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/operators/nodes/gateway-setup.html). 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. 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 egress point for mixnet traffic, and always receive mixnet traffic from it (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. +* 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. ## Further Reading * [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 4.2 diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index 44dc924d86..b093c6f0b4 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -6,7 +6,7 @@ Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix Mix nodes, after receiving a packet, decrypt its outer 'layer' and hold it for a variable amount of time before passing it to its next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were received. -Mix nodes are rewarded according to their quality of service, and their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) affected by this (as well as their delegation-based reputation - see [further reading](#further-reading) for more on this). +Mix nodes are rewarded according to their quality of service, and the probability of their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) is also affected by this (as well as their delegation-based reputation - see the [Mix node deepdive](#further-reading) below for more on this). ## (Coming soon) Mixing: a Step-by-Step Breakdown diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index eba1666351..855cf21700 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -8,8 +8,5 @@ The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` ## Further Reading * Detailed info on Nyx Validators and token flow can be found in [Nym Reward Sharing for Mixnets document](https://nymtech.net/nym-cryptoecon-paper.pdf) in section 2.3 and 2.4. -* For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). -* More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). -* [Here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. * Our [quarterly update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. * [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 3.1 \ No newline at end of file From 62c03b3136f7dbcffc929cdd80e6e474f37583f0 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 11:47:11 +0200 Subject: [PATCH 050/146] removed doubled header --- documentation/operators/src/preliminary-steps.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index ec13e7ea59..2f7cb2008b 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,8 +1,6 @@ # Preliminary Steps -> The Nym `mix node`, `gateway` and `network-requester` binaries were built in the [building nym](./binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. - -## Preliminary steps +> The Nym `mixnode`, `gateway` and `network-requester` binaries were built in the [building nym](./binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. There are a couple of steps that need completing before starting to set up your mix node, gateway or a network requester: From 3dd3692e8d61ce1e0f7a23e1d46557d40eea1f51 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 12:51:34 +0200 Subject: [PATCH 051/146] updated links in operator binaries compilation list --- documentation/operators/src/binaries/building-nym.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/binaries/building-nym.md b/documentation/operators/src/binaries/building-nym.md index 8610fcb63a..20c157ad21 100644 --- a/documentation/operators/src/binaries/building-nym.md +++ b/documentation/operators/src/binaries/building-nym.md @@ -55,12 +55,12 @@ NETWORK=sandbox cargo build --release # build your binaries with **sandbox** con Quite a bit of stuff gets built. The key working parts are: -* [mix node](../nodes/mix-node-setup.md): `nym-mixnode` -* [gateway node](../nodes/gateway-setup.md): `nym-gateway` +* [mix node](../nodes/mix-node.md): `nym-mixnode` +* [gateway node](../nodes/gateway.md): `nym-gateway` * [websocket client](https://nymtech.net/docs/clients/websocket-client.html): `nym-client` * [socks5 client](https://nymtech.net/docs/clients/socks5-client.html): `nym-socks5-client` * [webassembly client](https://nymtech.net/docs/clients/webassembly-client.html): `webassembly-client` -* [network requester](../nodes/network-requester-setup.md): `nym-network-requester` +* [network requester](../nodes/network-requester.md): `nym-network-requester` * [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli` The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages. From fc7e4be1750144dc85d0b15041bc0dc50724d962 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 13:25:37 +0200 Subject: [PATCH 052/146] fixed links --- documentation/operators/src/binaries/building-nym.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/binaries/building-nym.md b/documentation/operators/src/binaries/building-nym.md index 20c157ad21..8610fcb63a 100644 --- a/documentation/operators/src/binaries/building-nym.md +++ b/documentation/operators/src/binaries/building-nym.md @@ -55,12 +55,12 @@ NETWORK=sandbox cargo build --release # build your binaries with **sandbox** con Quite a bit of stuff gets built. The key working parts are: -* [mix node](../nodes/mix-node.md): `nym-mixnode` -* [gateway node](../nodes/gateway.md): `nym-gateway` +* [mix node](../nodes/mix-node-setup.md): `nym-mixnode` +* [gateway node](../nodes/gateway-setup.md): `nym-gateway` * [websocket client](https://nymtech.net/docs/clients/websocket-client.html): `nym-client` * [socks5 client](https://nymtech.net/docs/clients/socks5-client.html): `nym-socks5-client` * [webassembly client](https://nymtech.net/docs/clients/webassembly-client.html): `webassembly-client` -* [network requester](../nodes/network-requester.md): `nym-network-requester` +* [network requester](../nodes/network-requester-setup.md): `nym-network-requester` * [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli` The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages. From 2db3297d1e297680d9871c0c55c7345e63ad9eef Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 14:11:06 +0200 Subject: [PATCH 053/146] updated grantee info update link --- documentation/dev-portal/src/info-request.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/documentation/dev-portal/src/info-request.md b/documentation/dev-portal/src/info-request.md index 551da83bf3..e3edbdc3de 100644 --- a/documentation/dev-portal/src/info-request.md +++ b/documentation/dev-portal/src/info-request.md @@ -1,6 +1,6 @@ # Change Service Grantee Information -The Nym Service Grantees User Information Update Form allows Service Grantees to update their information with the Nym team. The form allows grantees to update their current: +If you wish to update any of the following information: - `Email Address` - `NYM address` - `Network Requester` @@ -9,10 +9,6 @@ The Nym Service Grantees User Information Update Form allows Service Grantees to - `Service` - `Payment Address` -Complete and submit your form so the Nym team to keep track of the service grantees and your current information, ensuring that deliver payments and handle other logistics smooth and accurately. - -> ⚠️ Service Grantee User Information will be updated by our team by 5pm UTC between Mon - Fri. - - +Please reach out either in the `#service-grantees` channel on Discord or on [Matrix](https://matrix.to/#/#nym-community:nymtech.chat). From 6be7c094be53209ea488569b9eb346332dcae809 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 14:24:57 +0200 Subject: [PATCH 054/146] fixed incorrect import path for chat app --- documentation/docs/src/sdk/typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/src/sdk/typescript.md b/documentation/docs/src/sdk/typescript.md index eed1167692..5ce939e858 100644 --- a/documentation/docs/src/sdk/typescript.md +++ b/documentation/docs/src/sdk/typescript.md @@ -47,7 +47,7 @@ There are multiple example projects in [`nym/sdk/typescript/examples/`](https:// The best place to start if you just want to quickly get a basic frontend up and running with which to experiment is `examples/plain-html`: ```typescript -{{#include ../../../../sdk/typescript/examples/plain-html/src/index.ts}} +{{#include ../../../../sdk/typescript/examples/chat-app/plain-html/src/index.ts}} ``` As you can see, all that is required to create an ephemeral keypair and connect to the mixnet is creating a client and then subscribing to the mixnet events coming down the websocket, and adding logic to deal with them. From 05259410b20152e6eb16969977273d33076f09cd Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 14:25:29 +0200 Subject: [PATCH 055/146] changed out of date var 'mix_node_release_version' to 'platform_release_version --- documentation/operators/src/nodes/maintenance.md | 2 +- documentation/operators/src/nodes/mix-node-setup.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 911a6825af..bb7a0f0ea7 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -230,7 +230,7 @@ Here's a systemd service file to do that: ```ini [Unit] -Description=Nym Mixnode ({{mix_node_release_version}}) +Description=Nym Mixnode ({{platform_release_version}}) StartLimitInterval=350 StartLimitBurst=10 diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 1c70383a61..a50c5cac13 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -87,13 +87,13 @@ Mixnode configuration completed. |_| |_|\__, |_| |_| |_| |___/ - (nym-mixnode - version {{mix_node_release_version}}) + (nym-mixnode - version {{platform_release_version}}) -Identity Key: DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"{{mix_node_release_version}}"},"cost_params +Identity Key: DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"{{platform_release_version}}"},"cost_params Sphinx Key: CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z Host: 62.240.134.189 (bind address: 62.240.134.189) -Version: {{mix_node_release_version}} +Version: {{platform_release_version}} Mix Port: 1789, Verloc port: 1790, Http Port: 8000 ``` ~~~ @@ -134,7 +134,7 @@ It will look something like this: |_| |_|\__, |_| |_| |_| |___/ - (nym-mixnode - version {{mix_node_release_version}}) + (nym-mixnode - version {{platform_release_version}}) >>> attempting to sign 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4 From d49ba6e025f72958ad8c8f3e9aa3c3743348d02a Mon Sep 17 00:00:00 2001 From: Gala Date: Wed, 9 Aug 2023 17:56:36 +0200 Subject: [PATCH 056/146] theme change --- documentation/dev-portal/book.toml | 6 ++-- documentation/dev-portal/custom.css | 38 +++++++++++++++++++++++ documentation/dev-portal/last-changed.css | 6 ---- 3 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 documentation/dev-portal/custom.css delete mode 100644 documentation/dev-portal/last-changed.css diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index 3b34e41d86..d9853f839c 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -17,7 +17,7 @@ src = "src" # - run `mdbook build`: this will rebuild the `./theme` directory # - change value of `turn-off` back to `true` [preprocessor.theme] -pagetoc = true +pagetoc = true # some variables related (defined in theme/css/variables.css) # `content-max-width` + `pagetoc-width` = 95% seems the best pagetoc-width = "13%" @@ -37,7 +37,7 @@ nav-chapters-min-width = "auto" chapter-line-height = "2em" section-line-height = "1.5em" -# # if true, never read and touch the files in theme dir +# if true, never read and touch the files in theme dir turn-off = false [preprocessor.admonish] @@ -77,7 +77,7 @@ curly-quotes = true # mathjax-support = false # useful if we want to pull equations in ? copy-fonts = true no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "custom.css"] additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" diff --git a/documentation/dev-portal/custom.css b/documentation/dev-portal/custom.css new file mode 100644 index 0000000000..0174c7796c --- /dev/null +++ b/documentation/dev-portal/custom.css @@ -0,0 +1,38 @@ +:root { + --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", + monospace, monospace; +} +.coal { + --bg: #121726; + --fg: #f2f2f2; + + --sidebar-bg: #121726; + --sidebar-fg: #f2f2f2; + --sidebar-active: #fb6e4e; + + --icons: #f2f2f2; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +.light { + --bg: #f4f6f8; + --fg: #121726; + + --sidebar-bg: #f4f6f8; + --sidebar-fg: #121726; + --sidebar-active: #fb6e4e; + + --icons: #121726; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 5px 0; +} \ No newline at end of file diff --git a/documentation/dev-portal/last-changed.css b/documentation/dev-portal/last-changed.css deleted file mode 100644 index 0c4228de32..0000000000 --- a/documentation/dev-portal/last-changed.css +++ /dev/null @@ -1,6 +0,0 @@ -footer { - font-size: 0.8em; - text-align: center; - border-top: 1px solid black; - padding: 5px 0; - } \ No newline at end of file From ae79dc4ec68d4bde9a6e14b38493d004f0b2e1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 10 Aug 2023 14:40:15 +0100 Subject: [PATCH 057/146] using stricter version requirements for mdbook and mdbook-variables --- .github/workflows/ci-dev.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-dev.yml b/.github/workflows/ci-dev.yml index 82068fce76..16a4dda0b4 100644 --- a/.github/workflows/ci-dev.yml +++ b/.github/workflows/ci-dev.yml @@ -22,10 +22,13 @@ jobs: with: toolchain: stable - name: Install mdbook - run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook) + # to make sure we don't run into toml dependency issue, make sure to pull fixed mdbook that depends on old 0.5 + # and OLD mdbook-variables that uses the same dependency + # (mdbook-variables 0.2.3 updated to 0.7 which was used by mdbook incorrectly and extremely briefly) + run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) - name: Install mdbook plugins run: | - cargo install --vers "^0.2.0" mdbook-variables && cargo install \ + cargo install --vers "=0.2.2" mdbook-variables && cargo install \ --vers "^1.8.0" mdbook-admonish && cargo install --vers \ "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ && cargo install --vers "^0.7.7" mdbook-linkcheck From 0f777204b89412d7280b2f0a5b884b7c28cd3d54 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:31:56 +0200 Subject: [PATCH 058/146] picked theme changes:dev-portal -> operators; theme finished --- documentation/operators/book.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index c39af18a65..52d1379fa8 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -18,7 +18,7 @@ src = "src" # - run `mdbook build`: this will rebuild the `./theme` directory # - change value of `turn-off` back to `true` [preprocessor.theme] -pagetoc = true +pagetoc = true # some variables related (defined in theme/css/variables.css) pagetoc-width = "13%" content-max-width = "70%" # 82 @@ -87,7 +87,7 @@ curly-quotes = true # mathjax-support = false # useful if we want to pull equations in copy-fonts = true no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./last-changed.css"] +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./custom.css"] additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" From c5c6d3cc2784be46b651197786d9a42f2ff1f755 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:32:13 +0200 Subject: [PATCH 059/146] picked theme changes:dev-portal -> operators; theme finished --- documentation/operators/custom.css | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 documentation/operators/custom.css diff --git a/documentation/operators/custom.css b/documentation/operators/custom.css new file mode 100644 index 0000000000..170e91dd26 --- /dev/null +++ b/documentation/operators/custom.css @@ -0,0 +1,38 @@ +:root { + --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", + monospace, monospace; +} +.coal { + --bg: #121726; + --fg: #f2f2f2; + + --sidebar-bg: #121726; + --sidebar-fg: #f2f2f2; + --sidebar-active: #fb6e4e; + + --icons: #f2f2f2; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +.light { + --bg: #f4f6f8; + --fg: #121726; + + --sidebar-bg: #f4f6f8; + --sidebar-fg: #121726; + --sidebar-active: #fb6e4e; + + --icons: #121726; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 5px 0; +} From 9966d0fa5fc292903a5997e31764b05729c4fa96 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:39:04 +0200 Subject: [PATCH 060/146] applied theme changes:dev-portal -> docs --- documentation/docs/book.toml | 2 +- documentation/docs/custom.css | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 documentation/docs/custom.css diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index cda7e3db07..ce666bddf2 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -85,7 +85,7 @@ curly-quotes = true # mathjax-support = false # useful if we want to pull equations in copy-fonts = true no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "./custom.css"] additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" diff --git a/documentation/docs/custom.css b/documentation/docs/custom.css new file mode 100644 index 0000000000..170e91dd26 --- /dev/null +++ b/documentation/docs/custom.css @@ -0,0 +1,38 @@ +:root { + --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", + monospace, monospace; +} +.coal { + --bg: #121726; + --fg: #f2f2f2; + + --sidebar-bg: #121726; + --sidebar-fg: #f2f2f2; + --sidebar-active: #fb6e4e; + + --icons: #f2f2f2; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +.light { + --bg: #f4f6f8; + --fg: #121726; + + --sidebar-bg: #f4f6f8; + --sidebar-fg: #121726; + --sidebar-active: #fb6e4e; + + --icons: #121726; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 5px 0; +} From b1b276e8ba3363f4448aa4b169c4b67a94461388 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 10:16:37 +0200 Subject: [PATCH 061/146] pull fix from ci-dev.yml to ci-docs.yml --- .github/workflows/ci-docs.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index 2523013204..5d7874833b 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -27,14 +27,13 @@ jobs: command: build args: --workspace --release --all - name: Install mdbook - run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook) + run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) - name: Install mdbook plugins run: | - cargo install --vers "^0.2.0" mdbook-variables && cargo install \ + cargo install --vers "=0.2.2" mdbook-variables && cargo install \ --vers "^1.8.0" mdbook-admonish && cargo install --vers \ - "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \ - mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \ - cargo install --vers "^0.5.0" mdbook-cmdrun + "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ + && cargo install --vers "^0.7.7" mdbook-linkcheck - name: Clean website run: cd documentation/docs && mdbook clean - name: Build website From 3714ee76ff430d791f5a7e85636bd70af4adc8be Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 10:53:34 +0200 Subject: [PATCH 062/146] added workflow_dispatch to ci for dev-portal and docs --- .github/workflows/cd-dev.yml | 1 + .github/workflows/cd-docs.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/cd-dev.yml b/.github/workflows/cd-dev.yml index 0ca463345f..664f3cd79e 100644 --- a/.github/workflows/cd-dev.yml +++ b/.github/workflows/cd-dev.yml @@ -1,6 +1,7 @@ name: CD dev-portal on: + workflow_dispatch: push: branches: master paths: diff --git a/.github/workflows/cd-docs.yml b/.github/workflows/cd-docs.yml index 782a2c196d..b3f15ab265 100644 --- a/.github/workflows/cd-docs.yml +++ b/.github/workflows/cd-docs.yml @@ -1,6 +1,7 @@ name: CD docs on: + workflow_dispatch: push: branches: master paths: From f9108ea4009e9227935dc7780aa9d145e9801008 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 12:29:20 +0200 Subject: [PATCH 063/146] reintroduced linkchecker + fixed broken links --- documentation/docs/book.toml | 4 ++-- documentation/docs/src/architecture/network-overview.md | 2 +- documentation/docs/src/binaries/building-nym.md | 2 +- documentation/docs/src/clients/socks5-client.md | 6 +++--- documentation/docs/src/nyx/ledger-live.md | 2 +- documentation/docs/src/nyx/rpc-node.md | 2 +- documentation/docs/src/wallet/cli-wallet.md | 4 ++-- documentation/operators/book.toml | 4 ++-- documentation/operators/src/nodes/maintenance.md | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index ce666bddf2..6d22440ee3 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -119,5 +119,5 @@ expand = true # partial words will match longer terms heading-split-level = 3 # link results to heading levels copy-js = true # include Javascript code for search -# [output.linkcheck] -# warning-policy = "warn" +[output.linkcheck] +warning-policy = "warn" diff --git a/documentation/docs/src/architecture/network-overview.md b/documentation/docs/src/architecture/network-overview.md index fab4655e09..3a69f78be7 100644 --- a/documentation/docs/src/architecture/network-overview.md +++ b/documentation/docs/src/architecture/network-overview.md @@ -26,7 +26,7 @@ The mixnet - the different pieces of software that your traffic will pass throug * **Gateways** act as message storage for clients which may go offline and come back online again, and defend against denial of service attacks. The default gateway implementation included in the Nym platform code holds packets for later retrieval. For many applications (such as simple chat), this is usable out of the box, as it provides a place that potentially offline clients can retrieve packets from. The access token allows clients to pull messages from the gateway node. -* **Services** are applications that communicate with nym clients, listening and sending traffic to the mixnet. This is an umbrella term for a variety of different pieces of code, such as the [network requester](../nodes/network-requester-setup.md) binary. +* **Services** are applications that communicate with nym clients, listening and sending traffic to the mixnet. This is an umbrella term for a variety of different pieces of code, such as the [network requester](../nodes/network-requester.md) binary. * **Nyx Blockchain Validators** secure the network with proof-of-stake Sybil defenses, determine which nodes are included within the network, and work together to create Coconut threshold credentials which provide anonymous access to data and resources. They also produce blocks and secure the Nyx Blockchain. Initially, this chain was used only to house the CosmWasm smart contracts keeping track of Nym's network topology, token vesting contracts, and the `NYM` token itself. In recent months, we've decided to expand the role of Nyx and instead expand its role by making it an open smart contract platform for anyone to upload CosmWasm smart contracts to. Validators also provide privacy-enhanced credentials based on the testimony of a set of decentralized, blockchain-based issuing authorities. Nym validators use the [Coconut](https://arxiv.org/abs/1802.07344) [signature scheme](https://en.wikipedia.org/wiki/Digital_signature) to issue credentials. This allows privacy apps to generate anonymous resource claims through decentralised authorities, then use them with Service Providers. diff --git a/documentation/docs/src/binaries/building-nym.md b/documentation/docs/src/binaries/building-nym.md index a02e378ebb..a79af72c3d 100644 --- a/documentation/docs/src/binaries/building-nym.md +++ b/documentation/docs/src/binaries/building-nym.md @@ -8,7 +8,7 @@ Nym has two main codebases: - the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code _except_ for the validators. - the [Nym validators](https://github.com/nymtech/nyxd), written in Go. -> This page details how to build the main Nym platform code. **If you want to build and run a validator, [go here](../nodes/validator-setup.md) instead.** +> This page details how to build the main Nym platform code. **If you want to build and run a validator, [go here](../nodes/validator.md) instead.** ## Prerequisites - Debian/Ubuntu: `pkg-config`, `build-essential`, `libssl-dev`, `curl`, `jq`, `git` diff --git a/documentation/docs/src/clients/socks5-client.md b/documentation/docs/src/clients/socks5-client.md index e8bce0e948..e3a5759685 100644 --- a/documentation/docs/src/clients/socks5-client.md +++ b/documentation/docs/src/clients/socks5-client.md @@ -60,7 +60,7 @@ There are 2 pieces of software that work together to send SOCKS traffic through 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-setup.md). Packets are shuffled and mixed as they transit the mixnet. +* 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! @@ -100,9 +100,9 @@ Before you can use the client, you need to initalise a new instance of it, which 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 `--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-setup.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/). +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-setup.md#network-requester-whitelist): Keybase, Telegram, Electrum, Blockstream Green, and Helios. +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. diff --git a/documentation/docs/src/nyx/ledger-live.md b/documentation/docs/src/nyx/ledger-live.md index f7559b6fd2..031834fa24 100644 --- a/documentation/docs/src/nyx/ledger-live.md +++ b/documentation/docs/src/nyx/ledger-live.md @@ -4,7 +4,7 @@ Use the following instructions to interact with the Nyx blockchain - either with ## Prerequisites * Download and install [Ledger Live](https://www.ledger.com/ledger-live). -* Compile the `nyxd` binary as per the instructions [here](../nodes/validator-setup.md#building-the-nym-validator). Stop after you can successfully run `nyxd` and get the helptext in your console output. +* Compile the `nyxd` binary as per the instructions [here](https://nymtech.net/operators/nodes/validator-setup.md#building-the-nym-validator). Stop after you can successfully run `nyxd` and get the helptext in your console output. ## Prepare your Ledger App * Plug in your Ledger device diff --git a/documentation/docs/src/nyx/rpc-node.md b/documentation/docs/src/nyx/rpc-node.md index af76f1f927..dc48d68409 100644 --- a/documentation/docs/src/nyx/rpc-node.md +++ b/documentation/docs/src/nyx/rpc-node.md @@ -4,6 +4,6 @@ RPC Nodes (which might otherwise be referred to as 'Lite Nodes' or just 'Full No You may want to set up an RPC Node for querying the blockchain, or in order to have an endpoint that your app can use to send transactions. -In order to set up an RPC Node, simply follow the instructions to set up a [Validator](../nodes/validator-setup.md), but **exclude the `nyxd tx staking create-validator` command**. +In order to set up an RPC Node, simply follow the instructions to set up a [Validator](https://nymtech.net/operators/nodes/validator-setup.md), but **exclude the `nyxd tx staking create-validator` command**. If you want to fast-sync your node, check out the Polkachu snapshot and their other [resources](https://polkachu.com/seeds/nym). \ No newline at end of file diff --git a/documentation/docs/src/wallet/cli-wallet.md b/documentation/docs/src/wallet/cli-wallet.md index 3f713b1937..36670190a3 100644 --- a/documentation/docs/src/wallet/cli-wallet.md +++ b/documentation/docs/src/wallet/cli-wallet.md @@ -1,8 +1,8 @@ # CLI Wallet -If you have already read our validator setup and maintenance [documentation](../nodes/validator-setup.md) you will have seen that we compile and use the `nyxd` binary primarily for our validators. This binary can however be used for many other tasks, such as creating and using keypairs for wallets, or automated setups that require the signing and broadcasting of transactions. +If you have already read our validator setup and maintenance [documentation](../nodes/validator.md) you will have seen that we compile and use the `nyxd` binary primarily for our validators. This binary can however be used for many other tasks, such as creating and using keypairs for wallets, or automated setups that require the signing and broadcasting of transactions. ### Using `nyxd` binary as a CLI wallet -You can use the `nyxd` as a minimal CLI wallet if you want to set up an account (or multiple accounts). Just compile the binary as per the documentation, **stopping after** the [building your validator](../nodes/validator-setup.md#building-your-validator) step is complete. You can then run `nyxd keys --help` to see how you can set up and store different keypairs with which to interact with the Nyx blockchain. +You can use the `nyxd` as a minimal CLI wallet if you want to set up an account (or multiple accounts). Just compile the binary as per the documentation, **stopping after** the [building your validator](../nodes/validator.md) step is complete. You can then run `nyxd keys --help` to see how you can set up and store different keypairs with which to interact with the Nyx blockchain. For more on interacting with the chain, see the [Interacting with Nyx Chain and Smart Contracts](../nyx/interacting-with-chain.md) page. diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 52d1379fa8..be7233c069 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -121,5 +121,5 @@ expand = true # partial words will match longer terms heading-split-level = 3 # link results to heading levels copy-js = true # include Javascript code for search -# [output.linkcheck] -# warning-policy = "warn" +[output.linkcheck] +warning-policy = "warn" diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index bb7a0f0ea7..c955975118 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -46,7 +46,7 @@ You can either do this graphically via the Desktop Wallet, or the CLI. ![Node Settings Page](../images/wallet-screenshots/node_settings.png) ### Updating node information via the CLI -If you want to bond your `` via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. +If you want to bond your `` via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.md#upgrade-a-mix-node) docs. ### Upgrading Network Requester to >= v1.1.10 from Date: Fri, 11 Aug 2023 12:29:30 +0200 Subject: [PATCH 064/146] rough staging sh script --- documentation/staging.sh | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 documentation/staging.sh diff --git a/documentation/staging.sh b/documentation/staging.sh new file mode 100755 index 0000000000..07ca2de1d2 --- /dev/null +++ b/documentation/staging.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# commands assume you run script from `nym/documentation/` + +# array of project dirs +declare -a projects=("docs" "dev-portal" "operators") + +## now loop through the above array +for i in "${projects[@]}" +do + # cd to project dir + cd "./$i" && + # little sanity checks + echo $(pwd) && echo $(mdbook --version) && + # clean old book + rm -rf ./book/ + # build book + mdbook build + # check for destination, if ! then mkdir & check again else echo thumbs up + if [ ! -d ../../dist/docs/$i ]; then + echo "dest doesn't exist: creating dir" + mkdir -p ../../dist/docs/$i + fi + if [ -d ../../dist/docs/$i ]; then + echo "cp destination exists, all good" + fi + # clean old dist/$i + rm -rf ../../dist/docs/$i + # move newly rendered book/ to dist + cp -r ./book/ ../../dist/docs/$i + # sanity check + ls -a ../../dist/docs/$i/html + # cd back to ../documentation/ + cd ../ +done \ No newline at end of file From 6a54a6653c724f0507675077f5688b15f37b61ef Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 12:30:41 +0200 Subject: [PATCH 065/146] removed unnecessary linkcheck rendering output from dist/ --- documentation/staging.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/staging.sh b/documentation/staging.sh index 07ca2de1d2..64fec07e47 100755 --- a/documentation/staging.sh +++ b/documentation/staging.sh @@ -27,9 +27,9 @@ do # clean old dist/$i rm -rf ../../dist/docs/$i # move newly rendered book/ to dist - cp -r ./book/ ../../dist/docs/$i + cp -r ./book/html/ ../../dist/docs/$i # sanity check - ls -a ../../dist/docs/$i/html + ls -a ../../dist/docs/$i/ # cd back to ../documentation/ cd ../ done \ No newline at end of file From 6c83b8824722de18d368999048cffd2552efaae7 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 13:08:19 +0200 Subject: [PATCH 066/146] updated readme with soon to be operator doc URL --- documentation/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/README.md b/documentation/README.md index 3330b3e969..e074f7cdfe 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -2,5 +2,6 @@ * `docs` contains technical documentation hosted at [https://nymtech.net/docs](https://nymtech.net/docs) * `dev-portal` contains developer documentation hosted at [https://nymtech.net/developers](https://nymtech.net/developers) +* `operators` contains node setup and maintenance guides hosted at [https://nymtech.net/operators](https://nymtech.net/operators) Each directory contains a readme with more information about running and contributing to the projects. Each is built with [`mdbook`](https://rust-lang.github.io/mdBook/index.html) - use `mdbook serve` to build and serve them (defaults to `localhost:3000`). From 85ab634d9c1f1f54073c97a133c83e645a0a3f41 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 10:10:36 +0200 Subject: [PATCH 067/146] tweak --- documentation/staging.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/documentation/staging.sh b/documentation/staging.sh index 64fec07e47..87fe4d5b58 100755 --- a/documentation/staging.sh +++ b/documentation/staging.sh @@ -13,6 +13,7 @@ do # little sanity checks echo $(pwd) && echo $(mdbook --version) && # clean old book + echo "cleaning old book" rm -rf ./book/ # build book mdbook build @@ -27,9 +28,9 @@ do # clean old dist/$i rm -rf ../../dist/docs/$i # move newly rendered book/ to dist - cp -r ./book/html/ ../../dist/docs/$i + rsync -r ./book/html/ ../../dist/docs/$i # sanity check - ls -a ../../dist/docs/$i/ + ls -laF ../../dist/docs/ # cd back to ../documentation/ cd ../ -done \ No newline at end of file +done From 17e1c5f9702590d671ad0eb7fb24ee993ef63bb2 Mon Sep 17 00:00:00 2001 From: serinko Date: Thu, 13 Jul 2023 16:51:04 +0200 Subject: [PATCH 068/146] initilizing operators guides mdbook --- documentation/operators/book.toml | 123 +++ documentation/operators/src/SUMMARY.md | 10 + documentation/operators/src/faq.md | 7 + .../src/images/wallet-screenshots/bonding.png | Bin 0 -> 56520 bytes .../wallet-screenshots/node_settings.png | Bin 0 -> 55864 bytes .../images/wallet-screenshots/wallet-sign.png | Bin 0 -> 111066 bytes documentation/operators/src/introduction.md | 34 + .../operators/src/nodes/mix-node-setup.md | 700 ++++++++++++++++++ .../operators/src/nodes/setup-guides.md | 18 + 9 files changed, 892 insertions(+) create mode 100644 documentation/operators/book.toml create mode 100644 documentation/operators/src/SUMMARY.md create mode 100644 documentation/operators/src/faq.md create mode 100644 documentation/operators/src/images/wallet-screenshots/bonding.png create mode 100644 documentation/operators/src/images/wallet-screenshots/node_settings.png create mode 100644 documentation/operators/src/images/wallet-screenshots/wallet-sign.png create mode 100644 documentation/operators/src/introduction.md create mode 100644 documentation/operators/src/nodes/mix-node-setup.md create mode 100644 documentation/operators/src/nodes/setup-guides.md diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml new file mode 100644 index 0000000000..c39bb1c6a1 --- /dev/null +++ b/documentation/operators/book.toml @@ -0,0 +1,123 @@ +[book] +title = "Nym Operators Guides" +authors = ["Max Hampshire", "serinko"] +description = "Guides to setup Nym infrastructure" +language = "en" +multilingual = false # for the moment - ideally work on chinese, brazillian, spanish next +src = "src" + +################# +# PREPROCESSORS # +################# + +# Note if changing these fields: +# - make sure you aren't running `mdbook serve` +# - change value of `turn-off = true` to `false`. This is set to `true` usually to avoid a known constant-reload bug with `mdbook serve` and this preprocessor +# - delete `./theme/` dir +# - change the preprocessor values that you want to edit +# - run `mdbook build`: this will rebuild the `./theme` directory +# - change value of `turn-off` back to `true` +[preprocessor.theme] +pagetoc = true +# some variables related (defined in theme/css/variables.css) +pagetoc-width = "13%" +content-max-width = "70%" # 82 +pagetoc-fontsize = "14.5px" +sidebar-width = "300px" +menu-bar-height = "40px" # memu-bar = the bar on the top +page-padding = "20px" +mobile-content-max-width = "98%" + +# layout +content-padding = "0 10px" +content-main-margin-left = "10%" +content-main-margin-right = "10%" +nav-chapters-max-width = "auto" +nav-chapters-min-width = "auto" +chapter-line-height = "2em" +section-line-height = "1.5em" + +# if true, never read and touch the files in theme dir: this is used to stop the looping reload issue referred to in the readme +turn-off = false + +[preprocessor.admonish] +command = "mdbook-admonish" +assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` + +# variables preprocessor: import variables into files +# https://gitlab.com/tglman/mdbook-variables/ +[preprocessor.variables.variables] +minimum_rust_version = "1.66" +# vars for links: TODO think on how to streamline updating +platform_release_version = "v1.1.22" +wallet_release_version = "v1.2.5" + +[preprocessor.last-changed] +command = "mdbook-last-changed" +renderer = ["html"] + +# used for grabbing output of binary commands for automation +# https://github.com/FauconFan/mdbook-cmdrun +[preprocessor.cmdrun] + +# more pre-processor plugins to look into from https://github.com/rust-lang/mdBook/wiki/Third-party-plugins & https://lib.rs/keywords/mdbook-preprocessor +# mdbook-i18n + +######### +# BUILD # +######### + +[build] +build-dir = "book" # the directory where the output is placed +create-missing = true # whether or not to create missing pages +use-default-preprocessors = true # use the default preprocessors +extra-watch-dirs = [] # directories to watch for triggering builds + +########## +# OUTPUT # +########## + +[output.html] +theme = "theme" # this is the default if not explicitly set +default-theme = "coal" +preferred-dark-theme = "coal" +curly-quotes = true +# mathjax-support = false # useful if we want to pull equations in +copy-fonts = true +no-section-label = false +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] +additional-js = ["theme/pagetoc.js"] +git-repository-url = "https://github.com/nymtech/nym" +git-repository-icon = "fa-github" +# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" +# site-url = "/docs/" +# cname = "nymtech.net" +# input-404 = "not-found.md" # todo make custom 404 page + +[output.html.fold] +enable = true # whether or not to enable section folding +level = 0 # the depth to start folding + +# controlling rust sample code blocks +[output.html.playground] +editable = false # allows editing the source code +copyable = true # include the copy button for copying code snippets +copy-js = true # includes the JavaScript for the code editor +line-numbers = false # displays line numbers for editable code +runnable = true # displays a run button for rust code + +# options for the built in text search +[output.html.search] +enable = true # enables the search feature +limit-results = 30 # maximum number of search results +teaser-word-count = 30 # number of words used for a search result teaser +use-boolean-and = true # multiple search terms must all match +boost-title = 2 # ranking boost factor for matches in headers +boost-hierarchy = 1 # ranking boost factor for matches in page names +boost-paragraph = 1 # ranking boost factor for matches in text +expand = true # partial words will match longer terms +heading-split-level = 3 # link results to heading levels +copy-js = true # include Javascript code for search + +# [output.linkcheck] +# warning-policy = "warn" diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md new file mode 100644 index 0000000000..7bb81c8800 --- /dev/null +++ b/documentation/operators/src/SUMMARY.md @@ -0,0 +1,10 @@ +- [Introduction](introduction.md) + +# Operators Guides + +- [Node Setup Guides](./nodes/setup-guides.md) + - [Mix Node](./nodes/mix-node-setup.md) + - [Gateway](./nodes/gateway-setup.md) + - [Network Requester](./nodes/network-requester-setup.md) +- [Troubleshooting](./nodes/troubleshooting.md) +- [FAQ](./faq.md) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md new file mode 100644 index 0000000000..d6b32f3e77 --- /dev/null +++ b/documentation/operators/src/faq.md @@ -0,0 +1,7 @@ + diff --git a/documentation/operators/src/images/wallet-screenshots/bonding.png b/documentation/operators/src/images/wallet-screenshots/bonding.png new file mode 100644 index 0000000000000000000000000000000000000000..b5cef3bb89bdde0e2d865001d14f9b4d1b1b28cc GIT binary patch literal 56520 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 literal 0 HcmV?d00001 diff --git a/documentation/operators/src/images/wallet-screenshots/node_settings.png b/documentation/operators/src/images/wallet-screenshots/node_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..69568ce6a540cbc1d6c4e0fea6d286451ebc189b GIT binary patch literal 55864 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%0Arw=^F)sf3iGu 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 z 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

l-5 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

ly}MeV>=*ZTQ0urb=*FZRXrf1u%f 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 literal 0 HcmV?d00001 diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md new file mode 100644 index 0000000000..f0344db71a --- /dev/null +++ b/documentation/operators/src/introduction.md @@ -0,0 +1,34 @@ +# Introduction + +This is Nym's operators guide, containing information and setup tutorials about the various pieces of Nym mixnet infrastructure nodes, such as mix node, gateway and network requester. + +If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). + +If you want to go deeper into Nym architecture and various software such as different, application clients, existing applications like the desktop wallet, mixnet explorer or SDKs, visit [Nym's technical documentation](https://nymtech.net/docs/). + +If you are looking for information on grants and beta-release Nym apps, check out the [Shipyard](https://shipyard.nymtech.net) site. + + +## Popular pages + + + +**Network Architecture:** +* [Network Overview](https://nymtech.net/docs/architecture/network-overview.html) +* [Mixnet Traffic Flow](https://nymtech.net/docs/architecture/traffic-flow.html) + +**Node setup and usage guides:** +* [Mix nodes](./nodes/mix-node-setup.md) +* [Gateways](./nodes/gateway-setup.md) +* [Network requesters](./nodes/network-requester-setup.md) + + +**Client setup and usage guides:** +* [Websocket client](https://nymtech.net/docs/clients/websocket-client.html) +* [Socks5 client](https://nymtech.net/docs/clients/socks5-client.html) +* [Webassembly client](https://nymtech.net/docs/clients/webassembly-client.html) + +**SDK guides:** +* [Typescript SDK](https://nymtech.net/docs/sdk/typescript.html) +* [Rust SDK](https://nymtech.net/docs/sdk/rust.html) + diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md new file mode 100644 index 0000000000..a24ec587ad --- /dev/null +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -0,0 +1,700 @@ + + +# Mix Nodes + +> The Nym mix node binary was built in the [building nym](https://nymtech.net/docs/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. + +> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. + +## Current version +``` + +``` + +The `nym-mixnode` binary is currently one point version ahead of the rest of the platform binaries due to a patch applied between releases. + +## Preliminary steps + +There are a couple of steps that need completing before starting to set up your mix node: + +- preparing your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) +- requisitioning a VPS (Virtual Private Server) + +### Wallet preparation + +#### Mainnet + +Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). + +If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. + +`NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several [exchanges](https://www.coingecko.com/en/coins/nym#markets). + +> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. + +#### Sandbox testnet + +Make sure to download a wallet and create an account as outlined above. Then head to our [token faucet](https://faucet.nymtech.net/) and get some tokens to use to bond it. + +### VPS Hardware Specs + +You will need to rent a VPS to run your mix node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol). + +For the moment, we haven't put a great amount of effort into optimizing concurrency to increase throughput, so don't bother provisioning a beastly server with multiple cores. This will change when we get a chance to start doing performance optimizations in a more serious way. Sphinx packet decryption is CPU-bound, so once we optimize, more fast cores will be better. + +For now, see the below rough specs: + +- Processors: 2 cores are fine. Get the fastest CPUs you can afford. +- RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. +- Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. + +## Mix node setup + +Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. + +To begin, move to `/taget/release` directory from which you run the node commands: + +``` +cd target/release +``` + +### Viewing command help + +You can check that your binaries are properly compiled with: + +``` +./nym-mixnode --help +``` + +Which should return a list of all available commands. + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +You can also check the various arguments required for individual commands with: + +``` +./nym-mixnode --help +``` + +### Initialising your mix node + +To check available configuration options for initializing your node use: + +``` +./nym-mixnode init --help +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +Initalise your mixnode with the following command, replacing the value of `--id` with the moniker you wish to give your mixnode, and the `--wallet-address` with the Nym address you created earlier. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. + +``` +./nym-mixnode init --id --host $(curl ifconfig.me) --wallet-address +``` + + +~~~admonish example collapsible=true title="Console output" +``` +.nym-mixnode init --id --host $(curl ifconfig.me) --wallet-address + + +Initialising mixnode ... +Saved mixnet identity and sphinx keypairs + 2023-06-04T08:20:32.862Z INFO nym_config > Configuration file will be saved to "/home//.nym/mixnodes//config/config.toml" +Saved configuration file to "/home//.nym/mixnodes//config/config.toml" +Mixnode configuration completed. + + _ __ _ _ _ __ ___ + | '_ \| | | | '_ \ _ \ + | | | | |_| | | | | | | + |_| |_|\__, |_| |_| |_| + |___/ + + (nym-mixnode - version {{mix_node_release_version}}) + + +Identity Key: DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"{{mix_node_release_version}}"},"cost_params +Sphinx Key: CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z +Host: 62.240.134.189 (bind address: 62.240.134.189) +Version: {{mix_node_release_version}} +Mix Port: 1789, Verloc port: 1790, Http Port: 8000 +``` +~~~ + +> The `init` command will refuse to destroy existing mix node keys. + +During the `init` process you will have the option to change the `http_api`, `verloc` and `mixnode` ports from their default settings. If you wish to change these in the future you can edit their values in the `config.toml` file created by the initialization process, which is located at `~/.nym/mixnodes//`. + +### Bonding your mix node + +```admonish caution +From `v1.1.3`, if you unbond your mixnode that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. +``` + +#### Bond via the Desktop wallet (recommended) + +You can bond your mix node via the Desktop wallet. + +* Open your wallet, and head to the `Bond` page, then select the node type `Mixnode` and input your node details. Press `Next`. + +* Enter the `Amount`, `Operating cost` and `Profit margin` and press `Next`. + +* You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it. + +``` +./nym-mixnode sign --id --contract-msg +``` + +It will look something like this: + +~~~admonish example collapsible=true title="Console output" +``` +./nym-mixnode sign --id upgrade_test --contract-msg 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4 + + _ __ _ _ _ __ ___ + | '_ \| | | | '_ \ _ \ + | | | | |_| | | | | | | + |_| |_|\__, |_| |_| |_| + |___/ + + (nym-mixnode - version {{mix_node_release_version}}) + + +>>> attempting to sign 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4 +>>> decoding the message... +>>> message to sign: {"nonce":0,"algorithm":"ed25519","message_type":"mixnode-bonding","content":{"sender":"n1eufxdlgt0puwrwptgjfqne8pj4nhy2u5ft62uq","proxy":null,"funds":[{"denom":"unym","amount":"100000000"}],"data":{"mix_node":{"host":"62.240.134.189","mix_port":1789,"verloc_port":1790,"http_api_port":8000,"sphinx_key":"CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z","identity_key":"DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"1.1.14"},"cost_params":{"profit_margin_percent":"0.1","interval_operating_cost":{"denom":"unym","amount":"40000000"}}}}} +``` +~~~ + +* Copy the resulting signature: + +``` +>>> The base58-encoded signature is: +2GbKcZVKFdpi3sR9xoJWzwPuGdj3bvd7yDtDYVoKfbTWdpjqAeU8KS5bSftD5giVLJC3gZiCg2kmEjNG5jkdjKUt +``` + +* And paste it into the wallet nodal, press `Next` and confirm the transaction. + +![Paste Signature](../images/wallet-screenshots/wallet-sign.png) + +* Your node will now be bonded and ready to mix at the beginning of the next epoch (at most 1 hour). + +> You are asked to `sign` a transaction on bonding so that the mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. + +#### Bond via the CLI (power users) +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. + +### Running your mix node + +Now you've bonded your mix node, run it with: + +``` +./nym-mixnode run --id +``` + +If everything worked, you'll see your node running on the either the [Sandbox testnet network explorer](https://sandbox-explorer.nymtech.net) or the [mainnet network explorer](https://explorer.nymtech.net), depending on which network you're running. + +Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list. + + + +Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. + +### Describe your mix node (optional) + +In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mixnode with the following command: + +``` +./nym-mixnode describe --id +``` + +> Remember to restart your mix node process in order for the new description to be propagated. + +### Upgrading your mix node + +Upgrading your node is a two-step process: +* Updating the binary and `~/.nym/mixnodes//config.toml` on your VPS +* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. + +#### Step 1: Upgrading your binary +Follow these steps to upgrade your mix node binary and update its config file: +* pause your mix node process. +* replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. +* restart your mix node process with the new binary. + +#### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). + +You can either do this graphically via the Desktop Wallet, or the CLI. + +#### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +\ +![Bonding page](../images/wallet-screenshots/bonding.png) + +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +\ +![Node Settings Page](../images/wallet-screenshots/node_settings.png) + +#### Updating node information via the CLI +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. + +### Displaying mix node information + +You can always check the details of your mix node with the `node-details` command: + +``` +./nym-mixnode node-details --id +``` + +## VPS Setup and Automation +### Configure your firewall +The following commands will allow you to set up a firewall using `ufw`. + +``` +# check if you have ufw installed +ufw version + +# if it is not installed, install with +sudo apt install ufw -y + +# enable ufw +sudo ufw enable + +# check the status of the firewall +sudo ufw status +``` + +Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: + +``` +sudo ufw allow 1789,1790,8000,22/tcp + +# check the status of the firewall +sudo ufw status +``` + +For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. + +### Automating your mix node with tmux and systemd + +It's useful to have the mix node automatically start at system boot time. + +#### tmux + +One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated. + +Use the following command to get `tmux`. + +Platform|Install Command +---|--- +Arch Linux|`pacman -S tmux` +Debian or Ubuntu|`apt install tmux` +Fedora|`dnf install tmux` +RHEL or CentOS|`yum install tmux` +macOS (using Homebrew|`brew install tmux` +macOS (using MacPorts)|`port install tmux` +openSUSE|`zypper install tmux` + +In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control). + +**Running tmux** + +No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let the mixnode run on its own on the VPS. + +* Pause your mixnode +* Start tmux with the command +``` +tmux +``` +* The terminal should stay in the same directory, just the layout changed into tmux default layout. +* Start the mixnode again with a command: +``` +./nym-mixnode run --id +``` +* Now, without closing the tmux window, you can close the whole terminal and the mixnode (and any other process running in tmux) will stay active. +* Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session: +``` +tmux attach session +``` +* To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?` + +#### systemd + +Here's a systemd service file to do that: + +```ini +[Unit] +Description=Nym Mixnode ({{mix_node_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User= +LimitNOFILE=65536 +ExecStart=/home///nym-mixnode run --id +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. + +Change the `` in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `` so it is the user you are running as. + +If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` + +Then run: + +``` +systemctl enable nym-mixnode.service +``` + +Start your node: + +``` +service nym-mixnode start +``` + +This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. + +You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. + +Note: if you make any changes to your systemd script after you've enabled it, you will need to run: + +``` +systemctl daemon-reload +``` + +This lets your operating system know it's ok to reload the service configuration. + +#### Setting the ulimit + +Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. + +`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes. + +If you see errors such as: + +``` +Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } +``` + +This means that the operating system is preventing network connections from being made. + +##### Set the ulimit via `systemd` service file + +Query the `ulimit` of your mix node with: + +``` +grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits +``` + +You'll get back the hard and soft limits, which looks something like this: + +``` +Max open files 65536 65536 files +``` + +If your output is **the same as above**, your node will not encounter any `ulimit` related issues. + +However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: + +``` +LimitNOFILE=65536 +``` + +Reload the daemon: + +``` +systemctl daemon-reload +``` + +or execute this as root for system-wide setting of `ulimit`: + +``` +echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf +``` + +Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. + +##### Set the ulimit on `non-systemd` based distributions + +In case you chose tmux option for mixnode automatization, see your `ulimit` list by running: + +``` +ulimit -a + +# watch for the output line -n +-n: file descriptors 1024 +``` + +You can change it either by running a command: + +``` +ulimit -u -n 4096 +``` + +or editing `etc/security/conf` and add the following lines: + +``` +# Example hard limit for max opened files +username hard nofile 4096 + +# Example soft limit for max opened files +username soft nofile 4096 +``` + +Then reboot your server and restart your mixnode. + +## Node Description +Node description is a short text that describes your node. It is displayed in the `./nym-mixnode list` command and in the `./nym-mixnode node-details` command. It also shows up in the node explorer to let people know what your node is about and link to your website. + +To set your node description, create a file called `description.toml` and put it in the same directory as your `config.toml` file (`~/.nym/mixnodes//description.toml`). The file should look like this example: + +```toml +name = "Winston Smith" +description = "I am the Sphinx" +link = "https://nymtech.net" +location = "Giza, Egypt" +``` + +You will need to restart your node for the changes to take effect. + +## Node Families + +Node family involves setting up a group of mix nodes that work together to provide greater privacy and security for network communications. This is achieved by having the nodes in the family share information and routes, creating a decentralized network that makes it difficult for third parties to monitor or track communication traffic. + +### Create a Node Family + +To create a Node family, you will need to install and configure multiple mix nodes, and then use the CLI to link them together into a family. Once your Node family is up and running, you can use it to route your network traffic through a series of nodes, obscuring the original source and destination of the communication. + +You can use either `nym-cli` which can be downloaded from the [release page](https://github.com/nymtech/nym/releases) or compiling `nyxd`. + + +Change directory by `cd ///` and run the following on the family head to obtain the signature for the member: + +``` +./nym-mixnode sign --id --text +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +Using `nym-cli`: + +> `--mnemonic` is the mnemonic of the member wanting to be the head of family. + +``` +/nym-cli cosmwasm execute '{"create_family": {"signature": "","family_head": "","owner_signature":"","label": ""}}' --mnemonic +``` + +Using `nyxd`: + +> `--from` is mnemonic of the member wanting to join the family. + +``` +./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block +``` + +To get the node owner signature, use: + +`./nym-mixnode node-details --id ` + +### Joining a Node Family + +Change directory by `cd ///` and run the following on the family head to obtain the signature for the member: + +``` +./nym-mixnode sign --id --text +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +Using `nym-cli`: + +``` +./nym-cli cosmwasm execute '{"join_family": {"signature": "","family_head": "","owner_signautre": "", "label":""}}' --mnemonic +``` + +Using `nyxd`: + +``` +./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block +``` + + +To get the node owner signature, use: + +`./nym-mixnode node-details --id ` + + +### Leaving a family +If wanting to leave, run the same initial command as above, followed by: + +Using `nym-cli`: + +``` +./nym-cli cosmwasm execute '{"leave_family": {"signature": "","family_head": "","owner_signautre": ""}}' --mnemonic +``` + +Using `nyxd`: + +``` +./nyxd tx wasm execute ${MIXNET-CONTRACT} '{"join_family": {"signature": "","family_head": ""}}' --node ${VALIDATOR-ENDPOINT} --from mix1 --chain-id nyx --gas-prices 0.025unym --gas auto --gas-adjustment 1.3 -y -b block +``` + +## Checking that your node is mixing correctly +### Network explorers +Once you've started your mix node and it connects to the validator, your node will automatically show up in the 'Mix nodes' section of either the Nym Network Explorers: + +- [Mainnet](https://explorer.nymtech.net/overview) +- [Sandbox testnet](https://sandbox-explorer.nymtech.net/) + +Enter your **identity key** to find your node. There are numerous statistics about your node on that page that are useful for checking your uptime history, packets mixed, and any delegations your node may have. + +There are also 2 community explorers which have been created by [Nodes Guru](https://nodes.guru): + +- [Mainnet](https://mixnet.explorers.guru/) +- [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) + +For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) + + + +### Virtual IPs and hosting via Google & AWS +For tru internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a mixnode there, please read the following. + +On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl ifconfig.me)`, but also specify `--announce-host` with the public IP. Please make sure that you pass the correct, routable `--announce-host`. + +For example, on a Google machine, you may see the following output from the `ifconfig` command: + +``` +ens4: flags=4163 mtu 1460 + inet 10.126.5.7 netmask 255.255.255.255 broadcast 0.0.0.0 + ... +``` + +The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. + +`./nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. + +Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. + +The right thing to do in this situation is to init with a command: +``` +./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18 +``` + +This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. + +To find the right IP configuration, contact your VPS provider for support. + +## Metrics / API endpoints +The mix node binary exposes several API endpoints that can be pinged in order to gather information about the node, and the Nym API (previously 'Validator API') exposes numerous mix node related endpoints which provide network-wide information about mix nodes, the network topology (the list of avaliable mix nodes for packet routing), and information regarding uptime monitoring and rewarding history. + +### Mix node API endpoints +Since the mix node binary exposes several API endpoints itself, you can ping these easily via curl: + +| Endpoint | Description | Command | +| -------------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | +| `/description` | Returns the description of the node set with the `describe` command | `curl :8000/description` | +| `/hardware` | Returns the hardware information of the node | `curl :8000/hardware` | +| `/verloc` | Returns the verloc information of the node, updated every 12 hours | `curl :8000/verloc` | + +The code for exposed API endpoints can be found [here](https://github.com/nymtech/nym/tree/release/{{platform_release_version}}/mixnode/src/node/http). + +> You can get more detailed info by appending `?debug` to the URL, like so: +> ``` +> curl http://:8000/stats?debug +> ``` + +### Mix node related Nym API (previously 'Validator API') endpoints +Numerous endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. + +#### Mix node Reward Estimation API endpoint + +The Reward Estimation API endpoint allows mixnode operators to estimate the rewards they could earn for running a Nym mixnode with a specific `MIX_ID`. + +> The `` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). + +The endpoint is a particularly common for mixnode operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mixnode, the quality of the mixnode's performance, and the overall demand for mixnodes in the network. This information can be useful for mixnode operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability. + +Using this API endpoint returns information about the Reward Estimation: + +``` +/status/mixnode//reward-estimation +``` + +Query Response: + +``` + "estimation": { + "total_node_reward": "942035.916721770541325331", + "operator": "161666.263307386408152071", + "delegates": "780369.65341438413317326", + "operating_cost": "54444.444444444444444443" + }, +``` + +> The unit of value is measured in `uNYM`. + +- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node. + +- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network. + +- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network. + +- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. + +- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. + +## Ports +All mix node-specific port configuration can be found in `$HOME/.nym/mixnodes//config/config.toml`. If you do edit any port configs, remember to restart your mix node. + +### Mix node port reference +| Default port | Use | +| ------------ | ------------------------- | +| `1789` | Listen for mixnet traffic | +| `1790` | Listen for VerLoc traffic | +| `8000` | Metrics http API endpoint | +/ + diff --git a/documentation/operators/src/nodes/setup-guides.md b/documentation/operators/src/nodes/setup-guides.md new file mode 100644 index 0000000000..b19cf07deb --- /dev/null +++ b/documentation/operators/src/nodes/setup-guides.md @@ -0,0 +1,18 @@ + +# Node Setup Guides + +To setup any type of Nym's node, start with building [Nym's platform](https://nymtech.net/docs/binaries/building-nym.html) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). + +This section contains setup guides for the following node types: +* [Mix node](./mix-node-setup.md) +* [Gateway](./gateway-setup.md) +* [Network Requester](./network-requester-setup.md) +* [Validator](./validator-setup.md) + + From 232032baf4b47c8959b81a04222d6232c3705b81 Mon Sep 17 00:00:00 2001 From: serinko Date: Thu, 13 Jul 2023 16:59:25 +0200 Subject: [PATCH 069/146] feature/operators-guide: coppied all configs from ../docs/ --- documentation/operators/.gitignore | 27 ++ documentation/operators/mdbook-admonish.css | 352 ++++++++++++++++++ .../operators/src/nodes/gateway-setup.md | 1 + .../src/nodes/network-requester-setup.md | 1 + .../operators/src/nodes/troubleshooting.md | 1 + 5 files changed, 382 insertions(+) create mode 100644 documentation/operators/.gitignore create mode 100644 documentation/operators/mdbook-admonish.css create mode 100644 documentation/operators/src/nodes/gateway-setup.md create mode 100644 documentation/operators/src/nodes/network-requester-setup.md create mode 100644 documentation/operators/src/nodes/troubleshooting.md diff --git a/documentation/operators/.gitignore b/documentation/operators/.gitignore new file mode 100644 index 0000000000..e84b38bdfb --- /dev/null +++ b/documentation/operators/.gitignore @@ -0,0 +1,27 @@ +# mdbook files +book +book/* +theme/index.hbs +theme/pagetoc.css +theme/pagetoc.js +theme/* +theme + +# --------------- +# Compiled assets +# --------------- +.sass-cache +_site + +# ---------- +# Developing +# ---------- +todo.md +.vscode + +# OSX +.DS_Store + +theme/ +theme +theme/* diff --git a/documentation/operators/mdbook-admonish.css b/documentation/operators/mdbook-admonish.css new file mode 100644 index 0000000000..5e360387df --- /dev/null +++ b/documentation/operators/mdbook-admonish.css @@ -0,0 +1,352 @@ +@charset "UTF-8"; +:root { + --md-admonition-icon--note: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--abstract: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--info: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--tip: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--success: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--question: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--warning: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--failure: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--danger: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--bug: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--example: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--quote: + url("data:image/svg+xml;charset=utf-8,"); + --md-details-icon: + url("data:image/svg+xml;charset=utf-8,"); +} + +:is(.admonition) { + display: flow-root; + margin: 1.5625em 0; + padding: 0 1.2rem; + color: var(--fg); + page-break-inside: avoid; + background-color: var(--bg); + border: 0 solid black; + border-inline-start-width: 0.4rem; + border-radius: 0.2rem; + box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); +} +@media print { + :is(.admonition) { + box-shadow: none; + } +} +:is(.admonition) > * { + box-sizing: border-box; +} +:is(.admonition) :is(.admonition) { + margin-top: 1em; + margin-bottom: 1em; +} +:is(.admonition) > .tabbed-set:only-child { + margin-top: 0; +} +html :is(.admonition) > :last-child { + margin-bottom: 1.2rem; +} + +a.admonition-anchor-link { + display: none; + position: absolute; + left: -1.2rem; + padding-right: 1rem; +} +a.admonition-anchor-link:link, a.admonition-anchor-link:visited { + color: var(--fg); +} +a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { + text-decoration: none; +} +a.admonition-anchor-link::before { + content: "§"; +} + +:is(.admonition-title, summary) { + position: relative; + margin-block: 0; + margin-inline: -1.6rem -1.2rem; + padding-block: 0.8rem; + padding-inline: 4.4rem 1.2rem; + font-weight: 700; + background-color: rgba(68, 138, 255, 0.1); + display: flex; +} +:is(.admonition-title, summary) p { + margin: 0; +} +html :is(.admonition-title, summary):last-child { + margin-bottom: 0; +} +:is(.admonition-title, summary)::before { + position: absolute; + top: 0.625em; + inset-inline-start: 1.6rem; + width: 2rem; + height: 2rem; + background-color: #448aff; + mask-image: url('data:image/svg+xml;charset=utf-8,'); + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; +} +:is(.admonition-title, summary):hover a.admonition-anchor-link { + display: initial; +} + +details.admonition > summary.admonition-title::after { + position: absolute; + top: 0.625em; + inset-inline-end: 1.6rem; + height: 2rem; + width: 2rem; + background-color: currentcolor; + mask-image: var(--md-details-icon); + -webkit-mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; + transform: rotate(0deg); + transition: transform 0.25s; +} +details[open].admonition > summary.admonition-title::after { + transform: rotate(90deg); +} + +:is(.admonition):is(.note) { + border-color: #448aff; +} + +:is(.note) > :is(.admonition-title, summary) { + background-color: rgba(68, 138, 255, 0.1); +} +:is(.note) > :is(.admonition-title, summary)::before { + background-color: #448aff; + mask-image: var(--md-admonition-icon--note); + -webkit-mask-image: var(--md-admonition-icon--note); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.abstract, .summary, .tldr) { + border-color: #00b0ff; +} + +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { + background-color: rgba(0, 176, 255, 0.1); +} +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { + background-color: #00b0ff; + mask-image: var(--md-admonition-icon--abstract); + -webkit-mask-image: var(--md-admonition-icon--abstract); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.info, .todo) { + border-color: #00b8d4; +} + +:is(.info, .todo) > :is(.admonition-title, summary) { + background-color: rgba(0, 184, 212, 0.1); +} +:is(.info, .todo) > :is(.admonition-title, summary)::before { + background-color: #00b8d4; + mask-image: var(--md-admonition-icon--info); + -webkit-mask-image: var(--md-admonition-icon--info); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.tip, .hint, .important) { + border-color: #00bfa5; +} + +:is(.tip, .hint, .important) > :is(.admonition-title, summary) { + background-color: rgba(0, 191, 165, 0.1); +} +:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { + background-color: #00bfa5; + mask-image: var(--md-admonition-icon--tip); + -webkit-mask-image: var(--md-admonition-icon--tip); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.success, .check, .done) { + border-color: #00c853; +} + +:is(.success, .check, .done) > :is(.admonition-title, summary) { + background-color: rgba(0, 200, 83, 0.1); +} +:is(.success, .check, .done) > :is(.admonition-title, summary)::before { + background-color: #00c853; + mask-image: var(--md-admonition-icon--success); + -webkit-mask-image: var(--md-admonition-icon--success); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.question, .help, .faq) { + border-color: #64dd17; +} + +:is(.question, .help, .faq) > :is(.admonition-title, summary) { + background-color: rgba(100, 221, 23, 0.1); +} +:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { + background-color: #64dd17; + mask-image: var(--md-admonition-icon--question); + -webkit-mask-image: var(--md-admonition-icon--question); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.warning, .caution, .attention) { + border-color: #ff9100; +} + +:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { + background-color: rgba(255, 145, 0, 0.1); +} +:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { + background-color: #ff9100; + mask-image: var(--md-admonition-icon--warning); + -webkit-mask-image: var(--md-admonition-icon--warning); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.failure, .fail, .missing) { + border-color: #ff5252; +} + +:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { + background-color: rgba(255, 82, 82, 0.1); +} +:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { + background-color: #ff5252; + mask-image: var(--md-admonition-icon--failure); + -webkit-mask-image: var(--md-admonition-icon--failure); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.danger, .error) { + border-color: #ff1744; +} + +:is(.danger, .error) > :is(.admonition-title, summary) { + background-color: rgba(255, 23, 68, 0.1); +} +:is(.danger, .error) > :is(.admonition-title, summary)::before { + background-color: #ff1744; + mask-image: var(--md-admonition-icon--danger); + -webkit-mask-image: var(--md-admonition-icon--danger); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.bug) { + border-color: #f50057; +} + +:is(.bug) > :is(.admonition-title, summary) { + background-color: rgba(245, 0, 87, 0.1); +} +:is(.bug) > :is(.admonition-title, summary)::before { + background-color: #f50057; + mask-image: var(--md-admonition-icon--bug); + -webkit-mask-image: var(--md-admonition-icon--bug); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.example) { + border-color: #7c4dff; +} + +:is(.example) > :is(.admonition-title, summary) { + background-color: rgba(124, 77, 255, 0.1); +} +:is(.example) > :is(.admonition-title, summary)::before { + background-color: #7c4dff; + mask-image: var(--md-admonition-icon--example); + -webkit-mask-image: var(--md-admonition-icon--example); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.quote, .cite) { + border-color: #9e9e9e; +} + +:is(.quote, .cite) > :is(.admonition-title, summary) { + background-color: rgba(158, 158, 158, 0.1); +} +:is(.quote, .cite) > :is(.admonition-title, summary)::before { + background-color: #9e9e9e; + mask-image: var(--md-admonition-icon--quote); + -webkit-mask-image: var(--md-admonition-icon--quote); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +.navy :is(.admonition) { + background-color: var(--sidebar-bg); +} + +.ayu :is(.admonition), .coal :is(.admonition) { + background-color: var(--theme-hover); +} + +.rust :is(.admonition) { + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { + color: var(--sidebar-fg); +} diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md new file mode 100644 index 0000000000..f4ee68e242 --- /dev/null +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -0,0 +1 @@ +# Gateway diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md new file mode 100644 index 0000000000..797dfd7795 --- /dev/null +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -0,0 +1 @@ +# Network Requester diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md new file mode 100644 index 0000000000..4f341277d3 --- /dev/null +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -0,0 +1 @@ +# Troubleshooting From cbee6153bd4a11dad0bc7d8ea6d1e75c9b20e90b Mon Sep 17 00:00:00 2001 From: serinko Date: Fri, 14 Jul 2023 11:20:51 +0200 Subject: [PATCH 070/146] mixnode-seup: minor edits --- documentation/operators/src/introduction.md | 10 ++++++++-- documentation/operators/src/nodes/mix-node-setup.md | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index f0344db71a..d2c148bf64 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -21,7 +21,13 @@ If you are looking for information on grants and beta-release Nym apps, check ou * [Mix nodes](./nodes/mix-node-setup.md) * [Gateways](./nodes/gateway-setup.md) * [Network requesters](./nodes/network-requester-setup.md) - +* [Validators](./nodes/validator-setup.md) + +**Troubleshooting and FAQ** +* [Troubleshooting](./nodes/troubleshooting.md) +* [FAQ](./faq.md) + + diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index a24ec587ad..723984ff39 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -63,7 +63,7 @@ For now, see the below rough specs: ## Mix node setup -Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](https://nymtech.net/docs/binaries/building-nym.html), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. To begin, move to `/taget/release` directory from which you run the node commands: From 55cd1a8b9134f6503fb3863778d47bcbc080aa41 Mon Sep 17 00:00:00 2001 From: serinko Date: Fri, 14 Jul 2023 13:25:12 +0200 Subject: [PATCH 071/146] operators-guide: created generic docs maintenance.md and preliminary-steps.md to avoid redundancy --- documentation/operators/src/SUMMARY.md | 3 + documentation/operators/src/faq.md | 7 + .../wallet-gateway-sign.png | Bin 0 -> 118052 bytes documentation/operators/src/introduction.md | 3 +- .../operators/src/nodes/gateway-setup.md | 254 ++++++++++++- .../operators/src/nodes/maintenance.md | 357 ++++++++++++++++++ .../operators/src/nodes/mix-node-setup.md | 35 +- .../operators/src/preliminary-steps.md | 43 +++ 8 files changed, 667 insertions(+), 35 deletions(-) create mode 100644 documentation/operators/src/images/wallet-screenshots/wallet-gateway-sign.png create mode 100644 documentation/operators/src/nodes/maintenance.md create mode 100644 documentation/operators/src/preliminary-steps.md diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 7bb81c8800..796c7d41ed 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -3,8 +3,11 @@ # Operators Guides - [Node Setup Guides](./nodes/setup-guides.md) +- [Preliminary Steps](./preliminary-steps.md) - [Mix Node](./nodes/mix-node-setup.md) - [Gateway](./nodes/gateway-setup.md) - [Network Requester](./nodes/network-requester-setup.md) + - [Validator](./nodes/validator-setup.md) +- [Maintenance](./nodes/maintenance.md) - [Troubleshooting](./nodes/troubleshooting.md) - [FAQ](./faq.md) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index d6b32f3e77..5e1f5b72ad 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -4,4 +4,11 @@ TODO - [ ] List friendly VPS providers - [ ] Explain difficulty running a node on a self-hosted machine - [ ] Explain uNYM vs NYM. Why, ratio, etc + +Some community questions: +Hi, do you know if it's on the roadmap for network nodes (requesters, socks5 client, etc.) to reconnect to another gateway if the current gateway's connection drops or has issues? I have to reset my requester and socks5 clients to connect them to a new gateway almost every day...😕 having to delete the entire folders associated with them + +you should be able to switch gateway (and overwrite keys) using —force-register + + ---> diff --git a/documentation/operators/src/images/wallet-screenshots/wallet-gateway-sign.png b/documentation/operators/src/images/wallet-screenshots/wallet-gateway-sign.png new file mode 100644 index 0000000000000000000000000000000000000000..63a76aaf4daa49a970ceed5e65c6bcf03891d507 GIT binary patch literal 118052 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

gh{@Ld5VYc~WzO%W;Gv3S$jd$h&x{|!h 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

@E}Q7HmryqarIxWXBsD9W9l?>YP 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

TaZoR+yex1nQT6Ur! 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 Fe*r}Fq&@%u literal 0 HcmV?d00001 diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index d2c148bf64..a97860f292 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -23,7 +23,8 @@ If you are looking for information on grants and beta-release Nym apps, check ou * [Network requesters](./nodes/network-requester-setup.md) * [Validators](./nodes/validator-setup.md) -**Troubleshooting and FAQ** +**Maintenance, troubleshooting and FAQ** +* [Maintenance](./nodes/maintenance.md) * [Troubleshooting](./nodes/troubleshooting.md) * [FAQ](./faq.md) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index f4ee68e242..591cd3d1a9 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -1 +1,253 @@ -# Gateway +# Gateways + +> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. + +> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. + +## Current version +``` + +``` + +## Preliminary steps + +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your gateway. + + +## Gateway setup +Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-gateway` binary, you can set up your gateway with the instructions below. + +To begin, move to `/taget/release` directory from which you run the node commands: + +``` +cd target/release +``` + +### Viewing command help +You can check that your binaries are properly compiled with: + +``` +./nym-gateway --help +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +You can also check the various arguments required for individual commands with: + +``` +./nym-gateway --help +``` + +### Initialising your gateway +To check available configuration options use: + +``` + ./nym-gateway init --help +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +The following command returns a gateway on your current IP with the `id` of `supergateway`: + +``` +./nym-gateway init --id supergateway --host $(curl ifconfig.me) --wallet-address n1eufxdlgt0puwrwptgjfqne8pj4nhy2u5ft62uq +``` + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +The `$(curl ifconfig.me)` command above returns your IP automatically using an external service. Alternatively, you can enter your IP manually if you wish. If you do this, remember to enter your IP **without** any port information. + +### Bonding your gateway +#### Via the Desktop wallet +You can bond your gateway via the Desktop wallet. + +1. Open your wallet, and head to the `Bonding` page, then select the node type `Gateway` and input your node details (Location format is , ). Press `Next` + +2. Enter the `Amount`, `Operating cost` and press `Next`. + +3. You will be asked to run a the `sign` command with your `gateway` - copy and paste the long signature as the value of `--contract-msg` and run it. + +``` +./nym-mixnode sign --id --contract-msg +``` + +It will look something like this: + +~~~admonish example collapsible=true title="Console output" +``` +./nym-gateway sign --id upgrade_test --contract-msg 2Mf8xYytgEeyJke9LA7TjhHoGQWNBEfgHZtTyy2krFJfGHSiqy7FLgTnauSkQepCZTqKN5Yfi34JQCuog9k6FGA2EjsdpNGAWHZiuUGDipyJ6UksNKRxnFKhYW7ri4MRduyZwbR98y5fQMLAwHne1Tjm9cXYCn8McfigNt77WAYwBk5bRRKmC34BJMmWcAxphcLES2v9RdSR68tkHSpy2C8STfdmAQs3tZg8bJS5Qa8pQdqx14TnfQAPLk3QYCynfUJvgcQTrg29aqCasceGRpKdQ3Tbn81MLXAGAs7JLBbiMEAhCezAr2kEN8kET1q54zXtKz6znTPgeTZoSbP8rzf4k2JKHZYWrHYF9JriXepuZTnyxAKAxvGFPBk8Z6KAQi33NRQkwd7MPyttatHna6kG9x7knffV6ebGzgRBf7NV27LurH8x4L1uUXwm1v1UYCA1WSBQ9Pp2JW69k5v5v7G9gBy8RUcZnMbeL26Qqb8WkuGcmuHhaFfoqSfV7PRHPpPT4M8uRqUyR4bjUtSJJM1yh6QSeZk9BEazzoJqPeYeGoiFDZ3LMj2jesbJweQR4caaYuRczK92UGSSqu9zBKmE45a + + + _ __ _ _ _ __ ___ + | '_ \| | | | '_ \ _ \ + | | | | |_| | | | | | | + |_| |_|\__, |_| |_| |_| + |___/ + + (nym-gateway - version {{platform_release_version}}) + + +>>> attempting to sign 2Mf8xYytgEeyJke9LA7TjhHoGQWNBEfgHZtTyy2krFJfGHSiqy7FLgTnauSkQepCZTqKN5Yfi34JQCuog9k6FGA2EjsdpNGAWHZiuUGDipyJ6UksNKRxnFKhYW7ri4MRduyZwbR98y5fQMLAwHne1Tjm9cXYCn8McfigNt77WAYwBk5bRRKmC34BJMmWcAxphcLES2v9RdSR68tkHSpy2C8STfdmAQs3tZg8bJS5Qa8pQdqx14TnfQAPLk3QYCynfUJvgcQTrg29aqCasceGRpKdQ3Tbn81MLXAGAs7JLBbiMEAhCezAr2kEN8kET1q54zXtKz6znTPgeTZoSbP8rzf4k2JKHZYWrHYF9JriXepuZTnyxAKAxvGFPBk8Z6KAQi33NRQkwd7MPyttatHna6kG9x7knffV6ebGzgRBf7NV27LurH8x4L1uUXwm1v1UYCA1WSBQ9Pp2JW69k5v5v7G9gBy8RUcZnMbeL26Qqb8WkuGcmuHhaFfoqSfV7PRHPpPT4M8uRqUyR4bjUtSJJM1yh6QSeZk9BEazzoJqPeYeGoiFDZ3LMj2jesbJweQR4caaYuRczK92UGSSqu9zBKmE45a +>>> decoding the message... +>>> message to sign: {"nonce":0,"algorithm":"ed25519","message_type":"gateway-bonding","content":{"sender":"n1ewmme88q22l8syvgshqma02jv0vqrug9zq9dy8","proxy":null,"funds":[{"denom":"unym","amount":"100000000"}],"data":{"gateway":{"host":"62.240.134.189","mix_port":1789,"clients_port":9000,"location":"62.240.134.189","sphinx_key":"FKbuN7mPdoCG9jA3CkAfXxC5X4rHhqeMVtmfRtJ3cFZd","identity_key":"3RoAhR8gEdfBETMjm2vbMFzKddxXDdE9ygBAnJHWqSzD","version":"1.1.13"}}}} +``` +~~~ + +* Copy the resulting signature: + +``` +>>> The base58-encoded signature is: +2SPDjLjX4b6XEtkgG7yD8Znsb1xycL1edFvRK4JcVnPsM9k6HXEUUeVS6rswRiYxoj1bMgiRKyPDwiksiuyxu8Xi +``` + +* And paste it into the wallet nodal, press `Next` and confirm the transaction. + +![Paste Signature](../images/wallet-screenshots/wallet-gateway-sign.png) + +* Your gateway is now bonded. + +> You are asked to `sign` a transaction on bonding so that the mixnet smart contract is able to map your nym address to your node. This allows us to create a nonce for each account and defend against replay attacks. + +#### Via the CLI (power users) +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.html#bond-a-mix-node) docs. + +### Running your gateway +The `run` command starts the gateway: + +``` +./nym-gateway run --id +``` + +### Upgrading your gateway +Upgrading your node is a two-step process: +* Updating the binary and `config.toml` on your VPS +* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. + +>These instructions are specifically regarding upgrading your gateway binary from one version to another. If you want to change node information such as the listening port, you can do this by clicking the `node settings` tab in the `Bonding` page of the wallet. + +#### Step 1: Upgrading your binary +Follow these steps to upgrade your binary and update its config file: +* pause your gateway process. +* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. +* restart your gateway process with the new binary. + +> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. + +#### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). + +You can either do this graphically via the Desktop Wallet, or the CLI. + +#### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +![Bonding page](../images/wallet-screenshots/bonding.png) + +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +![Node Settings Page](../images/wallet-screenshots/node_settings.png) + +#### Updating node information via the CLI +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. + +## VPS Setup and Automation +### Configure your firewall +Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: + +``` +# check if you have ufw installed +ufw version +# if it is not installed, install with +sudo apt install ufw -y +# enable ufw +sudo ufw enable +# check the status of the firewall +sudo ufw status +``` + +Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: + +``` +sudo ufw allow 1789,22,9000/tcp +# check the status of the firewall +sudo ufw status +``` + +For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. + +### Automating your gateway with systemd +Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: + +```ini +[Unit] +Description=Nym Gateway ({{platform_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User=nym +LimitNOFILE=65536 +ExecStart=/home/nym/nym-gateway run --id supergateway +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. + +Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. + +If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` + + +Then run: + +``` +systemctl enable nym-gateway.service +``` + +Start your node: + +``` +service nym-gateway start +``` + +This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. + +You can also do `service nym-gateway stop` or `service nym-gateway restart`. + +Note: if you make any changes to your systemd script after you've enabled it, you will need to run: + +``` +systemctl daemon-reload +``` + +This lets your operating system know it's ok to reload the service configuration. + +## Gateway related Validator API endpoints +Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. + +## Ports +All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. + +### Gateway port reference +| Default port | Use | +|--------------|---------------------------| +| 1789 | Listen for Mixnet traffic | +| 9000 | Listen for Client traffic | diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md new file mode 100644 index 0000000000..b2fe722d0a --- /dev/null +++ b/documentation/operators/src/nodes/maintenance.md @@ -0,0 +1,357 @@ +# Maintenance + + + + + +### Upgrading your mix node + +Upgrading your node is a two-step process: +* Updating the binary and `~/.nym/mixnodes//config.toml` on your VPS +* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. + +#### Step 1: Upgrading your binary +Follow these steps to upgrade your mix node binary and update its config file: +* pause your mix node process. +* replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. +* restart your mix node process with the new binary. + +#### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). + +You can either do this graphically via the Desktop Wallet, or the CLI. + +#### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +\ +![Bonding page](../images/wallet-screenshots/bonding.png) + +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +\ +![Node Settings Page](../images/wallet-screenshots/node_settings.png) + +#### Updating node information via the CLI +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. + +--- + +## VPS Setup and Automation +### Configure your firewall +The following commands will allow you to set up a firewall using `ufw`. + +``` +# check if you have ufw installed +ufw version + +# if it is not installed, install with +sudo apt install ufw -y + +# enable ufw +sudo ufw enable + +# check the status of the firewall +sudo ufw status +``` + +Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: + +``` +sudo ufw allow 1789,1790,8000,22/tcp + +# check the status of the firewall +sudo ufw status +``` + +For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. + +### Automating your mix node with tmux and systemd + +It's useful to have the mix node automatically start at system boot time. + +#### tmux + +One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated. + +Use the following command to get `tmux`. + +Platform|Install Command +---|--- +Arch Linux|`pacman -S tmux` +Debian or Ubuntu|`apt install tmux` +Fedora|`dnf install tmux` +RHEL or CentOS|`yum install tmux` +macOS (using Homebrew|`brew install tmux` +macOS (using MacPorts)|`port install tmux` +openSUSE|`zypper install tmux` + +In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control). + +**Running tmux** + +No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let the mixnode run on its own on the VPS. + +* Pause your mixnode +* Start tmux with the command +``` +tmux +``` +* The terminal should stay in the same directory, just the layout changed into tmux default layout. +* Start the mixnode again with a command: +``` +./nym-mixnode run --id +``` +* Now, without closing the tmux window, you can close the whole terminal and the mixnode (and any other process running in tmux) will stay active. +* Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session: +``` +tmux attach session +``` +* To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?` + +#### systemd + +Here's a systemd service file to do that: + +```ini +[Unit] +Description=Nym Mixnode ({{mix_node_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User= +LimitNOFILE=65536 +ExecStart=/home///nym-mixnode run --id +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. + +Change the `` in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `` so it is the user you are running as. + +If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` + +Then run: + +``` +systemctl enable nym-mixnode.service +``` + +Start your node: + +``` +service nym-mixnode start +``` + +This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. + +You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. + +Note: if you make any changes to your systemd script after you've enabled it, you will need to run: + +``` +systemctl daemon-reload +``` + +This lets your operating system know it's ok to reload the service configuration. + +#### Setting the ulimit + +Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. + +`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes. + +If you see errors such as: + +``` +Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } +``` + +This means that the operating system is preventing network connections from being made. + +##### Set the ulimit via `systemd` service file + +Query the `ulimit` of your mix node with: + +``` +grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits +``` + +You'll get back the hard and soft limits, which looks something like this: + +``` +Max open files 65536 65536 files +``` + +If your output is **the same as above**, your node will not encounter any `ulimit` related issues. + +However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: + +``` +LimitNOFILE=65536 +``` + +Reload the daemon: + +``` +systemctl daemon-reload +``` + +or execute this as root for system-wide setting of `ulimit`: + +``` +echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf +``` + +Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. + +##### Set the ulimit on `non-systemd` based distributions + +In case you chose tmux option for mixnode automatization, see your `ulimit` list by running: + +``` +ulimit -a + +# watch for the output line -n +-n: file descriptors 1024 +``` + +You can change it either by running a command: + +``` +ulimit -u -n 4096 +``` + +or editing `etc/security/conf` and add the following lines: + +``` +# Example hard limit for max opened files +username hard nofile 4096 + +# Example soft limit for max opened files +username soft nofile 4096 +``` + +Then reboot your server and restart your mixnode. + + + + + +#### Step 1: Upgrading your binary +Follow these steps to upgrade your binary and update its config file: +* pause your gateway process. +* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). +* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. +* restart your gateway process with the new binary. + +> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. + +#### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). + +You can either do this graphically via the Desktop Wallet, or the CLI. + +#### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +![Bonding page](../images/wallet-screenshots/bonding.png) + +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +![Node Settings Page](../images/wallet-screenshots/node_settings.png) + +#### Updating node information via the CLI +If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. + +--- + +## VPS Setup and Automation +### Configure your firewall +Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: + +``` +# check if you have ufw installed +ufw version +# if it is not installed, install with +sudo apt install ufw -y +# enable ufw +sudo ufw enable +# check the status of the firewall +sudo ufw status +``` + +Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: + +``` +sudo ufw allow 1789,22,9000/tcp +# check the status of the firewall +sudo ufw status +``` + +For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. + +### Automating your gateway with systemd +Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: + +```ini +[Unit] +Description=Nym Gateway ({{platform_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User=nym +LimitNOFILE=65536 +ExecStart=/home/nym/nym-gateway run --id supergateway +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. + +Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. + +If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` + + +Then run: + +``` +systemctl enable nym-gateway.service +``` + +Start your node: + +``` +service nym-gateway start +``` + +This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. + +You can also do `service nym-gateway stop` or `service nym-gateway restart`. + +Note: if you make any changes to your systemd script after you've enabled it, you will need to run: + +``` +systemctl daemon-reload +``` + +This lets your operating system know it's ok to reload the service configuration. + +## Gateway related Validator API endpoints +Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 723984ff39..68f6bf9090 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -28,42 +28,11 @@ The `nym-mixnode` binary is currently one point version ahead of the rest of the ## Preliminary steps -There are a couple of steps that need completing before starting to set up your mix node: - -- preparing your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) -- requisitioning a VPS (Virtual Private Server) - -### Wallet preparation - -#### Mainnet - -Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). - -If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. - -`NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several [exchanges](https://www.coingecko.com/en/coins/nym#markets). - -> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. - -#### Sandbox testnet - -Make sure to download a wallet and create an account as outlined above. Then head to our [token faucet](https://faucet.nymtech.net/) and get some tokens to use to bond it. - -### VPS Hardware Specs - -You will need to rent a VPS to run your mix node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol). - -For the moment, we haven't put a great amount of effort into optimizing concurrency to increase throughput, so don't bother provisioning a beastly server with multiple cores. This will change when we get a chance to start doing performance optimizations in a more serious way. Sphinx packet decryption is CPU-bound, so once we optimize, more fast cores will be better. - -For now, see the below rough specs: - -- Processors: 2 cores are fine. Get the fastest CPUs you can afford. -- RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. -- Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your mixnode. ## Mix node setup -Now that you have built the [codebase](https://nymtech.net/docs/binaries/building-nym.html), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](https://nymtech.net/docs/binaries/building-nym.html), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. To begin, move to `/taget/release` directory from which you run the node commands: diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md new file mode 100644 index 0000000000..1c738b34bb --- /dev/null +++ b/documentation/operators/src/preliminary-steps.md @@ -0,0 +1,43 @@ +# Preliminary Steps + +> The Nym mixnode, gateway and network requester binaries were built in the [building nym](https://nymtech.net/docs/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. + +## Preliminary steps + +There are a couple of steps that need completing before starting to set up your mixnode, gateway or a network requester: + +- preparing your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) +- requisitioning a VPS (Virtual Private Server) + +### Wallet preparation +#### Mainnet +Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). + +If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. + +`NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several [exchanges](https://www.coingecko.com/en/coins/nym#markets). + +> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. + + +#### Sandbox testnet +Make sure to download a wallet and create an account as outlined above. Then head to our [token faucet](https://faucet.nymtech.net/) and get some tokens to use to bond it. + +### VPS Hardware Specs +You will need to rent a VPS to run your node on. One key reason for this is that your node **must be able to send TCP data using both IPv4 and IPv6** (as other nodes you talk to may use either protocol). + +For the moment, we haven't put a great amount of effort into optimizing concurrency to increase throughput, so don't bother provisioning a beastly server with multiple cores. This will change when we get a chance to start doing performance optimizations in a more serious way. Sphinx packet decryption is CPU-bound, so once we optimize, more fast cores will be better. + +For now, see the below rough specs: + +- Processors: 2 cores are fine. Get the fastest CPUs you can afford. + +#### For Nym Mixnode + +- RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. +- Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. + +#### For Nym Gateway + +- RAM: Memory requirements depend on the amount of users your Gateway will be serving at any one time. If you're just going to be using it yourself, then minimal RAM is fine. **If you're running your Gateway as part of a Service Grant, get something with at least 4GB RAM.** +- Disks: much like the amount of RAM your Gateway could use, the amount of disk space required will vary with the amount of users your Gateway is serving. **If you're running your Gateway as part of a Service Grant, get something with at least 40GB storage.** From 9a76db479ba1a7bfba63f3362f720c734652ed4a Mon Sep 17 00:00:00 2001 From: serinko Date: Fri, 14 Jul 2023 17:17:07 +0200 Subject: [PATCH 072/146] operator-guides: made todo notes --- documentation/operators/src/faq.md | 2 ++ documentation/operators/src/nodes/gateway-setup.md | 8 +++++++- documentation/operators/src/nodes/mix-node-setup.md | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 5e1f5b72ad..e09a78c21c 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -10,5 +10,7 @@ Hi, do you know if it's on the roadmap for network nodes (requesters, socks5 cli you should be able to switch gateway (and overwrite keys) using —force-register +make a note that the keys will be overwritten in bold when you're noting it in the operators guides + ---> diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 591cd3d1a9..ecd04d1005 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -1,3 +1,7 @@ + # Gateways > The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. @@ -153,9 +157,11 @@ You can either do this graphically via the Desktop Wallet, or the CLI. #### Updating node information via the Desktop Wallet * Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: +/ ![Bonding page](../images/wallet-screenshots/bonding.png) * Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. +/ ![Node Settings Page](../images/wallet-screenshots/node_settings.png) #### Updating node information via the CLI @@ -244,7 +250,7 @@ This lets your operating system know it's ok to reload the service configuration Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. ## Ports -All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. +All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. ### Gateway port reference | Default port | Use | diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 68f6bf9090..dc27005feb 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -10,6 +10,10 @@ TODO - [x] Add second console output to Initialising your mixnode manually as the automatized is not working - [ ] Point users to understand the requirements for becoming a part of the active set. - [ ] Include how to move a mix node from one VPS to another while keeping the delegation etc (ie init a new mix node and move `/home/nym/.nym/mixnodes/data/*` there ?) + - copy that dir over to the new vps + - re-run init - remember that init doesn't overwrite existing keys - to generate a config with the new listening address etc + - change the node info via the wallet + - Since otherwise their keys will point to the old IP address in the smart contract, and their node will (a) not be able to be connected to, and (b) fail uptime checks - [ ] Explain more about self hosted nodes in the 6.1 not only as a troubleshooting ---> From 389ccffb631b537eed19ffe0196b4a63877f3a33 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 14 Jul 2023 19:21:25 +0200 Subject: [PATCH 073/146] operators-guide: moved repeating to maintenance.md, shortened and cleaned the existing guides --- .../operators/src/nodes/gateway-setup.md | 126 +------ .../operators/src/nodes/maintenance.md | 249 ++++++------ .../operators/src/nodes/mix-node-setup.md | 356 +----------------- 3 files changed, 142 insertions(+), 589 deletions(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index ecd04d1005..eaacfaf52a 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -1,6 +1,6 @@ # Gateways @@ -133,127 +133,7 @@ The `run` command starts the gateway: ``` ./nym-gateway run --id ``` +## Maintenance -### Upgrading your gateway -Upgrading your node is a two-step process: -* Updating the binary and `config.toml` on your VPS -* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. +For gateway upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) ->These instructions are specifically regarding upgrading your gateway binary from one version to another. If you want to change node information such as the listening port, you can do this by clicking the `node settings` tab in the `Bonding` page of the wallet. - -#### Step 1: Upgrading your binary -Follow these steps to upgrade your binary and update its config file: -* pause your gateway process. -* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your gateway process with the new binary. - -> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. - -#### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). - -You can either do this graphically via the Desktop Wallet, or the CLI. - -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -/ -![Bonding page](../images/wallet-screenshots/bonding.png) - -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -/ -![Node Settings Page](../images/wallet-screenshots/node_settings.png) - -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. - -## VPS Setup and Automation -### Configure your firewall -Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: - -``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status -``` - -Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: - -``` -sudo ufw allow 1789,22,9000/tcp -# check the status of the firewall -sudo ufw status -``` - -For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. - -### Automating your gateway with systemd -Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: - -```ini -[Unit] -Description=Nym Gateway ({{platform_release_version}}) -StartLimitInterval=350 -StartLimitBurst=10 - -[Service] -User=nym -LimitNOFILE=65536 -ExecStart=/home/nym/nym-gateway run --id supergateway -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 - -[Install] -WantedBy=multi-user.target -``` - -Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. - -Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. - -If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: - -`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` - - -Then run: - -``` -systemctl enable nym-gateway.service -``` - -Start your node: - -``` -service nym-gateway start -``` - -This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. - -You can also do `service nym-gateway stop` or `service nym-gateway restart`. - -Note: if you make any changes to your systemd script after you've enabled it, you will need to run: - -``` -systemctl daemon-reload -``` - -This lets your operating system know it's ok to reload the service configuration. - -## Gateway related Validator API endpoints -Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. - -## Ports -All gateway specific port configuration can be found in `$HOME/.nym/gateways//config/config.toml`. If you do edit any port configs, remember to restart your gateway. - -### Gateway port reference -| Default port | Use | -|--------------|---------------------------| -| 1789 | Listen for Mixnet traffic | -| 9000 | Listen for Client traffic | diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index b2fe722d0a..583bb6aa47 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -1,47 +1,46 @@ # Maintenance - +## Upgrading your node - - -### Upgrading your mix node +> The process is the similar for mixnode, gateway and network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. Upgrading your node is a two-step process: -* Updating the binary and `~/.nym/mixnodes//config.toml` on your VPS -* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. +* Updating the binary and `~/.nym///config.toml` on your VPS +* Updating the node information in the [mixnet smart contract](https://nymtech.net/docs/nyx/mixnet-contract.html). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. -#### Step 1: Upgrading your binary +### Step 1: Upgrading your binary Follow these steps to upgrade your mix node binary and update its config file: * pause your mix node process. * replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. * restart your mix node process with the new binary. -#### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). +### Step 2: Updating your node information in the smart contract +Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). You can either do this graphically via the Desktop Wallet, or the CLI. -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -\ +### Updating node information via the Desktop Wallet +* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: + ![Bonding page](../images/wallet-screenshots/bonding.png) -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -\ +* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. + ![Node Settings Page](../images/wallet-screenshots/node_settings.png) -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. +### Updating node information via the CLI +If you want to bond your `` via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. ---- ## VPS Setup and Automation ### Configure your firewall -The following commands will allow you to set up a firewall using `ufw`. +Although your `` is now ready to recieve traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`. ``` # check if you have ufw installed @@ -57,20 +56,24 @@ sudo ufw enable sudo ufw status ``` -Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: +Finally open your `` p2p port, as well as ports for ssh and ports for verloc and measurement pings: ``` +# for mixnode sudo ufw allow 1789,1790,8000,22/tcp +# for gateway +sudo ufw allow 1789,22,9000/tcp + # check the status of the firewall sudo ufw status ``` -For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. +For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) or [gateway port reference table](https://nymtech.net/docs/nodes/gateway-setup.html#gateway-port-reference) below. -### Automating your mix node with tmux and systemd +### Automating your node with tmux and systemd -It's useful to have the mix node automatically start at system boot time. +Although it’s not totally necessary, it's useful to have the mix node automatically start at system boot time. #### tmux @@ -92,22 +95,22 @@ In case it didn't work for your distribution, see how to build `tmux` from [vers **Running tmux** -No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let the mixnode run on its own on the VPS. +No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let your `` run on its own on the VPS. -* Pause your mixnode +* Pause your `` * Start tmux with the command ``` tmux ``` -* The terminal should stay in the same directory, just the layout changed into tmux default layout. -* Start the mixnode again with a command: +* The tmux terminal should open in the same working directory, just the layout changed into tmux default layout. +* Start the `` again with a command: ``` -./nym-mixnode run --id +./ run --id ``` -* Now, without closing the tmux window, you can close the whole terminal and the mixnode (and any other process running in tmux) will stay active. +* Now, without closing the tmux window, you can close the whole terminal and the `` (and any other process running in tmux) will stay active. * Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session: ``` -tmux attach session +tmux attach-session ``` * To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?` @@ -115,6 +118,8 @@ tmux attach session Here's a systemd service file to do that: +For mixnode: + ```ini [Unit] Description=Nym Mixnode ({{mix_node_release_version}}) @@ -133,29 +138,60 @@ RestartSec=30 WantedBy=multi-user.target ``` -Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. +* Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. -Change the `` in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `` so it is the user you are running as. +For gateway: -If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command might look like this: +```ini +[Unit] +Description=Nym Gateway ({{platform_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 -`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` +[Service] +User=nym +LimitNOFILE=65536 +ExecStart=/home///nym-gateway run --id +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +* Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. + +Change the `` in `ExecStart` to point at your `` binary (`nym-mixnode` or `nym-gateway), and the `` so it is the user you are running as. + +If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command for nym mixnode might look like this: + +`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id `. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` Then run: ``` +# for mixnode systemctl enable nym-mixnode.service + +# for gateway +systemctl enable nym-gateway.service ``` Start your node: ``` +# for mixnode service nym-mixnode start + +# for gateway +service nym-gateway start + ``` This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. -You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. +You can also do `service stop` or `service restart`. Note: if you make any changes to your systemd script after you've enabled it, you will need to run: @@ -165,7 +201,7 @@ systemctl daemon-reload This lets your operating system know it's ok to reload the service configuration. -#### Setting the ulimit +### Setting the ulimit Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. @@ -179,7 +215,9 @@ Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too This means that the operating system is preventing network connections from being made. -##### Set the ulimit via `systemd` service file +#### Set the ulimit via `systemd` service file + +The ulimit setup is relevant for maintenance of nym mixnode only. Query the `ulimit` of your mix node with: @@ -215,7 +253,7 @@ echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. -##### Set the ulimit on `non-systemd` based distributions +#### Set the ulimit on `non-systemd` based distributions In case you chose tmux option for mixnode automatization, see your `ulimit` list by running: @@ -244,114 +282,89 @@ username soft nofile 4096 Then reboot your server and restart your mixnode. +## Virtual IPs and hosting via Google & AWS +For true internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a `` there, please read the following. +On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl ifconfig.me)`, but also specify `--announce-host` with the public IP. Please make sure that you pass the correct, routable `--announce-host`. - - -#### Step 1: Upgrading your binary -Follow these steps to upgrade your binary and update its config file: -* pause your gateway process. -* replace the existing binary with the newest binary (which you can either compile yourself or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your gateway process with the new binary. - -> Do **not** use the `upgrade` command: there is a known error with the command that will be fixed in a subsequent release. - -#### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). - -You can either do this graphically via the Desktop Wallet, or the CLI. - -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -![Bonding page](../images/wallet-screenshots/bonding.png) - -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -![Node Settings Page](../images/wallet-screenshots/node_settings.png) - -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../tools/nym-cli.md#upgrade-a-mix-node) docs. - ---- - -## VPS Setup and Automation -### Configure your firewall -Although your gateway is now ready to receive traffic, your server may not be - the following commands will allow you to set up a properly configured firewall using `ufw`: +For example, on a Google machine, you may see the following output from the `ifconfig` command: ``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status +ens4: flags=4163 mtu 1460 + inet 10.126.5.7 netmask 255.255.255.255 broadcast 0.0.0.0 + ... ``` -Finally open your gateway's p2p port, as well as ports for ssh and incoming traffic connections: +The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. +`./nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. + +Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. + +The right thing to do in this situation is to init with a command: ``` -sudo ufw allow 1789,22,9000/tcp -# check the status of the firewall -sudo ufw status +./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18 ``` -For more information about your gateway's port configuration, check the [gateway port reference table](#gateway-port-reference) below. +This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. -### Automating your gateway with systemd -Although it's not totally necessary, it's useful to have the gateway automatically start at system boot time. Here's a systemd service file to do that: +To find the right IP configuration, contact your VPS provider for support. -```ini -[Unit] -Description=Nym Gateway ({{platform_release_version}}) -StartLimitInterval=350 -StartLimitBurst=10 +## Nym API (previously 'Validator API') endpoints +Numerous API endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. -[Service] -User=nym -LimitNOFILE=65536 -ExecStart=/home/nym/nym-gateway run --id supergateway -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 +### Mix node Reward Estimation API endpoint -[Install] -WantedBy=multi-user.target -``` +The Reward Estimation API endpoint allows mixnode operators to estimate the rewards they could earn for running a Nym mixnode with a specific `MIX_ID`. -Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. +> The `` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). -Change the path in `ExecStart` to point at your gateway binary (`nym-gateway`), and the `User` so it is the user you are running as. +The endpoint is a particularly common for mixnode operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mixnode, the quality of the mixnode's performance, and the overall demand for mixnodes in the network. This information can be useful for mixnode operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability. -If you have built nym on your server, and your username is `jetpanther`, then the start command might look like this: - -`ExecStart=/home/jetpanther/nym/target/release/nym-gateway run --id your-id`. Basically, you want the full `/path/to/nym-gateway run --id whatever-your-node-id-is` - - -Then run: +Using this API endpoint returns information about the Reward Estimation: ``` -systemctl enable nym-gateway.service +/status/mixnode//reward-estimation ``` -Start your node: +Query Response: ``` -service nym-gateway start + "estimation": { + "total_node_reward": "942035.916721770541325331", + "operator": "161666.263307386408152071", + "delegates": "780369.65341438413317326", + "operating_cost": "54444.444444444444444443" + }, ``` -This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. +> The unit of value is measured in `uNYM`. -You can also do `service nym-gateway stop` or `service nym-gateway restart`. +- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node. -Note: if you make any changes to your systemd script after you've enabled it, you will need to run: +- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network. -``` -systemctl daemon-reload -``` +- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network. -This lets your operating system know it's ok to reload the service configuration. +- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. -## Gateway related Validator API endpoints -Numerous gateway related API endpoints are documented on the Validator API's [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your broswer, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. +- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. + +## Ports +All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your mix node. + +### Mix node port reference +| Default port | Use | +| ------------ | ------------------------- | +| `1789` | Listen for mixnet traffic | +| `1790` | Listen for VerLoc traffic | +| `8000` | Metrics http API endpoint | + + +### Gateway port reference +| Default port | Use | +|--------------|---------------------------| +| `1789` | Listen for Mixnet traffic | +| `9000` | Listen for Client traffic | + +/ diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index dc27005feb..8690b17806 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -1,6 +1,6 @@ # Mix Nodes @@ -198,263 +199,16 @@ Keep reading to find out more about configuration options or troubleshooting if Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. -### Describe your mix node (optional) +## Node Description (optional) In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mixnode with the following command: ``` ./nym-mixnode describe --id ``` +Node description is a short text that describes your node. It is displayed in the `./nym-mixnode list` command and in the `./nym-mixnode node-details --id ` command. It also shows up in the node explorer to let people know what your node is about and link to your website. -> Remember to restart your mix node process in order for the new description to be propagated. - -### Upgrading your mix node - -Upgrading your node is a two-step process: -* Updating the binary and `~/.nym/mixnodes//config.toml` on your VPS -* Updating the node information in the [mixnet smart contract](../nyx/mixnet-contract.md). **This is the information that is present on the [mixnet explorer](https://explorer.nymtech.net)**. - -#### Step 1: Upgrading your binary -Follow these steps to upgrade your mix node binary and update its config file: -* pause your mix node process. -* replace the existing binary with the newest binary (which you can either [compile yourself](https://nymtech.net/docs/binaries/building-nym.html) or grab from our [releases page](https://github.com/nymtech/nym/releases)). -* re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. -* restart your mix node process with the new binary. - -#### Step 2: Updating your node information in the smart contract -Follow these steps to update the information about your mix node which is publically avaliable from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). - -You can either do this graphically via the Desktop Wallet, or the CLI. - -#### Updating node information via the Desktop Wallet -* Navigate to the `Bonding` page and click the `Node Settings` link in the top right corner: -\ -![Bonding page](../images/wallet-screenshots/bonding.png) - -* Update the fields in the `Node Settings` page and click `Submit changes to the blockchain`. -\ -![Node Settings Page](../images/wallet-screenshots/node_settings.png) - -#### Updating node information via the CLI -If you want to bond your mix node via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. - -### Displaying mix node information - -You can always check the details of your mix node with the `node-details` command: - -``` -./nym-mixnode node-details --id -``` - -## VPS Setup and Automation -### Configure your firewall -The following commands will allow you to set up a firewall using `ufw`. - -``` -# check if you have ufw installed -ufw version - -# if it is not installed, install with -sudo apt install ufw -y - -# enable ufw -sudo ufw enable - -# check the status of the firewall -sudo ufw status -``` - -Finally open your mix node's p2p port, as well as ports for ssh and ports `8000` and `1790` for verloc and measurement pings: - -``` -sudo ufw allow 1789,1790,8000,22/tcp - -# check the status of the firewall -sudo ufw status -``` - -For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) below. - -### Automating your mix node with tmux and systemd - -It's useful to have the mix node automatically start at system boot time. - -#### tmux - -One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated. - -Use the following command to get `tmux`. - -Platform|Install Command ----|--- -Arch Linux|`pacman -S tmux` -Debian or Ubuntu|`apt install tmux` -Fedora|`dnf install tmux` -RHEL or CentOS|`yum install tmux` -macOS (using Homebrew|`brew install tmux` -macOS (using MacPorts)|`port install tmux` -openSUSE|`zypper install tmux` - -In case it didn't work for your distribution, see how to build `tmux` from [version control](https://github.com/tmux/tmux#from-version-control). - -**Running tmux** - -No when you installed tmux on your VPS, let's run a mixnode on tmux, which allows you to detach your terminal and let the mixnode run on its own on the VPS. - -* Pause your mixnode -* Start tmux with the command -``` -tmux -``` -* The terminal should stay in the same directory, just the layout changed into tmux default layout. -* Start the mixnode again with a command: -``` -./nym-mixnode run --id -``` -* Now, without closing the tmux window, you can close the whole terminal and the mixnode (and any other process running in tmux) will stay active. -* Next time just start your teminal, ssh into the VPS and run the following command to attach back to your previous session: -``` -tmux attach session -``` -* To see keybinding options of tmux press `ctrl`+`b` and after 1 second `?` - -#### systemd - -Here's a systemd service file to do that: - -```ini -[Unit] -Description=Nym Mixnode ({{mix_node_release_version}}) -StartLimitInterval=350 -StartLimitBurst=10 - -[Service] -User= -LimitNOFILE=65536 -ExecStart=/home///nym-mixnode run --id -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 - -[Install] -WantedBy=multi-user.target -``` - -Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. - -Change the `` in `ExecStart` to point at your mix node binary (`nym-mixnode`), and the `` so it is the user you are running as. - -If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command might look like this: - -`ExecStart=/home/jetpanther/nym/target/release/nym-mixnode run --id your-id`. Basically, you want the full `/path/to/nym-mixnode run --id whatever-your-node-id-is` - -Then run: - -``` -systemctl enable nym-mixnode.service -``` - -Start your node: - -``` -service nym-mixnode start -``` - -This will cause your node to start at system boot time. If you restart your machine, the node will come back up automatically. - -You can also do `service nym-mixnode stop` or `service nym-mixnode restart`. - -Note: if you make any changes to your systemd script after you've enabled it, you will need to run: - -``` -systemctl daemon-reload -``` - -This lets your operating system know it's ok to reload the service configuration. - -#### Setting the ulimit - -Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. - -`ulimit` is 1024 by default on most systems. It needs to be set higher, because mix nodes make and receive a lot of connections to other nodes. - -If you see errors such as: - -``` -Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } -``` - -This means that the operating system is preventing network connections from being made. - -##### Set the ulimit via `systemd` service file - -Query the `ulimit` of your mix node with: - -``` -grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits -``` - -You'll get back the hard and soft limits, which looks something like this: - -``` -Max open files 65536 65536 files -``` - -If your output is **the same as above**, your node will not encounter any `ulimit` related issues. - -However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: - -``` -LimitNOFILE=65536 -``` - -Reload the daemon: - -``` -systemctl daemon-reload -``` - -or execute this as root for system-wide setting of `ulimit`: - -``` -echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf -``` - -Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. - -##### Set the ulimit on `non-systemd` based distributions - -In case you chose tmux option for mixnode automatization, see your `ulimit` list by running: - -``` -ulimit -a - -# watch for the output line -n --n: file descriptors 1024 -``` - -You can change it either by running a command: - -``` -ulimit -u -n 4096 -``` - -or editing `etc/security/conf` and add the following lines: - -``` -# Example hard limit for max opened files -username hard nofile 4096 - -# Example soft limit for max opened files -username soft nofile 4096 -``` - -Then reboot your server and restart your mixnode. - -## Node Description -Node description is a short text that describes your node. It is displayed in the `./nym-mixnode list` command and in the `./nym-mixnode node-details` command. It also shows up in the node explorer to let people know what your node is about and link to your website. - -To set your node description, create a file called `description.toml` and put it in the same directory as your `config.toml` file (`~/.nym/mixnodes//description.toml`). The file should look like this example: +You can set your node description, by creating a file called `description.toml` and put it in the same directory as your `config.toml` file (`~/.nym/mixnodes//description.toml`). The file should look like this example: ```toml name = "Winston Smith" @@ -463,7 +217,7 @@ link = "https://nymtech.net" location = "Giza, Egypt" ``` -You will need to restart your node for the changes to take effect. +> Remember to restart your mix node process in order for the new description to be propagated. ## Node Families @@ -573,101 +327,7 @@ For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) -### Virtual IPs and hosting via Google & AWS -For tru internet decentralization we encourage operators to use diverse VPS providers instead of the largest companies offering such services. If for some reasons you have already running AWS or Google and want to setup a mixnode there, please read the following. +## Maintenance -On some services (AWS, Google, etc) the machine's available bind address is not the same as the public IP address. In this case, bind `--host` to the local machine address returned by `$(curl ifconfig.me)`, but also specify `--announce-host` with the public IP. Please make sure that you pass the correct, routable `--announce-host`. - -For example, on a Google machine, you may see the following output from the `ifconfig` command: - -``` -ens4: flags=4163 mtu 1460 - inet 10.126.5.7 netmask 255.255.255.255 broadcast 0.0.0.0 - ... -``` - -The `ens4` interface has the IP `10.126.5.7`. But this isn't the public IP of the machine, it's the IP of the machine on Google's internal network. Google uses virtual routing, so the public IP of this machine is something else, maybe `36.68.243.18`. - -`./nym-mixnode init --host 10.126.5.7`, initalises the mix node, but no packets will be routed because `10.126.5.7` is not on the public internet. - -Trying `nym-mixnode init --host 36.68.243.18`, you'll get back a startup error saying `AddrNotAvailable`. This is because the mix node doesn't know how to bind to a host that's not in the output of `ifconfig`. - -The right thing to do in this situation is to init with a command: -``` -./nym-mixnode init --host 10.126.5.7 --announce-host 36.68.243.18 -``` - -This will bind the mix node to the available host `10.126.5.7`, but announce the mix node's public IP to the directory server as `36.68.243.18`. It's up to you as a node operator to ensure that your public and private IPs match up properly. - -To find the right IP configuration, contact your VPS provider for support. - -## Metrics / API endpoints -The mix node binary exposes several API endpoints that can be pinged in order to gather information about the node, and the Nym API (previously 'Validator API') exposes numerous mix node related endpoints which provide network-wide information about mix nodes, the network topology (the list of avaliable mix nodes for packet routing), and information regarding uptime monitoring and rewarding history. - -### Mix node API endpoints -Since the mix node binary exposes several API endpoints itself, you can ping these easily via curl: - -| Endpoint | Description | Command | -| -------------------- | ------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | -| `/description` | Returns the description of the node set with the `describe` command | `curl :8000/description` | -| `/hardware` | Returns the hardware information of the node | `curl :8000/hardware` | -| `/verloc` | Returns the verloc information of the node, updated every 12 hours | `curl :8000/verloc` | - -The code for exposed API endpoints can be found [here](https://github.com/nymtech/nym/tree/release/{{platform_release_version}}/mixnode/src/node/http). - -> You can get more detailed info by appending `?debug` to the URL, like so: -> ``` -> curl http://:8000/stats?debug -> ``` - -### Mix node related Nym API (previously 'Validator API') endpoints -Numerous endpoints are documented on the Nym API (previously 'Validator API')'s [Swagger Documentation](https://validator.nymtech.net/api/swagger/index.html). There you can also try out various requests from your browser, and download the response from the API. Swagger will also show you what commands it is running, so that you can run these from an app or from your CLI if you prefer. - -#### Mix node Reward Estimation API endpoint - -The Reward Estimation API endpoint allows mixnode operators to estimate the rewards they could earn for running a Nym mixnode with a specific `MIX_ID`. - -> The `` can be found in the "Mix ID" column of the [Network Explorer](https://explorer.nymtech.net/network-components/mixnodes/active). - -The endpoint is a particularly common for mixnode operators as it can provide an estimate of potential earnings based on factors such as the amount of traffic routed through the mixnode, the quality of the mixnode's performance, and the overall demand for mixnodes in the network. This information can be useful for mixnode operators in deciding whether or not to run a mix node and in optimizing its operations for maximum profitability. - -Using this API endpoint returns information about the Reward Estimation: - -``` -/status/mixnode//reward-estimation -``` - -Query Response: - -``` - "estimation": { - "total_node_reward": "942035.916721770541325331", - "operator": "161666.263307386408152071", - "delegates": "780369.65341438413317326", - "operating_cost": "54444.444444444444444443" - }, -``` - -> The unit of value is measured in `uNYM`. - -- `estimated_total_node_reward` - An estimate of the total amount of rewards that a particular mix node can expect to receive during the current epoch. This value is calculated by the Nym Validator based on a number of factors, including the current state of the network, the number of mix nodes currently active in the network, and the amount of network traffic being processed by the mix node. - -- `estimated_operator_reward` - An estimate of the amount of rewards that a particular mix node operator can expect to receive. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the operator's stake in the network. - -- `estimated_delegators_reward` - An estimate of the amount of rewards that mix node delegators can expect to receive individually. This value is calculated by the Nym Validator based on a number of factors, including the amount of traffic being processed by the mix node, the quality of service provided by the mix node, and the delegator's stake in the network. - -- `estimated_node_profit` - An estimate of the profit that a particular mix node operator can expect to earn. This value is calculated by subtracting the mix node operator's `operating_costs` from their `estimated_operator_reward` for the current epoch. - -- `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. - -## Ports -All mix node-specific port configuration can be found in `$HOME/.nym/mixnodes//config/config.toml`. If you do edit any port configs, remember to restart your mix node. - -### Mix node port reference -| Default port | Use | -| ------------ | ------------------------- | -| `1789` | Listen for mixnet traffic | -| `1790` | Listen for VerLoc traffic | -| `8000` | Metrics http API endpoint | -/ +For mixnode upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) From d422741be43afca177d586cb39d792aaa3f77640 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 24 Jul 2023 12:53:32 +0200 Subject: [PATCH 074/146] operators-guide: create NR page & edit maintenance page --- documentation/operators/src/SUMMARY.md | 10 +- .../operators/src/nodes/gateway-setup.md | 2 +- .../operators/src/nodes/maintenance.md | 83 +++++++- .../operators/src/nodes/mix-node-setup.md | 2 +- .../src/nodes/network-requester-setup.md | 179 +++++++++++++++++- 5 files changed, 269 insertions(+), 7 deletions(-) diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 796c7d41ed..3e0fcf4280 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -1,9 +1,17 @@ +# Summary + - [Introduction](introduction.md) +# Binaries +- [Pre-built Binaries](../../docs/src/binaries/pre-built-binaries.md) +- [Building from Source](../../docs/src/binaries/building-nym.md) +- [Binary Initialisation and Configuration](../../docs/src/binaries/init-and-config.md) + + # Operators Guides - [Node Setup Guides](./nodes/setup-guides.md) -- [Preliminary Steps](./preliminary-steps.md) + - [Preliminary Steps](./preliminary-steps.md) - [Mix Node](./nodes/mix-node-setup.md) - [Gateway](./nodes/gateway-setup.md) - [Network Requester](./nodes/network-requester-setup.md) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index eaacfaf52a..dd5c65e2ad 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -4,7 +4,7 @@ TODO ---> # Gateways -> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym gateway was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 583bb6aa47..9216556050 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -20,6 +20,8 @@ Follow these steps to upgrade your mix node binary and update its config file: * re-run `init` with the same values as you used initially. **This will just update the config file, it will not overwrite existing keys**. * restart your mix node process with the new binary. +> In case of a network requester this is all all, the following step is only for mix nodes and gateways. + ### Step 2: Updating your node information in the smart contract Follow these steps to update the information about your `` which is publicly available from the [Nym API](https://validator.nymtech.net/api/swagger/index.html) and information displayed on the [mixnet explorer](https://explorer.nymtech.net). @@ -38,6 +40,37 @@ You can either do this graphically via the Desktop Wallet, or the CLI. If you want to bond your `` via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. +### Upgrading Network Requester to >= v1.1.10 from +``` + +Copy the old keys from your client to the network-requester configuration that was created above: + +``` +cp -vr ~/.nym/clients/myoldclient/data/* ~/.nym/service-providers/network-requester//data +``` + +Edit the configuration to match what you used on your client. Specifically, edit the configuration file at: + +``` +~/.nym/service-providers/network-requester//config/config.toml +``` + +Ensure that the fields `gateway_id`, `gateway_owner`, `gateway_listener` in the new config match those in the old client config at: + +``` +~/.nym/clients/myoldclient/config/config.toml +``` + + ## VPS Setup and Automation ### Configure your firewall Although your `` is now ready to recieve traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`. @@ -65,11 +98,16 @@ sudo ufw allow 1789,1790,8000,22/tcp # for gateway sudo ufw allow 1789,22,9000/tcp -# check the status of the firewall +# for network requester +sudo ufw allow 22,9000/tcp +``` + +Check the status of the firewall: +``` sudo ufw status ``` -For more information about your mix node's port configuration, check the [mix node port reference table](./mix-node-setup.md#mixnode-port-reference) or [gateway port reference table](https://nymtech.net/docs/nodes/gateway-setup.html#gateway-port-reference) below. +For more information about your node's port configuration, check the [port reference table](https://nymtech.net/docs/nodes/gateway-setup.html#ports) below. ### Automating your node with tmux and systemd @@ -162,6 +200,39 @@ WantedBy=multi-user.target * Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. +For network requester: + +```ini +[Unit] +Description=Nym Network Requester ({{platform_release_version}}) +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User=nym # replace this with whatever user you wish +LimitNOFILE=65536 +# remember to add the `--enable-statistics` flag if running as part of a service grant and check the path to your nym-network-requester binary +ExecStart=/home/nym/nym-network-requester run --id +KillSignal=SIGINT +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=multi-user.target +``` + +Now enable and start your requester: + +``` +systemctl enable nym-network-requester.service +systemctl start nym-network-requester.service + +# you can always check your requester has succesfully started with: +systemctl status nym-network-requester.service +``` +* Put the above file onto your system at `/etc/systemd/system/nym-network-requester.service`. + + Change the `` in `ExecStart` to point at your `` binary (`nym-mixnode` or `nym-gateway), and the `` so it is the user you are running as. If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command for nym mixnode might look like this: @@ -351,7 +422,7 @@ Query Response: - `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. ## Ports -All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your mix node. +All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your client and node processes. ### Mix node port reference | Default port | Use | @@ -367,4 +438,10 @@ All ``-specific port configuration can be found in `$HOME/.nym// The Nym mix node binary was built in the [building nym](https://nymtech.net/docs/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym mix node binary was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 797dfd7795..1f5e5eee0c 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -1 +1,178 @@ -# Network Requester + +# Network Requesters + +> The Nym gateway was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. + +> Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. + +## Current version +``` + +``` + +## Preliminary steps + +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your network requester. + +## Network Requester Whitelist +If you have access to a server, you can run the network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. + +By default the network requester is **not** an open proxy (although it can be used as one). It uses a file called `allowed.list` (located in `~/.nym/service-providers/network-requester//`) as a whitelist for outbound requests. + +Any request to a URL which is not on this list will be blocked. + +On startup, if this file is not present, the requester will grab the default whitelist from [Nym's default list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) automatically. + +This default whitelist is useful for knowing that the majority of network requesters are able to support certain apps 'out of the box'. + +**Operators of a network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. + +The domains and IPs on the default whitelist can be broken down by application as follows: + + +``` +# Keybase +keybaseapi.com +s3.amazonaws.com +amazonaws.com +twitter.com +keybase.io +gist.githubusercontent.com + +# Used to for uptime healthcheck (see the section on testing your requester below for more) +nymtech.net + +# Blockstream Green Bitcoin Wallet +blockstream.info +blockstream.com +greenaddress.it + +# Electrum Bitcoin Wallet +electrum.org + +# Helios Ethereum Client +alchemy.com +lightclientdata.org +p2pify.com + +# Telegram - these IPs have been copied from https://core.telegram.org/resources/cidr.txt as Telegram does +# not seem to route by domain as the other apps on this list do +91.108.56.0/22 +91.108.4.0/22 +91.108.8.0/22 +91.108.16.0/22 +91.108.12.0/22 +149.154.160.0/20 +91.105.192.0/23 +91.108.20.0/22 +185.76.151.0/24 +2001:b28:f23d::/48 +2001:b28:f23f::/48 +2001:67c:4e8::/48 +2001:b28:f23c::/48 +2a0a:f280::/32 + +# Matrix +matrix.org + +``` + +## Network Requester Directory +You can find a list of Network Requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. + +> We are currently working on a smart-contract based solution more in line with how Mix nodes and Gateways announce themselves to the network. + +## Viewing command help + +To begin, move to `/taget/release` directory from which you run the node commands: + +``` +cd target/release +``` + +The `./nym-network-requester --help ` command can be used to show a list of available parameters. + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + +You can check the required parameters for available commands by running: + +``` +./nym-network-requester --help +``` + +## Initializing and running your network requester + +The network-requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: + +``` + ./nym-network-requester init --id +``` + +In the following we used `example`. + +~~~admonish example collapsible=true title="Console output" +``` + +``` +~~~ + + +Now that we have initialized our network-requester, we can start it with the following command: + +``` + ./nym-network-requester run --id +``` + +## Maintenance + +For network requester upgrade (including an upgrade from `= v1.1.10`), firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md). + + +## Using your network requester + +The next thing to do is use your requester, share its address with friends (or whoever you want to help privacy-enhance their app traffic). Is this safe to do? If it was an open proxy, this would be unsafe, because any Nym user could make network requests to any system on the internet. + +To make things a bit less stressful for administrators, the Network Requester drops all incoming requests by default. In order for it to make requests, you need to add specific domains to the `allowed.list` file at `$HOME/.nym/service-providers/network-requester/allowed.list`. + +### Supporting custom domains with your network requester +It is easy to add new domains and services to your network requester - simply find out which endpoints (both URLs and raw IP addresses are supported) you need to whitelist, and then add these endpoints to your `allowed.list`. + +How to go about this? Have a look in your nym-network-requester config directory: + +``` +ls $HOME/.nym/service-providers/network-requester/ + +# returns: allowed.list unknown.list +``` + +We already know that `allowed.list` is what lets requests go through. All unknown requests are logged to `unknown.list`. If you want to try using a new client type, just start the new application, point it at your local [socks client](https://nymtech.net/docs/clients/socks5-client.html) (configured to use your remote `nym-network-requester`), and keep copying URLs from `unknown.list` into `allowed.list` (it may take multiple tries until you get all of them, depending on the complexity of the application). Make sure to restart your network requester! + +> If you are adding custom domains, please note that whilst they may appear in the logs of your network-requester as something like `api-0.core.keybaseapi.com:443`, you **only need** to include the main domain name, in this instance `keybaseapi.com` + +### Running an open proxy +If you *really* want to run an open proxy, perhaps for testing purposes for your own use or among a small group of trusted friends, it is possible to do so. You can disable network checks by passing the flag `--open-proxy` flag when you run it. If you run in this configuration, you do so at your own risk. + +## Testing your network requester +1. Make sure `nymtech.net` is in your `allowed.list` (remember to restart your network requester). + +2. Ensure that your network-requester is initialized and running. + +3. In another terminal window, run the following: + +``` +curl -x socks5h://localhost:1080 https://nymtech.net/.wellknown/connect/healthcheck.json +``` + +This command should return the following: + +``` +{ "status": "ok" } +``` + From 990f7d64ddba9bff7a019bed2a66cb25f5009ace Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 26 Jul 2023 11:46:36 +0200 Subject: [PATCH 075/146] operators-guide: create validator tutorial & add maintenance points --- documentation/operators/src/SUMMARY.md | 6 +- documentation/operators/src/introduction.md | 2 +- .../operators/src/nodes/maintenance.md | 219 +++++++++++++++++- .../operators/src/nodes/troubleshooting.md | 17 ++ 4 files changed, 231 insertions(+), 13 deletions(-) diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 3e0fcf4280..f767aec6f7 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -10,12 +10,14 @@ # Operators Guides -- [Node Setup Guides](./nodes/setup-guides.md) +- [Mixnet Nodes Setup](./nodes/setup-guides.md) - [Preliminary Steps](./preliminary-steps.md) - [Mix Node](./nodes/mix-node-setup.md) - [Gateway](./nodes/gateway-setup.md) - [Network Requester](./nodes/network-requester-setup.md) - - [Validator](./nodes/validator-setup.md) +- [Nyx Validator Setup](./nodes/validator-setup.md) - [Maintenance](./nodes/maintenance.md) - [Troubleshooting](./nodes/troubleshooting.md) + diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index a97860f292..48b5984eef 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -1,6 +1,6 @@ # Introduction -This is Nym's operators guide, containing information and setup tutorials about the various pieces of Nym mixnet infrastructure nodes, such as mix node, gateway and network requester. +This is Nym's operators guide, containing information and setup tutorials about the various pieces of Nym mixnet infrastructure nodes, such as mix node, gateway and network requester as well as Nyx chain validators. If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 9216556050..1ac31c959c 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -2,8 +2,7 @@ ## Upgrading your node @@ -70,10 +69,34 @@ Ensure that the fields `gateway_id`, `gateway_owner`, `gateway_listener` in the ~/.nym/clients/myoldclient/config/config.toml ``` +### Upgrading your validator + +Upgrading from `v0.31.1` -> `v0.32.0` process is fairly simple. Grab the `v0.32.0` release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files: + +- the new validator (`nyxd`) v0.32.0 +- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`) + +Wait for the upgrade height to be reached and the chain to halt awaiting upgrade, then: + +* copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`) replacing your existing file with the same name. +* swap in your new `nyxd` binary and restart. + +You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/9). + +Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. + +#### Common reasons for your validator being jailed + +The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. + +Running the command `df -H` will return the size of the various partitions of your VPS. + +If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. + ## VPS Setup and Automation ### Configure your firewall -Although your `` is now ready to recieve traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`. +Although your `` is now ready to receive traffic, your server may not be. The following commands will allow you to set up a firewall using `ufw`. ``` # check if you have ufw installed @@ -100,6 +123,9 @@ sudo ufw allow 1789,22,9000/tcp # for network requester sudo ufw allow 22,9000/tcp + +# for validator +sudo ufw allow 1317,26656,26660,22,80,443/tcp ``` Check the status of the firewall: @@ -156,7 +182,7 @@ tmux attach-session Here's a systemd service file to do that: -For mixnode: +##### For Mixnode ```ini [Unit] @@ -178,7 +204,7 @@ WantedBy=multi-user.target * Put the above file onto your system at `/etc/systemd/system/nym-mixnode.service`. -For gateway: +##### For Gateway ```ini [Unit] @@ -200,7 +226,7 @@ WantedBy=multi-user.target * Put the above file onto your system at `/etc/systemd/system/nym-gateway.service`. -For network requester: +##### For Network requester ```ini [Unit] @@ -232,8 +258,41 @@ systemctl status nym-network-requester.service ``` * Put the above file onto your system at `/etc/systemd/system/nym-network-requester.service`. +##### For Validator -Change the `` in `ExecStart` to point at your `` binary (`nym-mixnode` or `nym-gateway), and the `` so it is the user you are running as. +Below is a systemd unit file to place at `/etc/systemd/system/nymd.service`: + +```ini +[Unit] +Description=Nyxd +StartLimitInterval=350 +StartLimitBurst=10 + +[Service] +User=nyx # change to your user +Type=simple +Environment="LD_LIBRARY_PATH=/home/youruser/path/to/nyx/binaries" # change to correct path +ExecStart=/home/youruser/path/to/nyx/binaries/nymd start # change to correct path +Restart=on-failure +RestartSec=30 +LimitNOFILE=infinity + +[Install] +WantedBy=multi-user.target +``` + +Proceed to start it with: + +``` +systemctl daemon-reload # to pickup the new unit file +systemctl enable nymd # to enable the service +systemctl start nymd # to actually start the service +journalctl -f # to monitor system logs showing the service start +``` + +##### Following steps for Nym Mixnet nodes + +Change the `` in `ExecStart` to point at your `` binary (`nym-mixnode`, `nym-gateway` or `nym-network-requester`), and the `` so it is the user you are running as. If you have built nym in the `$HOME` directory on your server, and your username is `jetpanther`, then the start command for nym mixnode might look like this: @@ -288,14 +347,22 @@ This means that the operating system is preventing network connections from bein #### Set the ulimit via `systemd` service file +> Replace `` variable with `nym-mixnode`, `nym-gateway` or `nym-network-requester` according the node you running on your machine. + The ulimit setup is relevant for maintenance of nym mixnode only. -Query the `ulimit` of your mix node with: +Query the `ulimit` of your `` with: ``` -grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nym-mixnode | grep -v grep |head -n 1 | awk '{print $1}')/limits +# for nym-mixnode, nym-gateway and nym-network requester: +grep -i "open files" /proc/$(ps -A -o pid,cmd|grep | grep -v grep |head -n 1 | awk '{print $1}')/limits + +# for nyx validator: +grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nymd | grep -v grep |head -n 1 | awk '{print $1}')/limits ``` + + You'll get back the hard and soft limits, which looks something like this: ``` @@ -322,7 +389,15 @@ or execute this as root for system-wide setting of `ulimit`: echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf ``` -Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-mixnode)/limits | grep "Max open files"` to make sure the limit has changed to 65535. +Reboot your machine and restart your node. When it comes back, use: +``` +# for nym-mixnode, nym-gateway and nym-network requester: +cat /proc/$(pidof )/limits | grep "Max open files"` to make sure the limit has changed to 65535. + +# for validator +cat /proc/$(pidof nym-validator)/limits | grep "Max open files" +``` +Make sure the limit has changed to 65535. #### Set the ulimit on `non-systemd` based distributions @@ -421,6 +496,121 @@ Query Response: - `estimated_operator_cost` - An estimate of the total cost that a particular mix node operator can expect to incur for their participation. This value is calculated by the Nym Validator based on a number of factors, including the cost of running a mix node, such as server hosting fees, and other expenses associated with operating the mix node. +### Validator: Installing and configuring nginx for HTTPS +#### Setup +[Nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.) is an open source software used for operating high-performance web servers. It allows us to set up reverse proxying on our validator server to improve performance and security. + +Install `nginx` and allow the 'Nginx Full' rule in your firewall: + +``` +sudo ufw allow 'Nginx Full' +``` + +Check nginx is running via systemctl: + +``` +systemctl status nginx +``` + +Which should return: + +``` +● nginx.service - A high performance web server and a reverse proxy server + Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) + Active: active (running) since Fri 2018-04-20 16:08:19 UTC; 3 days ago + Docs: man:nginx(8) + Main PID: 2369 (nginx) + Tasks: 2 (limit: 1153) + CGroup: /system.slice/nginx.service + ├─2369 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; + └─2380 nginx: worker process +``` + +#### Configuration + +Proxying your validator's port `26657` to nginx port `80` can then be done by creating a file with the following at `/etc/nginx/conf.d/validator.conf`: + +``` +server { + listen 80; + listen [::]:80; + server_name "domain_name"; + + location / { + proxy_pass http://127.0.0.1:26657; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} +``` + +Followed by: + +``` +sudo apt install certbot nginx python3 +certbot --nginx -d nym-validator.yourdomain.com -m you@yourdomain.com --agree-tos --noninteractive --redirect +``` + +```admonish caution title="" +If using a VPS running Ubuntu 20: replace `certbot nginx python3` with `python3-certbot-nginx` +``` + +These commands will get you an https encrypted nginx proxy in front of the API. + +### Configuring Prometheus metrics (optional) + +Configure Prometheus with the following commands (adapted from NodesGuru's [Agoric setup guide](https://nodes.guru/agoric/setup-guide/en)): + +``` +echo 'export OTEL_EXPORTER_PROMETHEUS_PORT=9464' >> $HOME/.bashrc +source ~/.bashrc +sed -i '/\[telemetry\]/{:a;n;/enabled/s/false/true/;Ta}' $HOME/.nymd/config/app.toml +sed -i "s/prometheus-retention-time = 0/prometheus-retention-time = 60/g" $HOME/.nymd/config/app.toml +sudo ufw allow 9464 +echo 'Metrics URL: http://'$(curl -s ifconfig.me)':26660/metrics' +``` + +Your validator's metrics will be available to you at the returned 'Metrics URL'. + +~~~admonish example collapsible=true title="Console output" +``` +# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles. +# TYPE go_gc_duration_seconds summary +go_gc_duration_seconds{quantile="0"} 6.7969e-05 +go_gc_duration_seconds{quantile="0.25"} 7.864e-05 +go_gc_duration_seconds{quantile="0.5"} 8.4591e-05 +go_gc_duration_seconds{quantile="0.75"} 0.000115919 +go_gc_duration_seconds{quantile="1"} 0.001137591 +go_gc_duration_seconds_sum 0.356555301 +go_gc_duration_seconds_count 2448 +# HELP go_goroutines Number of goroutines that currently exist. +# TYPE go_goroutines gauge +go_goroutines 668 +# HELP go_info Information about the Go environment. +# TYPE go_info gauge +go_info{version="go1.15.7"} 1 +# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use. +# TYPE go_memstats_alloc_bytes gauge +go_memstats_alloc_bytes 1.62622216e+08 +# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed. +# TYPE go_memstats_alloc_bytes_total counter +go_memstats_alloc_bytes_total 2.09341707264e+11 +# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table. +# TYPE go_memstats_buck_hash_sys_bytes gauge +go_memstats_buck_hash_sys_bytes 5.612319e+06 +# HELP go_memstats_frees_total Total number of frees. +# TYPE go_memstats_frees_total counter +go_memstats_frees_total 2.828263344e+09 +# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started. +# TYPE go_memstats_gc_cpu_fraction gauge +go_memstats_gc_cpu_fraction 0.03357798610671518 +# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata. +# TYPE go_memstats_gc_sys_bytes gauge +go_memstats_gc_sys_bytes 1.3884192e+07 +``` +~~~ + ## Ports All ``-specific port configuration can be found in `$HOME/.nym///config/config.toml`. If you do edit any port configs, remember to restart your client and node processes. @@ -444,4 +634,13 @@ All ``-specific port configuration can be found in `$HOME/.nym// + + + # Troubleshooting + +### Common reasons for your validator being jailed + +The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. + +Running the command `df -H` will return the size of the various partitions of your VPS. + +If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. + From 49d909815d1fc3bcd5ccf81896f40b7aa26cc1d0 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 26 Jul 2023 12:55:05 +0200 Subject: [PATCH 076/146] operators-guide: incorporated PR #3656 --- documentation/operators/src/nodes/gateway-setup.md | 1 + documentation/operators/src/nodes/maintenance.md | 14 ++++++++++++++ .../operators/src/nodes/mix-node-setup.md | 2 ++ .../operators/src/nodes/network-requester-setup.md | 2 ++ 4 files changed, 19 insertions(+) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index dd5c65e2ad..cdc72700e2 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -45,6 +45,7 @@ You can also check the various arguments required for individual commands with: ``` ./nym-gateway --help ``` +> Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. ### Initialising your gateway To check available configuration options use: diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 1ac31c959c..d4884bad84 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -4,6 +4,20 @@ TODO - [x] Compare mixnode, gateway, NR steps and validator of upgrading and automation and make a generic page - this one - for all of them with additional notes for particular nodes ---> +## Useful commands + +> 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. + +For example `./target/debug/nym-network-requester --no-banner build-info --output json` will return: + +``` +{"binary_name":"nym-network-requester","build_timestamp":"2023-07-24T15:38:37.00657Z","build_version":"1.1.23","commit_sha":"c70149400206dce24cf20babb1e64f22202672dd","commit_timestamp":"2023-07-24T14:45:45Z","commit_branch":"feature/simplify-cli-parsing","rustc_version":"1.71.0","rustc_channel":"stable","cargo_profile":"debug"} +``` + ## Upgrading your node > The process is the similar for mixnode, gateway and network requester. In the following steps we use a placeholder `` in the commands, please change it for the type of node you want to upgrade. Any particularities for the given type of node are included. diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 435f560a59..8797c13056 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -67,6 +67,8 @@ You can also check the various arguments required for individual commands with: ./nym-mixnode --help ``` +> Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. + ### Initialising your mix node To check available configuration options for initializing your node use: diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 1f5e5eee0c..33dc3c7c90 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -107,6 +107,8 @@ You can check the required parameters for available commands by running: ./nym-network-requester --help ``` +> Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. + ## Initializing and running your network requester The network-requester needs to be initialized before it can be run. This is required for the embedded nym-client to connect successfully to the mixnet. We want to specify an `` using the `--id` command and give it a value of your choice. The following command will achieve that: From a002ddda8d9003e0ef20710c7be0fc97ec11cbfa Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 27 Jul 2023 12:41:22 +0200 Subject: [PATCH 077/146] operators-guide:troubleshooting.md done - content ready to go out --- documentation/operators/src/faq.md | 3 +- .../operators/src/nodes/maintenance.md | 41 ++- .../operators/src/nodes/mix-node-setup.md | 10 +- .../operators/src/nodes/troubleshooting.md | 325 +++++++++++++++++- 4 files changed, 365 insertions(+), 14 deletions(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index e09a78c21c..88836f17f2 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -3,7 +3,8 @@ TODO - [ ] Explain active set and needed metrics - [ ] List friendly VPS providers - [ ] Explain difficulty running a node on a self-hosted machine -- [ ] Explain uNYM vs NYM. Why, ratio, etc +- [ ] Explain uNYM vs NYM/uNYX vs NYX. Why, ratio, etc +- [ ] Explain why validators set is whitelisted Some community questions: Hi, do you know if it's on the roadmap for network nodes (requesters, socks5 client, etc.) to reconnect to another gateway if the current gateway's connection drops or has issues? I have to reset my requester and socks5 clients to connect them to a new gateway almost every day...😕 having to delete the entire folders associated with them diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index d4884bad84..d809027150 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -3,6 +3,11 @@ ## Useful commands @@ -107,6 +112,32 @@ Running the command `df -H` will return the size of the various partitions of yo If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. +## Moving a node + +In case of a need to move a node from one machine to another and avoiding to lose the delegation, here are few steps how to do it. + +The following examples transfers a mixnode (in case of other nodes, change the `mixnodes` in the command for the `` of your desire. + +* Pause your node process. + +Assuming both machines are remote VPS. + +* Make sure your `~/.ssh/.pub` is in both of the machines `~/.ssh/authorized_keys` file +* Create a `mixnodes` folder in the target VPS. Ssh in from your terminal and run: +``` +# in case none of the nym configs was created previously +mkdir ~/.nym + +#in case no nym mixnode was initialized previously +mkdir ~/.nym/mixnodes +``` +* Move the node data (keys) and config file to the new machine by opening a local terminal (as that one's ssh key is authorized in both of the machines) and running: +``` +scp -r @:~/.nym/mixnodes/ @:~/.nym/mixnodes/ +``` +* Re-run init (remember that init doesn't overwrite existing keys) to generate a config with the new listening address etc. +* Change the node smart contract info via the wallet interface. Otherwise the keys will point to the old IP address in the smart contract, and the node will not be able to be connected, and it will fail up-time checks. +* Re-run the node from the new location. ## VPS Setup and Automation ### Configure your firewall @@ -149,10 +180,18 @@ sudo ufw status For more information about your node's port configuration, check the [port reference table](https://nymtech.net/docs/nodes/gateway-setup.html#ports) below. -### Automating your node with tmux and systemd +### Automating your node with nohup, tmux and systemd Although it’s not totally necessary, it's useful to have the mix node automatically start at system boot time. +#### nohup + +`nohup` is a command with which your terminal is told to ignore the `HUP` or 'hangup' signal. This will stop the node process ending if you kill your session. + +``` +nohup ./ run --id # where `` is the id you set during the `init` command and depends on which node you starting +``` + #### tmux One way is to use `tmux` shell on top of your current VPS terminal. Tmux is a terminal multiplexer, it allows you to create several terminal windows and panes from a single terminal. Processes started in `tmux` keep running after closing the terminal as long as the given `tmux` window was not terminated. diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 8797c13056..7e1cafa64c 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -8,13 +8,7 @@ TODO - [x] Add step 2/3 in the wallet bonding - [x] Better picture alignment. - [x] Add second console output to Initialising your mixnode manually as the automatized is not working -- [ ] Point users to understand the requirements for becoming a part of the active set. -- [ ] Include how to move a mix node from one VPS to another while keeping the delegation etc (ie init a new mix node and move `/home/nym/.nym/mixnodes/data/*` there ?) - - copy that dir over to the new vps - - re-run init - remember that init doesn't overwrite existing keys - to generate a config with the new listening address etc - - change the node info via the wallet - - Since otherwise their keys will point to the old IP address in the smart contract, and their node will (a) not be able to be connected to, and (b) fail uptime checks -- [ ] Explain more about self hosted nodes in the 6.1 not only as a troubleshooting +- [x] Explain more about self hosted nodes in the 6.1 not only as a troubleshooting - [x] Move the upgrade, automation, ulimit, vps, API and port parts to maintenance.md ---> @@ -327,7 +321,7 @@ There are also 2 community explorers which have been created by [Nodes Guru](htt For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) - + ## Maintenance diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index b27a417063..e5333bcfe4 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -1,13 +1,323 @@ - - # Troubleshooting +## Binary Build Problems + +### I am trying to build from the GitHub archive files and the build fails + +GitHub automatically includes .zip and tar.gz files of the Nym repository in its release. You cannot extract these and build - you'll see something like this: + +``` + process didn't exit successfully: `/build/nym/src/nym-0.12.1/target/release/build/nym-socks5-client-c1d0f76a8c7d7e9a/build-script-build` (exit status: 101) + --- stderr + thread 'main' panicked at 'failed to extract build metadata: could not find repository from '/build/nym/src/nym-0.12.1/clients/socks5'; class=Repository (6); code=NotFound (-3)', clients/socks5/build.rs:7:31 + note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +warning: build failed, waiting for other jobs to finish... +error: build failed +``` + +Why does this happen? + +We have scripts which automatically include the Git commit hash and Git tag in the binary for easier debugging later. If you download a .zip and try building from that, it's not a Git repository and build will fail as above. + +What to do? + +* Open terminal in the directory where you want to have a git repository +* To get Nym repository for the first time, run: +``` +git clone https://github.com/nymtech/nym.git +``` +* Follow the instructions to build the platform +* To upgrade, pause your nodes, in the same terminal window run `git pull`, follow the upgrade instructions and re-start your nodes. + +## General Node Config + +### Where can I find my private and public keys and config? + +All config and keys files are stored in a directory named after your `id` which you chose during the `init` process, and can be found at the following PATH: `$HOME/.nym//` where `$HOME` is a home directory of the user (your current user in this case) that launched the node or client. + +The directory structure for each node will be roughly as follows: + +``` +bob@nym:~$ tree /home/nym/.nym/mixnodes/ +/home/nym/.nym/mixnodes/ +|-- nym010 +| |-- config +| | `-- config.toml +| `-- data +| |-- private_identity.pem +| |-- private_sphinx.pem +| |-- public_identity.pem +| `-- public_sphinx.pem +``` + +> If you `cat` the `public_sphinx.pem` key, the output will be different from the public key you will see on Nym [dashboard](https://sandbox-explorer.nymtech.net/). The reason for this is that `.pem` files are encoded in **base64**, however on the web they are in **base58**. Don't be confused if your keys look different. They are the same keys, just with different encoding :) + + +## Mix Nodes + +### How can I tell my node is up and running and mixing traffic? + +First of all check the 'Mixnodes' section of either the Nym Network Explorers: +* [Mainnet](https://explorer.nymtech.net/) +* [Sandbox testnet](https://sandbox-explorer.nymtech.net/) + +Enter your **identity key** to find your node. Check the contents of the `Mixnode stats` and `Routing score` sections. + +There are 2 community explorers currently, which have been created by [Nodes Guru](https://nodes.guru): +* [Mainnet](https://mixnet.explorers.guru/) +* [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) + +If you want more information, or if your node isn't showing up on the explorer of your choice and you want to double-check, here are some examples on how to check if the node is configured properly. + +#### Check from your VPS + +Additional details can be obtained via various methods after you connect to your VPS: + +##### Socket statistics with `ss` + +``` +sudo ss -s -t | grep 1789 # if you have specified a different port in your mixnode config, change accordingly +``` + +This command should return a lot of data containing `ESTAB`. This command should work on every unix based system. + +##### List open files and reliant processes with `lsof` + +``` +# check if lsof is installed: +lsof -v +# install if not installed +sudo apt install lsof +# run against mixnode port +sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly +``` + +This command should return something like this: + +``` +nym-mixno 103349 root 53u IPv6 1333229972 0t0 TCP [2a03:b0c0:3:d0::ff3:f001]:57844->[2a01:4f9:c011:38ae::5]:1789 (ESTABLISHED) +nym-mixno 103349 root 54u IPv4 1333229973 0t0 TCP nym:57104->194.5.78.73:1789 (ESTABLISHED) +nym-mixno 103349 root 55u IPv4 1333229974 0t0 TCP nym:48130->static.236.109.119.168.clients.your-server.de:1789 (ESTABLISHED) +nym-mixno 103349 root 56u IPv4 1333229975 0t0 TCP nym:52548->vmi572614.contaboserver.net:1789 (ESTABLISHED) +nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3:f001]:43244->[2600:1f18:1031:2401:c04b:2f25:ca79:fef3]:1789 (ESTABLISHED) +``` + +##### Query `systemd` journal with `journalctl` + +``` +sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed" +``` + +If you have created `nym-mixnode.service` file (i.e. you are running your mixnode via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: + +``` +2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets! +2021-05-18T12:38:02.178Z INFO nym_mixnode::node::metrics > Since startup mixed 233739 packets! +2021-05-18T12:40:32.344Z INFO nym_mixnode::node::metrics > Since startup mixed 233837 packets! +2021-05-18T12:46:08.549Z INFO nym_mixnode::node::metrics > Since startup mixed 234081 packets! +2021-05-18T12:56:57.129Z INFO nym_mixnode::node::metrics > Since startup mixed 234491 packets! +``` + +You can add ` | tail` to the end of the command to watch for new entries in real time if needed. + +##### 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. + +For example `./target/debug/nym-network-requester --no-banner build-info --output json` will return: + +``` +{"binary_name":"nym-network-requester","build_timestamp":"2023-07-24T15:38:37.00657Z","build_version":"1.1.23","commit_sha":"c70149400206dce24cf20babb1e64f22202672dd","commit_timestamp":"2023-07-24T14:45:45Z","commit_branch":"feature/simplify-cli-parsing","rustc_version":"1.71.0","rustc_channel":"stable","cargo_profile":"debug"} +``` + +#### Check from your local machine + +##### Scan ports with `nmap`: + +``` +nmap -p 1789 -Pn +``` + +If your mixnode is configured properly it should output something like this: + +``` +bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn + +Host is up (0.053s latency). + +PORT STATE SERVICE +1789/tcp open hello +``` + +##### Query online nodes: + +``` +curl --location --request GET 'https://validator.nymtech.net/api/v1/mixnodes/' +``` + +Will return a list all nodes currently online. + +You can query gateways by replacing `mixnodes` with `gateways` in the above command, and can query for the mixnodes and gateways on the Sandbox testnet by replacing `validator` with `sandbox-validator`. + + +#### Check with Network API + +We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mixnode, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). + +### Why is my node not mixing any packets? + +If you are still unable to see your node on the dashboard, or your node is declaring it has not mixed any packets, there are several potential issues: + +- The firewall on your host machine is not configured properly. Checkout the [instructions](./maintenance.md#configure-your-firewall). +- You provided incorrect information when bonding your node. +- You are running your mixnode from a VPS without IPv6 support. +- You did not use the `--announce-host` flag while running the mixnode from your local machine behind NAT. +- You did not configure your router firewall while running the mixnode from your local machine behind NAT, or you are lacking IPv6 support. +- Your mixnode is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). + +```admonish caution +Your mixnode **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! +``` + +#### Incorrect bonding information + +Check that you have provided the correct information when bonding your mixnode in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, un-bond and then re-bond your node! + +> All delegated stake will be lost when un-bonding! However the mixnode must be operational in the first place for the delegation to have any effect. + +#### Missing `announce-host` flag + +On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mixnode host. + +If the difference between the two is unclear, contact the help desk of your VPS provider. + +#### No IPv6 connectivity + +Make sure that your VPS has IPv6 connectivity available with whatever provider you are using. + +To get all ip addresses of your host, try following commands: + +``` +hostname -i +``` + +Will return your **local ip** address. + +``` +hostname -I +``` + +Will return all of the ip addresses of your host. This output should look something like this: + +``` +bob@nym:~$ hostname -I +88.36.11.23 172.18.0.1 2a01:28:ca:102::1:641 +``` + +- The first **ipv4** is the public ip you need to use for the `--announce-host` flag. +- The second **ipv4** is the local ip you need to use for the `--host` flag. +- The 3rd output should confirm if your machine has ipv6 available. + +### Running on a local machine behind NAT with no fixed IP address + +Your ISP has to be IPv6 ready if you want to run a mixnode on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. + +Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! + +If all goes well and you have IPv6 available, then you will need to `init` the mixnode with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). + +Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support. + +Here is a sample of the `init` command example to create the mixnode config. + +``` +./nym-mixnode init --id --host 0.0.0.0 --announce-host 85.160.12.13 +``` + +- `--host 0.0.0.0` should work every time even if your local machine IPv4 address changes. For example on Monday your router gives your machine an address `192.168.0.13` and on Wednesday, the DHCP lease will end and you will be asigned `192.168.0.14`. Using `0.0.0.0` should avoid this without having to set any static ip in your router`s configuration. + +- you can get your current IPv4 address by either using `curl ipinfo.io` if you're on MacOS or Linux or visiting [whatsmyip site](https://www.whatsmyip.org/). Simply copy it and use it as `--anounce-host` address. + +Make sure you check if your node is really mixing. We are aiming to improve the setup for operators running locally, however you may need a bit of patience to set this up from your home behind NAT. + +### Accidentally killing your node process on exiting session + +When you close your current terminal session, you need to make sure you don't kill the mixnode process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). + +### Common errors and warnings + +Most of the `ERROR` and `WARN` messages in your node logs are benign - as long as your node outputs `since startup mixed X packets!` (`X` bust be > 0) in your logs (and this number increases over time), your node is mixing packets. If you want to be sure, check the Nym [dashboard](https://sandbox-explorer.nymtech.net/) or see other ways on how to check if your node is mixing properly as outlined in the section [**How can I tell my node is up and running and mixing traffic?**](./troubleshooting.md#how-can-i-tell-my-node-is-up-and-running-and-mixing-traffic?) above. + +More specific errors and warnings are covered below. + +#### `tokio runtime worker` error + +If you are running into issues with an error including the following: + +``` +thread 'tokio-runtime-worker' panicked at 'Failed to create TCP listener: Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }' +``` + +Then you need to `--announce-host ` and `--host ` on startup. This issue is addressed [above](./troubleshooting.md#missing-`announce-host`-flag) + + +### Can I use a port other than 1789 ? + +Yes! Here is what you will need to do: + +Assuming you would like to use port `1337` for your mixnode, you need to open the new port (and close the old one): + +``` +sudo ufw allow 1337 +sudo ufw deny 1789 +``` + +And then edit the mixnode's config. + +> If you want to change the port for an already running node, you need to stop the process before editing your config file. + +The config file is located at `~/.nym/mixnodes//config/config.toml`. + +For example, assuming `` was chosen to be `alice-node`: + +``` +nano ~/.nym/mixnodes/alice-node/config/config.toml +``` + +You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. + +Finally, restart your node. You should see if the mixnode is using the port you have changed in the config.toml file right after you run the node. + +### What is `verloc` and do I have to configure my mixnode to implement it? + +`verloc` is short for _verifiable location_. Mixnodes and gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fakeable and trustworthy manner. + +You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet from version `0.10.1` onward. + +## Validators + ### Common reasons for your validator being jailed The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. @@ -16,3 +326,10 @@ Running the command `df -H` will return the size of the various partitions of yo If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. + +## Where can I get more help? + +The fastest way to reach one of us or get a help from the community, visit our [Telegram Node Setup Help Chat](https://t.me/nymchan_help_chat) or head to our [Discord](https://Discord.gg/nym). + +For more tech heavy question join our [Matrix core community channel](https://matrix.to/#/#general:nymtech.chat), where you can meet other builders and Nym core team members. + From 50b755cfde74f639cca8369e6b263c977b010fc6 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 27 Jul 2023 13:01:09 +0200 Subject: [PATCH 078/146] corrected scp -3 option --- documentation/operators/src/nodes/maintenance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index d809027150..26d5375a7d 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -133,7 +133,7 @@ mkdir ~/.nym/mixnodes ``` * Move the node data (keys) and config file to the new machine by opening a local terminal (as that one's ssh key is authorized in both of the machines) and running: ``` -scp -r @:~/.nym/mixnodes/ @:~/.nym/mixnodes/ +scp -r -3 @:~/.nym/mixnodes/ @:~/.nym/mixnodes/ ``` * Re-run init (remember that init doesn't overwrite existing keys) to generate a config with the new listening address etc. * Change the node smart contract info via the wallet interface. Otherwise the keys will point to the old IP address in the smart contract, and the node will not be able to be connected, and it will fail up-time checks. From b006e1820f3fa497de6b5633176a10e9bc17bbca Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 28 Jul 2023 13:22:40 +0200 Subject: [PATCH 079/146] faq.md: initial questions and answers - in progress --- documentation/operators/src/faq.md | 67 ++- .../operators/src/nodes/validator-setup.md | 558 ++++++++++++++++++ 2 files changed, 620 insertions(+), 5 deletions(-) create mode 100644 documentation/operators/src/nodes/validator-setup.md diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 88836f17f2..4fbc17694a 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -1,10 +1,10 @@ +---> +# Frequently Asked Questions + +## Mixnet nodes + +### What determines the rewards when running a mixnode? + +The stake required for a mix node to achieve maximum rewards is called to the mix node saturation point os simply stake saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. + +The node stake saturation point, which we denote by Nsat, is given by the stake supply, target level of staking divided by the number of rewarded (active) nodes. + +This design ensures the nodes aim to have a same size of stake (reputation) which can be done by delegation staking, as well as it ensures that there is a decentralization of staking as any higher level of staked tokens per node results in worse rewards. On the contrary, the more mix nodes are active, the lower is Nsat. The equilibrium is reached when the staked tokens are delegated equally across the active mix-nodes and that's our basis for this incentive system. + +For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). And [here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. And finally an [update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. + +### Which VPS providers would you recommend? + +Consider in which jurisdiction they reside and where they want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. + +### Why is a mixnode setup on a self-hosted machine so tricky? + +### What's the Sphinx packet size? + +The sizes are shown in the configs [here](https://github.com/nymtech/nym/blob/1ba6444e722e7757f1175a296bed6e31e25b8db8/common/nymsphinx/params/src/packet_sizes.rs#L12) (default is the one clients use, the others are for research purposes, not to be used in production as this would fragment the anonymity set). More info can be found [here](https://github.com/nymtech/nym/blob/4844ac953a12b29fa27688609ec193f1d560c996/common/nymsphinx/anonymous-replies/src/reply_surb.rs#L80). + +### Why a mix node and a gateway cannot be bond to the same wallet? + +Becauase of the way the smart contract works we keep it one-node one-address at the moment. + +### Which nodes are the most needed to be setup to strengthen Nym infrastructure and which ones bring rewards? + +Right now only mix nodes are rewarded. We're working on gateway and service payments. Gateways are the weak link right now due mostly to lack of incentivisation. Services like Network Requesters are obviously the most necessary for people to start using the platform, and we're working on smart contracts to allow for people to start advertising them the same way they do mix nodes. + +### Are mixnodes whitelisted? + +Nope, anyone can run a mixnode. Purely reliant on the node's reputation (self stake + delegations) & routing score. + +## Validators and tokens + +### What's the difference between NYM and uNYM? + +1 NYM = 1 000 000 uNYM + + + +### Can I run a validator? + +We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. + +### Why is validator set entry whitelisted? + +We understand that the early days of the Nyx blockchain will face possible vulnerabilities in terms of size - easy to disrupt or halt the chain if a malicious party entered with a large portion of stake. Besides that, there are some legal issues we need to address before we can distribute the validator set in a fully permissions fashion. + +### Why does Nym do many airdrops? + +It is part of ensuring decentralisation - we need to avoid a handful of people having too much control over the token and market. Of course ideally people will stake the tokens and contribute to the project at this stage. We run surveys to better understand what people are doing with their tokens and what usability issues there are for staking. Any feedback is appreciated as it helps us improve all aspects of using the token and participating in the ecosystem. diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md new file mode 100644 index 0000000000..6eafb49106 --- /dev/null +++ b/documentation/operators/src/nodes/validator-setup.md @@ -0,0 +1,558 @@ + +# Validators + +> Nym has two main codebases: +> - the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code except for the validators. +> - the [Nym validators](https://github.com/nymtech/nyxd), written in Go. + +The validator is built using [Cosmos SDK](https://cosmos.network) and [Tendermint](https://tendermint.com), with a [CosmWasm](https://cosmwasm.com) smart contract controlling the directory service, node bonding, and delegated mixnet staking. + +> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. + +## Building your validator + +> Any syntax in `<>` brackets is a user's unique variable. Exchange it with a corresponding name without the `<>` brackets. + +### Prerequisites +#### `git`, `gcc`, `jq` + +* Debian-based systems: +``` +apt install git build-essential jq + +# optional additional manual pages can be installed with: +apt-get install manpages-dev +``` + +* Arch-based systems: +Install `git`, `gcc` and `jq` with the following: +``` +pacman -S git gcc jq +``` + +#### `Go` +`Go` can be installed via the following commands (taken from the [Go Download and install page](https://go.dev/doc/install)): + +``` +# First remove any existing old Go installation and extract the archive you just downloaded into /usr/local: +# You may need to run the command as root or through sudo +rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.6.linux-amd64.tar.gz + +# Add /usr/local/go/bin to the PATH environment variable +export PATH=$PATH:/usr/local/go/bin +source $HOME/.profile +``` + + +Verify `Go` is installed with: + +``` +go version +# Should return something like: +go version go1.20.4 linux/amd64 +``` + +### Download a precompiled validator binary +You can find pre-compiled binaries for Ubuntu `22.04` and `20.04` [here](https://github.com/nymtech/nyxd/releases). + +```admonish caution title="" +There are seperate releases for Mainnet and the Sandbox testnet - make sure to download the correct binary to avoid `bech32Prefix` mismatches. +``` + +### Manually compiling your validator binary +The codebase for the Nyx validators can be found [here](https://github.com/nymtech/nyxd). + +The validator binary can be compiled by running the following commands: +``` +git clone https://github.com/nymtech/nyxd.git +cd nyxd +git checkout release/ + +# Mainnet +make build + +# Sandbox testnet +BECH32_PREFIX=nymt make build +``` + +At this point, you will have a copy of the `nyxd` binary in your `build/` directory. Test that it's compiled properly by running: + +``` +./build/nyxd +``` + +You should see a similar help menu printed to you: + +~~~admonish example collapsible=true title="Console output" +``` +Wasm Daemon (server) + +Usage: + nyxd [command] + +Available Commands: + add-genesis-account Add a genesis account to genesis.json + add-wasm-genesis-message Wasm genesis subcommands + collect-gentxs Collect genesis txs and output a genesis.json file + config Create or query an application CLI configuration file + debug Tool for helping with debugging your application + export Export state to JSON + gentx Generate a genesis tx carrying a self delegation + help Help about any command + init Initialize private validator, p2p, genesis, and application configuration files + keys Manage your application's keys + query Querying subcommands + rollback rollback cosmos-sdk and tendermint state by one height + start Run the full node + status Query remote node for status + tendermint Tendermint subcommands + tx Transactions subcommands + validate-genesis validates the genesis file at the default location or at the location passed as an arg + version Print the application binary version information + +Flags: + -h, --help help for nyxd + --home string directory for config and data (default "/home/willow/.nyxd") + --log_format string The logging format (json|plain) (default "plain") + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) (default "info") + --trace print out full stack trace on errors + +Use "nyxd [command] --help" for more information about a command. + +``` +~~~ + +### Linking `nyxd` to `libwasmvm.so` + +`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1`. + +If you downloaded your `nyxd` binary from Github, you will have seen this file when un-`tar`-ing the `.tar.gz` file from the releases page. + +If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.so` file to correct location. + +Simply `cp` or `mv` that file to `/lib/x86_64-linux-gnu/` and re-run `nyxd`. + +### Adding `nyxd` to your `$PATH` +You'll need to set `LD_LIBRARY_PATH` in your user's `~/.bashrc` or `~/.zshrc` file (depends on the terminal you use), and add that to our path. Replace `/home///binaries` in the command below to the locations of `nyxd` and `libwasmvm.so` and run it. If you have compiled these on the server, they will be in the `build/` folder: + +``` +NYX_BINARIES=/home/// + +# if you are using another shell like zsh replace '.bashrc' with the relevant config file +echo 'export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:'NYX_BINARIES >> ~/.bashrc +echo 'export PATH=$PATH:'${NYX_BINARIES} >> ~/.bashrc +source ~/.bashrc +``` + +Test everything worked: + +``` +nyxd +``` + +This should return the regular help menu: + +~~~admonish example collapsible=true title="Console output" +``` +Wasm Daemon (server) + +Usage: + nyxd [command] + +Available Commands: + add-genesis-account Add a genesis account to genesis.json + add-wasm-genesis-message Wasm genesis subcommands + collect-gentxs Collect genesis txs and output a genesis.json file + config Create or query an application CLI configuration file + debug Tool for helping with debugging your application + export Export state to JSON + gentx Generate a genesis tx carrying a self delegation + help Help about any command + init Initialize private validator, p2p, genesis, and application configuration files + keys Manage your application's keys + query Querying subcommands + rollback rollback cosmos-sdk and tendermint state by one height + start Run the full node + status Query remote node for status + tendermint Tendermint subcommands + tx Transactions subcommands + validate-genesis validates the genesis file at the default location or at the location passed as an arg + version Print the application binary version information + +Flags: + -h, --help help for nyxd + --home string directory for config and data (default "/home/willow/.nyxd") + --log_format string The logging format (json|plain) (default "plain") + --log_level string The logging level (trace|debug|info|warn|error|fatal|panic) (default "info") + --trace print out full stack trace on errors + +Use "nyxd [command] --help" for more information about a command. + +``` +~~~ + +## Initialising your validator +### Prerequisites: + +- FQDN Domain name +- IPv4 and IPv6 connectivity + +Choose a name for your validator and use it in place of `` in the following command: + +``` +# Mainnet +nyxd init --chain-id=nyx + +# Sandbox testnet +nyxd init --chain-id=sandbox +``` + +```admonish caution title="" +`init` generates `priv_validator_key.json` and `node_key.json`. + +If you have already set up a validator on a network, **make sure to back up the key located at** +`~/.nyxd/config/priv_validator_key.json`. + +If you don't save the validator key, then it can't sign blocks and will be jailed all the time, and +there is no way to deterministically (re)generate this key. +``` + +At this point, you have a new validator, with its own genesis file located at `$HOME/.nyxd/config/genesis.json`. You will need to replace the contents of that file that with either the Nyx Mainnet or Sandbox Testnet genesis file. + +You can use the following command to download them for the correct network: + +``` +# Mainnet +wget -O $HOME/.nyxd/config/genesis.json https://nymtech.net/genesis/genesis.json + +# Sandbox testnet +wget -O $HOME/.nyxd/config/genesis.json https://sandbox-validator1.nymtech.net/snapshots/genesis.json +``` + +### `config.toml` configuration + +Edit the following config options in `$HOME/.nyxd/config/config.toml` to match the information below for your network: + +``` +# Mainnet +persistent_peers = "ee03a6777fb76a2efd0106c3769daaa064a3fcb5@51.79.21.187:26656" +create_empty_blocks = false +laddr = "tcp://0.0.0.0:26656" +``` + +``` +# Sandbox testnet +cors_allowed_origins = ["*"] +persistent_peers = "8421c0a3d90d490e27e8061f2abcb1276c8358b6@sandbox-validator1.nymtech.net:26666" +create_empty_blocks = false +laddr = "tcp://0.0.0.0:26656" +``` + +These affect the following: +* `persistent_peers = "@.nymtech.net:26666"` allows your validator to start pulling blocks from other validators. **The main sandbox validator listens on `26666` instead of the default `26656` for debugging**. It is recommended you do not change your port from `26656`. +* `create_empty_blocks = false` will save space +* `laddr = "tcp://0.0.0.0:26656"` is in your p2p configuration options + +Optionally, if you want to enable [Prometheus](https://prometheus.io/) metrics then the following must also match in the `config.toml`: + +- `prometheus = true` +- `prometheus_listen_addr = ":26660"` + +> Remember to enable metrics in the 'Configuring Prometheus metrics' section below as well. + +And if you wish to add a human-readable moniker to your node: + +- `moniker = ""` + +Finally, if you plan on using [Cockpit](https://cockpit-project.org/documentation.html) on your server, change the `grpc` port from `9090` as this is the port used by Cockpit. + +### `app.toml` configuration +In the file `$HOME/nyxd/config/app.toml`, set the following values: + +``` +# Mainnet +minimum-gas-prices = "0.025unym,0.025unyx" +enable = true in the `[api]` section to get the API server running +``` +``` +# Sandbox Testnet +minimum-gas-prices = "0.025unymt,0.025unyxt" +enable = true` in the `[api]` section to get the API server running +``` + +### Setting up your validator's admin user +You'll need an admin account to be in charge of your validator. Set that up with: + +``` +nyxd keys add nyxd-admin +``` + +This will add keys for your administrator account to your system's keychain and log your name, address, public key, and mnemonic. As the instructions say, remember to **write down your mnemonic**. + +You can get the admin account's address with: + +``` +nyxd keys show nyxd-admin -a +``` + +Type in your keychain **password**, not the mnemonic, when asked. + +## Starting your validator + +```admonish caution title="" +If you are running a Sandbox testnet validator, please skip the `validate-genesis` command: it will fail due to the size of the genesis file as this is a fork of an existing chain state. +``` + +Everything should now be ready to go. You've got the validator set up, all changes made in `config.toml` and `app.toml`, the Nym genesis file copied into place (replacing the initial auto-generated one). Now let's validate the whole setup: + +``` +nyxd validate-genesis +``` + +If this check passes, you should receive the following output: + +``` +File at /path/to/genesis.json is a valid genesis file +``` + +> If this test did not pass, check that you have replaced the contents of `//.nymd/config/genesis.json` with that of the correct genesis file. + +### Open firewall ports + +Before starting the validator, we will need to open the firewall ports: + +``` +# if ufw is not already installed: +sudo apt install ufw +sudo ufw enable +sudo ufw allow 1317,26656,26660,22,80,443/tcp +# to check everything worked +sudo ufw status +``` + +Ports `22`, `80`, and `443` are for ssh, http, and https connections respectively. The rest of the ports are documented [here](https://docs.cosmos.network/main/core/grpc_rest). + +For more information about your validator's port configuration, check the [validator port reference table](https://nymtech.net/operators/binaries/maintenance.html#ports) below. + +> If you are planning to use [Cockpit](https://cockpit-project.org/) on your validator server then you will have defined a different `grpc` port in your `config.toml` above: remember to open this port as well. + +Start the validator: + +``` +nyxd start +``` + +Once your validator starts, it will start requesting blocks from other validators. This may take several hours. Once it's up to date, you can issue a request to join the validator set with the command below. + +### Syncing from a snapshot +If you wish to sync from a snapshot on **mainnet** use Polkachu's [mainnet](https://polkachu.com/networks/nym) resources. + +If you wish to sync from a snapshot on **Sandbox testnet** use the below commands, which are a modified version of Polkachu's excellent resources. These commands assume you are running an OS with `apt` as the package manager: + +``` +# install lz4 if necessary +sudo apt install snapd -y +sudo snap install lz4 + +# download the snapshot +wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://sandbox-validator1.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4 + +# reset your validator state +nyxd tendermint unsafe-reset-all + +# unpack the snapshot +lz4 -c -d nyxd-sandbox-snapshot-data.tar.lz4 | tar -x -C $HOME/.nyxd +``` + +You can then restart `nyxd` - it should start syncing from a block > 2000000. + +### Joining Consensus +```admonish caution title="" +When joining consensus, make sure that you do not disrupt (or worse - halt) the network by coming in with a disproportionately large amount of staked tokens. + +Please initially stake a small amount of tokens compared to existing validators, then delegate to yourself in tranches over time. +``` + +Once your validator has synced and you have received tokens, you can join consensus and produce blocks. + +``` +# Mainnet +nyxd tx staking create-validator + --amount=10000000unyx + --fees=0unyx + --pubkey=$(/home///nyxd/binaries/nyxd tendermint show-validator) + --moniker="" + --chain-id=nyx + --commission-rate="0.10" + --commission-max-rate="0.20" + --commission-max-change-rate="0.01" + --min-self-delegation="1" + --gas="auto" + --gas-adjustment=1.15 + --from="KEYRING_NAME" + --node https://rpc-1.nyx.nodes.guru:443 +``` +``` +# Sandbox Testnet +nyxd tx staking create-validator + --amount=10000000unyxt + --fees=5000unyxt + --pubkey=$(/home///nym/binaries/nyxd tendermint show-validator) + --moniker="" + --chain-id=sandbox + --commission-rate="0.10" + --commission-max-rate="0.20" + --commission-max-change-rate="0.01" + --min-self-delegation="1" + --gas="auto" + --gas-adjustment=1.15 + --from="KEYRING_NAME" + --node https://sandbox-validator1.nymtech.net:443 +``` + +You'll need either `unyxt` tokens on Sandbox, or `unyx` tokens on mainnet to perform this command. + +> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. + +If you want to edit some details for your node you will use a command like this: + +``` +# Mainnet +nyxd tx staking edit-validator + --chain-id=nyx + --moniker="" + --details="Nyx validator" + --security-contact="" + --identity="" + --gas="auto" + --gas-adjustment=1.15 + --from="KEYRING_NAME" + --fees 2000unyx +``` +``` +# Sandbox testnet +nyxd tx staking edit-validator + --chain-id=sandbox + --moniker="" + --details="Sandbox testnet validator" + --security-contact="your email" + --identity="" + --gas="auto" + --gas-adjustment=1.15 + --from="KEYRING_NAME" + --fees 2000unyxt +``` + +With above command you can specify the `gpg` key last numbers (as used in `keybase`) as well as validator details and your email for security contact. + +### Automating your validator with systemd +You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#systemd) with a quick tutorial. + +### Installing and configuring nginx for HTTPS + +If you want to set up a reverse proxying on the validator server to improve security and performance, using [nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.), follow the manual on the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#setup). + +### Setting the ulimit + +Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#Setting-the-ulimit) to change the `ulimit` value for validators. + +## Using your validator +### Unjailing your validator +If your validator gets jailed, you can fix it with the following command: + +``` +# Mainnet +nyxd tx slashing unjail + --broadcast-mode=block + --from="KEYRING_NAME" + --chain-id=nyx + --gas=auto + --gas-adjustment=1.4 + --fees=7000unyx +``` +``` +# Sandbox Testnet +nyxd tx slashing unjail + --broadcast-mode=block + --from="KEYRING_NAME" + --chain-id=sandbox + --gas=auto + --gas-adjustment=1.4 + --fees=7000unyxt +``` + +### Upgrading your validator + +To upgrade your validator, follow the steps on the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#Setting-the-ulimit). + +#### Common reasons for your validator being jailed + +The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. + +Running the command `df -H` will return the size of the various partitions of your VPS. + +If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. + +### Day 2 operations with your validator + +You can check your current balances with: + +``` +nymd query bank balances ${ADDRESS} +``` + +For example, on the Sanbox testnet this would return: + +```yaml +balances: +- amount: "919376" +denom: unymt +pagination: +next_key: null +total: "0" +``` + +You can, of course, stake back the available balance to your validator with the following command. + +> Remember to save some tokens for gas costs! + +``` +# Mainnet +nyxd tx staking delegate VALOPERADDRESS AMOUNTunym + --from="KEYRING_NAME" + --keyring-backend=os + --chain-id=nyx + --gas="auto" + --gas-adjustment=1.15 + --fees 5000unyx +``` +``` +# Sandbox Testnet +nyxd tx staking delegate VALOPERADDRESS AMOUNTunymt + --from="KEYRING_NAME" + --keyring-backend=os + --chain-id=sandbox + --gas="auto" + --gas-adjustment=1.15 + --fees 5000unyxt +``` + From f0c0ddb1c27d7b66c6f689189129265c69d5f135 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:25:11 +0200 Subject: [PATCH 080/146] operators: book build - minor issues remain --- documentation/operators/book.toml | 10 ++++++---- documentation/operators/src/SUMMARY.md | 3 +-- documentation/operators/src/faq.md | 2 +- .../operators/src/nodes/mix-node-setup.md | 14 -------------- 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index c39bb1c6a1..4202abc3f9 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -52,9 +52,11 @@ minimum_rust_version = "1.66" platform_release_version = "v1.1.22" wallet_release_version = "v1.2.5" -[preprocessor.last-changed] -command = "mdbook-last-changed" -renderer = ["html"] + +# [preprocessor.last-changed] +# command = "mdbook-last-changed" +# renderer = ["html"] + # used for grabbing output of binary commands for automation # https://github.com/FauconFan/mdbook-cmdrun @@ -85,7 +87,7 @@ curly-quotes = true # mathjax-support = false # useful if we want to pull equations in copy-fonts = true no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css"] #,"last-changed.css"] additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index f767aec6f7..04d855952f 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -18,6 +18,5 @@ - [Nyx Validator Setup](./nodes/validator-setup.md) - [Maintenance](./nodes/maintenance.md) - [Troubleshooting](./nodes/troubleshooting.md) - + diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 4fbc17694a..0de60740bd 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -31,7 +31,7 @@ For more detailed calculation, read our blog post [Nym Token Economics update](h ### Which VPS providers would you recommend? -Consider in which jurisdiction they reside and where they want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. +Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. ### Why is a mixnode setup on a self-hosted machine so tricky? diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 7e1cafa64c..f8981fed68 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -1,17 +1,3 @@ - - # Mix Nodes > The Nym mix node binary was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. From a0418daaea504216703818b0220bf5e714198acb Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:47:57 +0200 Subject: [PATCH 081/146] operators: comment missing info --- documentation/operators/src/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 0de60740bd..3c832b68ed 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -33,7 +33,7 @@ For more detailed calculation, read our blog post [Nym Token Economics update](h Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. -### Why is a mixnode setup on a self-hosted machine so tricky? + ### What's the Sphinx packet size? From 585cf55026ead8bab80d970e9f9a32d08f8654f1 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 31 Jul 2023 13:53:21 +0200 Subject: [PATCH 082/146] operators: typo edit --- documentation/operators/src/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index 3c832b68ed..faefd70b18 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -21,7 +21,7 @@ make a note that the keys will be overwritten in bold when you're noting it in t ### What determines the rewards when running a mixnode? -The stake required for a mix node to achieve maximum rewards is called to the mix node saturation point os simply stake saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. +The stake required for a mix node to achieve maximum rewards is called mix node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. The node stake saturation point, which we denote by Nsat, is given by the stake supply, target level of staking divided by the number of rewarded (active) nodes. From 09b15ae020ead3b0553beb1feaf5d2fe4daed707 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:58:29 +0200 Subject: [PATCH 083/146] operators guide: add src/binaries/ files, fix links --- documentation/operators/src/SUMMARY.md | 6 +- .../operators/src/binaries/building-nym.html | 350 ++++++++++++++++++ .../operators/src/binaries/building-nym.md | 71 ++++ .../src/binaries/init-and-config.html | 290 +++++++++++++++ .../operators/src/binaries/init-and-config.md | 13 + .../src/binaries/pre-built-binaries.html | 286 ++++++++++++++ .../src/binaries/pre-built-binaries.md | 6 + .../src/binaries/version-compatiblity.md | 38 ++ .../operators/src/nodes/gateway-setup.md | 2 +- .../operators/src/nodes/mix-node-setup.md | 4 +- .../src/nodes/network-requester-setup.md | 2 +- .../operators/src/nodes/setup-guides.md | 8 +- .../operators/src/nodes/validator-setup.md | 10 +- .../operators/src/preliminary-steps.md | 2 +- 14 files changed, 1071 insertions(+), 17 deletions(-) create mode 100644 documentation/operators/src/binaries/building-nym.html create mode 100644 documentation/operators/src/binaries/building-nym.md create mode 100644 documentation/operators/src/binaries/init-and-config.html create mode 100644 documentation/operators/src/binaries/init-and-config.md create mode 100644 documentation/operators/src/binaries/pre-built-binaries.html create mode 100644 documentation/operators/src/binaries/pre-built-binaries.md create mode 100644 documentation/operators/src/binaries/version-compatiblity.md diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index 04d855952f..a3f55376c8 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -3,9 +3,9 @@ - [Introduction](introduction.md) # Binaries -- [Pre-built Binaries](../../docs/src/binaries/pre-built-binaries.md) -- [Building from Source](../../docs/src/binaries/building-nym.md) -- [Binary Initialisation and Configuration](../../docs/src/binaries/init-and-config.md) +- [Pre-built Binaries](./binaries/pre-built-binaries.md) +- [Building from Source](./binaries/building-nym.md) +- [Binary Initialisation and Configuration](./binaries/init-and-config.md) # Operators Guides diff --git a/documentation/operators/src/binaries/building-nym.html b/documentation/operators/src/binaries/building-nym.html new file mode 100644 index 0000000000..2f73af4b4f --- /dev/null +++ b/documentation/operators/src/binaries/building-nym.html @@ -0,0 +1,350 @@ + + + + + + Building from Source - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Building from Source

+
+

Nym runs on Mac OS X, Linux, and Windows. All nodes except the Desktop Wallet and NymConnect on Windows should be considered experimental - it works fine if you’re an app developer but isn’t recommended for running nodes.

+
+

Building Nym

+

Nym has two main codebases:

+
    +
  • the Nym platform, written in Rust. This contains all of our code except for the validators.
  • +
  • the Nym validators, written in Go.
  • +
+
+

This page details how to build the main Nym platform code. If you want to build and run a validator, go here instead.

+
+

Prerequisites

+
    +
  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
  • +
+
apt install pkg-config build-essential libssl-dev curl jq git
+
+
    +
  • Arch/Manjaro: base-devel
  • +
+
pacman -S base-devel
+
+
    +
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git +Running the following the script installs Homebrew and the above dependencies:
  • +
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
+
    +
  • Rust & cargo >= 1.66
  • +
+

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

+

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

+

Download and build Nym binaries

+

The following commands will compile binaries into the nym/target/release directory:

+
rustup update
+git clone https://github.com/nymtech/nym.git
+cd nym
+
+git reset --hard # in case you made any changes on your branch
+git pull # in case you've checked it out before
+
+git checkout release/v1.1.22 # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks
+
+cargo build --release # build your binaries with **mainnet** configuration
+NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration
+
+

Quite a bit of stuff gets built. The key working parts are:

+ +

The repository also contains Typescript applications which aren’t built in this process. These can be built by following the instructions on their respective docs pages.

+ +
+

You cannot build from GitHub’s .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn’t a Git repository). Check the code out from github using git clone instead.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/operators/src/binaries/building-nym.md b/documentation/operators/src/binaries/building-nym.md new file mode 100644 index 0000000000..8610fcb63a --- /dev/null +++ b/documentation/operators/src/binaries/building-nym.md @@ -0,0 +1,71 @@ +# Building from Source + +> Nym runs on Mac OS X, Linux, and Windows. All nodes **except the Desktop Wallet and NymConnect** on Windows should be considered experimental - it works fine if you're an app developer but isn't recommended for running nodes. + +## Building Nym +Nym has two main codebases: + +- the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code _except_ for the validators. +- the [Nym validators](https://github.com/nymtech/nyxd), written in Go. + +> This page details how to build the main Nym platform code. **If you want to build and run a validator, [go here](../nodes/validator-setup.md) instead.** + +## Prerequisites +- Debian/Ubuntu: `pkg-config`, `build-essential`, `libssl-dev`, `curl`, `jq`, `git` + +``` +apt install pkg-config build-essential libssl-dev curl jq git +``` + +- Arch/Manjaro: `base-devel` + +``` +pacman -S base-devel +``` + +- Mac OS X: `pkg-config` , `brew`, `openss1`, `protobuf`, `curl`, `git` +Running the following the script installs Homebrew and the above dependencies: + +``` +/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" +``` + +- `Rust & cargo >= {{minimum_rust_version}}` + +We recommend using the [Rust shell script installer](https://www.rust-lang.org/tools/install). Installing cargo from your package manager (e.g. `apt`) is not recommended as the packaged versions are usually too old. + +If you really don't want to use the shell script installer, the [Rust installation docs](https://forge.rust-lang.org/infra/other-installation-methods.html) contain instructions for many platforms. + +## Download and build Nym binaries +The following commands will compile binaries into the `nym/target/release` directory: + +``` +rustup update +git clone https://github.com/nymtech/nym.git +cd nym + +git reset --hard # in case you made any changes on your branch +git pull # in case you've checked it out before + +git checkout release/{{platform_release_version}} # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks + +cargo build --release # build your binaries with **mainnet** configuration +NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration +``` + +Quite a bit of stuff gets built. The key working parts are: + +* [mix node](../nodes/mix-node-setup.md): `nym-mixnode` +* [gateway node](../nodes/gateway-setup.md): `nym-gateway` +* [websocket client](https://nymtech.net/docs/clients/websocket-client.html): `nym-client` +* [socks5 client](https://nymtech.net/docs/clients/socks5-client.html): `nym-socks5-client` +* [webassembly client](https://nymtech.net/docs/clients/webassembly-client.html): `webassembly-client` +* [network requester](../nodes/network-requester-setup.md): `nym-network-requester` +* [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli` + +The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages. +* [Nym Wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) +* [Nym Connect](https://nymtech.net/developers/quickstart/nymconnect-gui.html) +* [Network Explorer UI](https://nymtech.net/docs/explorers/mixnet-explorer.html) + +> You cannot build from GitHub's .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn't a Git repository). Check the code out from github using `git clone` instead. diff --git a/documentation/operators/src/binaries/init-and-config.html b/documentation/operators/src/binaries/init-and-config.html new file mode 100644 index 0000000000..147c89cc2d --- /dev/null +++ b/documentation/operators/src/binaries/init-and-config.html @@ -0,0 +1,290 @@ + + + + + + Binary Initialisation and Configuration - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Binary Initialisation and Configuration

+

All Nym binaries must first be initialised with init before being run.

+

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

+

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will not overwrite existing keypairs if they are present.

+

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

+

Once you have run init, you can start your binary with the run command, usually only accompanied by the id of the binary that you specified.

+

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/operators/src/binaries/init-and-config.md b/documentation/operators/src/binaries/init-and-config.md new file mode 100644 index 0000000000..e749662b8e --- /dev/null +++ b/documentation/operators/src/binaries/init-and-config.md @@ -0,0 +1,13 @@ +# Binary Initialisation and Configuration + +All Nym binaries must first be initialised with `init` before being `run`. + +The `init` command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc. + +The `init` command will also create the necessary keypairs and configuration files at `~/.nym///` if these files do not already exist. **It will not overwrite existing keypairs if they are present.** + +You can reconfigure your binaries at any time by editing the config file located at `~/.nym///config/config.toml` and restarting the binary process. + +Once you have run `init`, you can start your binary with the `run` command, usually only accompanied by the `id` of the binary that you specified. + +This `id` is **never** transmitted over the network, and is used to select which local config and key files to use for startup. diff --git a/documentation/operators/src/binaries/pre-built-binaries.html b/documentation/operators/src/binaries/pre-built-binaries.html new file mode 100644 index 0000000000..3497c15d85 --- /dev/null +++ b/documentation/operators/src/binaries/pre-built-binaries.html @@ -0,0 +1,286 @@ + + + + + + Pre-built Binaries - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Pre-built Binaries

+

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

+

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/operators/src/binaries/pre-built-binaries.md b/documentation/operators/src/binaries/pre-built-binaries.md new file mode 100644 index 0000000000..269c26276c --- /dev/null +++ b/documentation/operators/src/binaries/pre-built-binaries.md @@ -0,0 +1,6 @@ +# Pre-built Binaries + +The [Github releases page](https://github.com/nymtech/nym/releases) has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere. + +If the pre-built binaries don't work or are unavailable for your system, you will need to build the platform yourself. + diff --git a/documentation/operators/src/binaries/version-compatiblity.md b/documentation/operators/src/binaries/version-compatiblity.md new file mode 100644 index 0000000000..67e8a71ce6 --- /dev/null +++ b/documentation/operators/src/binaries/version-compatiblity.md @@ -0,0 +1,38 @@ +# Version Compatibility Table + +There are numerous components to Nym which are released independently of one another aside from when breaking changes occur in the [core platform code](https://github.com/nymtech/nym/) - mix nodes, gateways, network requesters, and clients. + +Whilst in general it recommended to be running the most recent version of any software, if you cannot do that for whatever reason this table will tell you which versions of different components are mutually compatible with which platform code releases. + + +| Core Platform | SDK | Wallet | NymConnect | Network Explorer | Mixnet contract | Vesting contract | +| ---------------- | ------------- | --------------- | --------------- | ---------------- | --------------- | ---------------- | +| 1.1.13 - 1.1.14* | 1.1.7 | 1.1.12 - 1.1.13 | 1.1.12 - 1.1.13 | 1.1.2 | 1.2.0 - 1.3.0 | 1.2.0 - 1.3.0 | +| 1.1.1 - 1.1.12 | 1.1.4 - 1.1.7 | 1.1.0 - 1.1.12 | 1.1.1 - 1.1.12 | 1.1.0 - 1.1.2 | 1.1.0 - 1.1.3 | 1.1.0 - 1.1.3 | +| 1.1.0 - 1.1.1 | 1.1.4 | 1.1.0 | 1.1.0 - 1.1.1 | 1.1.0 | 1.1.0 | 1.1.0 | +| 1.1.0 | x | 1.1.0 | 1.1.0 | 1.1.0 | 1.1.0 | 1.1.0 | + +`*` the `nym-mixnode` binary is currently one point ahead of the main platform release version + +> There are seperate changelogs for [`NymConnect`](https://github.com/nymtech/nym/blob/release/{{platform_release_version}}/nym-connect/CHANGELOG.md) and the [`Desktop Wallet`](https://github.com/nymtech/nym/blob/release/{{platform_release_version}}/nym-wallet/CHANGELOG.md). The changelog referenced below is for the core platform code. + +| Platform release changelog | +| ---------------------------------------------------------------------------------------- | +| 1.1.14 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.14/CHANGELOG.md)) | +| 1.1.13 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.13/CHANGELOG.md)) | +| 1.1.12 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.12/CHANGELOG.md)) | +| 1.1.11 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.11/CHANGELOG.md)) | +| 1.1.10 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.10/CHANGELOG.md)) | +| 1.1.9 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.9/CHANGELOG.md)) | +| 1.1.8 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.8/CHANGELOG.md)) | +| 1.1.7 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.7/CHANGELOG.md)) | +| 1.1.6 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.6/CHANGELOG.md)) | +| 1.1.5 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.5/CHANGELOG.md)) | +| 1.1.4 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.4/CHANGELOG.md)) | +| 1.1.3 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.3/CHANGELOG.md)) | +| 1.1.2 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.2/CHANGELOG.md)) | +| 1.1.1 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.1/CHANGELOG.md)) | +| 1.1.0 ([CHANGELOG](https://github.com/nymtech/nym/blob/release/v1.1.0/CHANGELOG.md)) | +| 1.0.2 ([CHANGELOG](https://github.com/nymtech/nym/blob/nym-binaries-1.0.2/CHANGELOG.md)) | +| 1.0.1 ([CHANGELOG](https://github.com/nymtech/nym/blob/nym-binaries-1.0.1/CHANGELOG.md)) | +| 1.0.0 ([CHANGELOG](https://github.com/nymtech/nym/blob/nym-binaries-1.0.0/CHANGELOG.md)) | diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index cdc72700e2..31cff54c22 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -4,7 +4,7 @@ TODO ---> # Gateways -> The Nym gateway was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index f8981fed68..0e711b6faf 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -1,6 +1,6 @@ # Mix Nodes -> The Nym mix node binary was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym mix node binary was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. @@ -17,7 +17,7 @@ Make sure you do the preparation listed in the [preliminary steps page](../preli ## Mix node setup -Now that you have built the [codebase](https://nymtech.net/docs/binaries/building-nym.html), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. To begin, move to `/taget/release` directory from which you run the node commands: diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 33dc3c7c90..1cfee00e9b 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -4,7 +4,7 @@ TODO: ---> # Network Requesters -> The Nym gateway was built in the [building nym](https://nymtech.net/operators/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. > Any syntax in `<>` brackets is a user's unique variable. Exchange with a corresponding name without the `<>` brackets. diff --git a/documentation/operators/src/nodes/setup-guides.md b/documentation/operators/src/nodes/setup-guides.md index b19cf07deb..37955a6549 100644 --- a/documentation/operators/src/nodes/setup-guides.md +++ b/documentation/operators/src/nodes/setup-guides.md @@ -1,13 +1,13 @@ # Node Setup Guides -To setup any type of Nym's node, start with building [Nym's platform](https://nymtech.net/docs/binaries/building-nym.html) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). +To setup any type of Nym's node, start with building [Nym's platform](../binaries/building-nym.md) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). This section contains setup guides for the following node types: * [Mix node](./mix-node-setup.md) diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 6eafb49106..1c843a4cab 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -351,7 +351,7 @@ sudo ufw status Ports `22`, `80`, and `443` are for ssh, http, and https connections respectively. The rest of the ports are documented [here](https://docs.cosmos.network/main/core/grpc_rest). -For more information about your validator's port configuration, check the [validator port reference table](https://nymtech.net/operators/binaries/maintenance.html#ports) below. +For more information about your validator's port configuration, check the [validator port reference table](./maintenance.md#ports) below. > If you are planning to use [Cockpit](https://cockpit-project.org/) on your validator server then you will have defined a different `grpc` port in your `config.toml` above: remember to open this port as well. @@ -465,15 +465,15 @@ nyxd tx staking edit-validator With above command you can specify the `gpg` key last numbers (as used in `keybase`) as well as validator details and your email for security contact. ### Automating your validator with systemd -You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#systemd) with a quick tutorial. +You will most likely want to automate your validator restarting if your server reboots. Checkout the [maintenance page](./maintenance.md#systemd) with a quick tutorial. ### Installing and configuring nginx for HTTPS -If you want to set up a reverse proxying on the validator server to improve security and performance, using [nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.), follow the manual on the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#setup). +If you want to set up a reverse proxying on the validator server to improve security and performance, using [nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.), follow the manual on the [maintenance page](./maintenance.md#setup). ### Setting the ulimit -Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#Setting-the-ulimit) to change the `ulimit` value for validators. +Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](./maintenance.md#Setting-the-ulimit) to change the `ulimit` value for validators. ## Using your validator ### Unjailing your validator @@ -502,7 +502,7 @@ nyxd tx slashing unjail ### Upgrading your validator -To upgrade your validator, follow the steps on the [maintenance page](https://nymtech.net/operators/binaries/maintenance.html#Setting-the-ulimit). +To upgrade your validator, follow the steps on the [maintenance page](./maintenance.md#setting-the-ulimit). #### Common reasons for your validator being jailed diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index 1c738b34bb..5cb76d8e19 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,6 +1,6 @@ # Preliminary Steps -> The Nym mixnode, gateway and network requester binaries were built in the [building nym](https://nymtech.net/docs/binaries/building-nym.html) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym mixnode, gateway and network requester binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ## Preliminary steps From 09c4df844843698b2d7f965e6ce02c31ec43a83b Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 11:04:11 +0200 Subject: [PATCH 084/146] operators guide: book built --- docs/src/binaries/building-nym.html | 242 ++++++++++++ docs/src/binaries/building-nym.md | 1 + docs/src/binaries/init-and-config.html | 242 ++++++++++++ docs/src/binaries/init-and-config.md | 1 + docs/src/binaries/pre-built-binaries.html | 242 ++++++++++++ docs/src/binaries/pre-built-binaries.md | 1 + .../docs/src/binaries/building-nym.html | 350 ++++++++++++++++++ .../docs/src/binaries/init-and-config.html | 290 +++++++++++++++ .../docs/src/binaries/pre-built-binaries.html | 286 ++++++++++++++ 9 files changed, 1655 insertions(+) create mode 100644 docs/src/binaries/building-nym.html create mode 100644 docs/src/binaries/building-nym.md create mode 100644 docs/src/binaries/init-and-config.html create mode 100644 docs/src/binaries/init-and-config.md create mode 100644 docs/src/binaries/pre-built-binaries.html create mode 100644 docs/src/binaries/pre-built-binaries.md create mode 100644 documentation/docs/src/binaries/building-nym.html create mode 100644 documentation/docs/src/binaries/init-and-config.html create mode 100644 documentation/docs/src/binaries/pre-built-binaries.html diff --git a/docs/src/binaries/building-nym.html b/docs/src/binaries/building-nym.html new file mode 100644 index 0000000000..90e9c937cc --- /dev/null +++ b/docs/src/binaries/building-nym.html @@ -0,0 +1,242 @@ + + + + + + Building from Source - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Building from Source

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/docs/src/binaries/building-nym.md b/docs/src/binaries/building-nym.md new file mode 100644 index 0000000000..f195be32f9 --- /dev/null +++ b/docs/src/binaries/building-nym.md @@ -0,0 +1 @@ +# Building from Source diff --git a/docs/src/binaries/init-and-config.html b/docs/src/binaries/init-and-config.html new file mode 100644 index 0000000000..2a9390a316 --- /dev/null +++ b/docs/src/binaries/init-and-config.html @@ -0,0 +1,242 @@ + + + + + + Binary Initialisation and Configuration - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Binary Initialisation and Configuration

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/docs/src/binaries/init-and-config.md b/docs/src/binaries/init-and-config.md new file mode 100644 index 0000000000..9087d5cf00 --- /dev/null +++ b/docs/src/binaries/init-and-config.md @@ -0,0 +1 @@ +# Binary Initialisation and Configuration diff --git a/docs/src/binaries/pre-built-binaries.html b/docs/src/binaries/pre-built-binaries.html new file mode 100644 index 0000000000..a02f51d2bd --- /dev/null +++ b/docs/src/binaries/pre-built-binaries.html @@ -0,0 +1,242 @@ + + + + + + Pre-built Binaries - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Pre-built Binaries

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/docs/src/binaries/pre-built-binaries.md b/docs/src/binaries/pre-built-binaries.md new file mode 100644 index 0000000000..8c52595ce9 --- /dev/null +++ b/docs/src/binaries/pre-built-binaries.md @@ -0,0 +1 @@ +# Pre-built Binaries diff --git a/documentation/docs/src/binaries/building-nym.html b/documentation/docs/src/binaries/building-nym.html new file mode 100644 index 0000000000..2f73af4b4f --- /dev/null +++ b/documentation/docs/src/binaries/building-nym.html @@ -0,0 +1,350 @@ + + + + + + Building from Source - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Building from Source

+
+

Nym runs on Mac OS X, Linux, and Windows. All nodes except the Desktop Wallet and NymConnect on Windows should be considered experimental - it works fine if you’re an app developer but isn’t recommended for running nodes.

+
+

Building Nym

+

Nym has two main codebases:

+
    +
  • the Nym platform, written in Rust. This contains all of our code except for the validators.
  • +
  • the Nym validators, written in Go.
  • +
+
+

This page details how to build the main Nym platform code. If you want to build and run a validator, go here instead.

+
+

Prerequisites

+
    +
  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
  • +
+
apt install pkg-config build-essential libssl-dev curl jq git
+
+
    +
  • Arch/Manjaro: base-devel
  • +
+
pacman -S base-devel
+
+
    +
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git +Running the following the script installs Homebrew and the above dependencies:
  • +
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+
+
    +
  • Rust & cargo >= 1.66
  • +
+

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

+

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

+

Download and build Nym binaries

+

The following commands will compile binaries into the nym/target/release directory:

+
rustup update
+git clone https://github.com/nymtech/nym.git
+cd nym
+
+git reset --hard # in case you made any changes on your branch
+git pull # in case you've checked it out before
+
+git checkout release/v1.1.22 # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks
+
+cargo build --release # build your binaries with **mainnet** configuration
+NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration
+
+

Quite a bit of stuff gets built. The key working parts are:

+ +

The repository also contains Typescript applications which aren’t built in this process. These can be built by following the instructions on their respective docs pages.

+ +
+

You cannot build from GitHub’s .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn’t a Git repository). Check the code out from github using git clone instead.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/docs/src/binaries/init-and-config.html b/documentation/docs/src/binaries/init-and-config.html new file mode 100644 index 0000000000..147c89cc2d --- /dev/null +++ b/documentation/docs/src/binaries/init-and-config.html @@ -0,0 +1,290 @@ + + + + + + Binary Initialisation and Configuration - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Binary Initialisation and Configuration

+

All Nym binaries must first be initialised with init before being run.

+

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

+

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will not overwrite existing keypairs if they are present.

+

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

+

Once you have run init, you can start your binary with the run command, usually only accompanied by the id of the binary that you specified.

+

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + diff --git a/documentation/docs/src/binaries/pre-built-binaries.html b/documentation/docs/src/binaries/pre-built-binaries.html new file mode 100644 index 0000000000..3497c15d85 --- /dev/null +++ b/documentation/docs/src/binaries/pre-built-binaries.html @@ -0,0 +1,286 @@ + + + + + + Pre-built Binaries - Nym Operators Guides + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+ {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ + {comment} +
+ +

Pre-built Binaries

+

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

+

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + From 8fd832e217d002eae51431b613955c74beee1ba0 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:30:07 +0200 Subject: [PATCH 085/146] reinitialized the book - simplified book.toml --- documentation/operators/.gitignore | 26 -- documentation/operators/book.toml | 120 +----- documentation/operators/mdbook-admonish.css | 352 ------------------ documentation/operators/src/faq.md | 17 - .../operators/src/nodes/gateway-setup.md | 4 - .../src/nodes/network-requester-setup.md | 4 - .../operators/src/nodes/setup-guides.md | 7 - .../operators/src/nodes/validator-setup.md | 8 - 8 files changed, 1 insertion(+), 537 deletions(-) delete mode 100644 documentation/operators/mdbook-admonish.css diff --git a/documentation/operators/.gitignore b/documentation/operators/.gitignore index e84b38bdfb..7585238efe 100644 --- a/documentation/operators/.gitignore +++ b/documentation/operators/.gitignore @@ -1,27 +1 @@ -# mdbook files book -book/* -theme/index.hbs -theme/pagetoc.css -theme/pagetoc.js -theme/* -theme - -# --------------- -# Compiled assets -# --------------- -.sass-cache -_site - -# ---------- -# Developing -# ---------- -todo.md -.vscode - -# OSX -.DS_Store - -theme/ -theme -theme/* diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 4202abc3f9..45ffb514ae 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -1,125 +1,7 @@ [book] -title = "Nym Operators Guides" +title = "Nym Operators Guide" authors = ["Max Hampshire", "serinko"] description = "Guides to setup Nym infrastructure" language = "en" multilingual = false # for the moment - ideally work on chinese, brazillian, spanish next src = "src" - -################# -# PREPROCESSORS # -################# - -# Note if changing these fields: -# - make sure you aren't running `mdbook serve` -# - change value of `turn-off = true` to `false`. This is set to `true` usually to avoid a known constant-reload bug with `mdbook serve` and this preprocessor -# - delete `./theme/` dir -# - change the preprocessor values that you want to edit -# - run `mdbook build`: this will rebuild the `./theme` directory -# - change value of `turn-off` back to `true` -[preprocessor.theme] -pagetoc = true -# some variables related (defined in theme/css/variables.css) -pagetoc-width = "13%" -content-max-width = "70%" # 82 -pagetoc-fontsize = "14.5px" -sidebar-width = "300px" -menu-bar-height = "40px" # memu-bar = the bar on the top -page-padding = "20px" -mobile-content-max-width = "98%" - -# layout -content-padding = "0 10px" -content-main-margin-left = "10%" -content-main-margin-right = "10%" -nav-chapters-max-width = "auto" -nav-chapters-min-width = "auto" -chapter-line-height = "2em" -section-line-height = "1.5em" - -# if true, never read and touch the files in theme dir: this is used to stop the looping reload issue referred to in the readme -turn-off = false - -[preprocessor.admonish] -command = "mdbook-admonish" -assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` - -# variables preprocessor: import variables into files -# https://gitlab.com/tglman/mdbook-variables/ -[preprocessor.variables.variables] -minimum_rust_version = "1.66" -# vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.22" -wallet_release_version = "v1.2.5" - - -# [preprocessor.last-changed] -# command = "mdbook-last-changed" -# renderer = ["html"] - - -# used for grabbing output of binary commands for automation -# https://github.com/FauconFan/mdbook-cmdrun -[preprocessor.cmdrun] - -# more pre-processor plugins to look into from https://github.com/rust-lang/mdBook/wiki/Third-party-plugins & https://lib.rs/keywords/mdbook-preprocessor -# mdbook-i18n - -######### -# BUILD # -######### - -[build] -build-dir = "book" # the directory where the output is placed -create-missing = true # whether or not to create missing pages -use-default-preprocessors = true # use the default preprocessors -extra-watch-dirs = [] # directories to watch for triggering builds - -########## -# OUTPUT # -########## - -[output.html] -theme = "theme" # this is the default if not explicitly set -default-theme = "coal" -preferred-dark-theme = "coal" -curly-quotes = true -# mathjax-support = false # useful if we want to pull equations in -copy-fonts = true -no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css"] #,"last-changed.css"] -additional-js = ["theme/pagetoc.js"] -git-repository-url = "https://github.com/nymtech/nym" -git-repository-icon = "fa-github" -# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" -# site-url = "/docs/" -# cname = "nymtech.net" -# input-404 = "not-found.md" # todo make custom 404 page - -[output.html.fold] -enable = true # whether or not to enable section folding -level = 0 # the depth to start folding - -# controlling rust sample code blocks -[output.html.playground] -editable = false # allows editing the source code -copyable = true # include the copy button for copying code snippets -copy-js = true # includes the JavaScript for the code editor -line-numbers = false # displays line numbers for editable code -runnable = true # displays a run button for rust code - -# options for the built in text search -[output.html.search] -enable = true # enables the search feature -limit-results = 30 # maximum number of search results -teaser-word-count = 30 # number of words used for a search result teaser -use-boolean-and = true # multiple search terms must all match -boost-title = 2 # ranking boost factor for matches in headers -boost-hierarchy = 1 # ranking boost factor for matches in page names -boost-paragraph = 1 # ranking boost factor for matches in text -expand = true # partial words will match longer terms -heading-split-level = 3 # link results to heading levels -copy-js = true # include Javascript code for search - -# [output.linkcheck] -# warning-policy = "warn" diff --git a/documentation/operators/mdbook-admonish.css b/documentation/operators/mdbook-admonish.css deleted file mode 100644 index 5e360387df..0000000000 --- a/documentation/operators/mdbook-admonish.css +++ /dev/null @@ -1,352 +0,0 @@ -@charset "UTF-8"; -:root { - --md-admonition-icon--note: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--abstract: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--info: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--tip: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--success: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--question: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--warning: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--failure: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--danger: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--bug: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--example: - url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--quote: - url("data:image/svg+xml;charset=utf-8,"); - --md-details-icon: - url("data:image/svg+xml;charset=utf-8,"); -} - -:is(.admonition) { - display: flow-root; - margin: 1.5625em 0; - padding: 0 1.2rem; - color: var(--fg); - page-break-inside: avoid; - background-color: var(--bg); - border: 0 solid black; - border-inline-start-width: 0.4rem; - border-radius: 0.2rem; - box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); -} -@media print { - :is(.admonition) { - box-shadow: none; - } -} -:is(.admonition) > * { - box-sizing: border-box; -} -:is(.admonition) :is(.admonition) { - margin-top: 1em; - margin-bottom: 1em; -} -:is(.admonition) > .tabbed-set:only-child { - margin-top: 0; -} -html :is(.admonition) > :last-child { - margin-bottom: 1.2rem; -} - -a.admonition-anchor-link { - display: none; - position: absolute; - left: -1.2rem; - padding-right: 1rem; -} -a.admonition-anchor-link:link, a.admonition-anchor-link:visited { - color: var(--fg); -} -a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { - text-decoration: none; -} -a.admonition-anchor-link::before { - content: "§"; -} - -:is(.admonition-title, summary) { - position: relative; - margin-block: 0; - margin-inline: -1.6rem -1.2rem; - padding-block: 0.8rem; - padding-inline: 4.4rem 1.2rem; - font-weight: 700; - background-color: rgba(68, 138, 255, 0.1); - display: flex; -} -:is(.admonition-title, summary) p { - margin: 0; -} -html :is(.admonition-title, summary):last-child { - margin-bottom: 0; -} -:is(.admonition-title, summary)::before { - position: absolute; - top: 0.625em; - inset-inline-start: 1.6rem; - width: 2rem; - height: 2rem; - background-color: #448aff; - mask-image: url('data:image/svg+xml;charset=utf-8,'); - -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-size: contain; - content: ""; -} -:is(.admonition-title, summary):hover a.admonition-anchor-link { - display: initial; -} - -details.admonition > summary.admonition-title::after { - position: absolute; - top: 0.625em; - inset-inline-end: 1.6rem; - height: 2rem; - width: 2rem; - background-color: currentcolor; - mask-image: var(--md-details-icon); - -webkit-mask-image: var(--md-details-icon); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-size: contain; - content: ""; - transform: rotate(0deg); - transition: transform 0.25s; -} -details[open].admonition > summary.admonition-title::after { - transform: rotate(90deg); -} - -:is(.admonition):is(.note) { - border-color: #448aff; -} - -:is(.note) > :is(.admonition-title, summary) { - background-color: rgba(68, 138, 255, 0.1); -} -:is(.note) > :is(.admonition-title, summary)::before { - background-color: #448aff; - mask-image: var(--md-admonition-icon--note); - -webkit-mask-image: var(--md-admonition-icon--note); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.abstract, .summary, .tldr) { - border-color: #00b0ff; -} - -:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { - background-color: rgba(0, 176, 255, 0.1); -} -:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { - background-color: #00b0ff; - mask-image: var(--md-admonition-icon--abstract); - -webkit-mask-image: var(--md-admonition-icon--abstract); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.info, .todo) { - border-color: #00b8d4; -} - -:is(.info, .todo) > :is(.admonition-title, summary) { - background-color: rgba(0, 184, 212, 0.1); -} -:is(.info, .todo) > :is(.admonition-title, summary)::before { - background-color: #00b8d4; - mask-image: var(--md-admonition-icon--info); - -webkit-mask-image: var(--md-admonition-icon--info); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.tip, .hint, .important) { - border-color: #00bfa5; -} - -:is(.tip, .hint, .important) > :is(.admonition-title, summary) { - background-color: rgba(0, 191, 165, 0.1); -} -:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { - background-color: #00bfa5; - mask-image: var(--md-admonition-icon--tip); - -webkit-mask-image: var(--md-admonition-icon--tip); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.success, .check, .done) { - border-color: #00c853; -} - -:is(.success, .check, .done) > :is(.admonition-title, summary) { - background-color: rgba(0, 200, 83, 0.1); -} -:is(.success, .check, .done) > :is(.admonition-title, summary)::before { - background-color: #00c853; - mask-image: var(--md-admonition-icon--success); - -webkit-mask-image: var(--md-admonition-icon--success); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.question, .help, .faq) { - border-color: #64dd17; -} - -:is(.question, .help, .faq) > :is(.admonition-title, summary) { - background-color: rgba(100, 221, 23, 0.1); -} -:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { - background-color: #64dd17; - mask-image: var(--md-admonition-icon--question); - -webkit-mask-image: var(--md-admonition-icon--question); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.warning, .caution, .attention) { - border-color: #ff9100; -} - -:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { - background-color: rgba(255, 145, 0, 0.1); -} -:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { - background-color: #ff9100; - mask-image: var(--md-admonition-icon--warning); - -webkit-mask-image: var(--md-admonition-icon--warning); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.failure, .fail, .missing) { - border-color: #ff5252; -} - -:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { - background-color: rgba(255, 82, 82, 0.1); -} -:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { - background-color: #ff5252; - mask-image: var(--md-admonition-icon--failure); - -webkit-mask-image: var(--md-admonition-icon--failure); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.danger, .error) { - border-color: #ff1744; -} - -:is(.danger, .error) > :is(.admonition-title, summary) { - background-color: rgba(255, 23, 68, 0.1); -} -:is(.danger, .error) > :is(.admonition-title, summary)::before { - background-color: #ff1744; - mask-image: var(--md-admonition-icon--danger); - -webkit-mask-image: var(--md-admonition-icon--danger); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.bug) { - border-color: #f50057; -} - -:is(.bug) > :is(.admonition-title, summary) { - background-color: rgba(245, 0, 87, 0.1); -} -:is(.bug) > :is(.admonition-title, summary)::before { - background-color: #f50057; - mask-image: var(--md-admonition-icon--bug); - -webkit-mask-image: var(--md-admonition-icon--bug); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.example) { - border-color: #7c4dff; -} - -:is(.example) > :is(.admonition-title, summary) { - background-color: rgba(124, 77, 255, 0.1); -} -:is(.example) > :is(.admonition-title, summary)::before { - background-color: #7c4dff; - mask-image: var(--md-admonition-icon--example); - -webkit-mask-image: var(--md-admonition-icon--example); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.quote, .cite) { - border-color: #9e9e9e; -} - -:is(.quote, .cite) > :is(.admonition-title, summary) { - background-color: rgba(158, 158, 158, 0.1); -} -:is(.quote, .cite) > :is(.admonition-title, summary)::before { - background-color: #9e9e9e; - mask-image: var(--md-admonition-icon--quote); - -webkit-mask-image: var(--md-admonition-icon--quote); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -.navy :is(.admonition) { - background-color: var(--sidebar-bg); -} - -.ayu :is(.admonition), .coal :is(.admonition) { - background-color: var(--theme-hover); -} - -.rust :is(.admonition) { - background-color: var(--sidebar-bg); - color: var(--sidebar-fg); -} -.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { - color: var(--sidebar-fg); -} diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index faefd70b18..bc3c210352 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -1,20 +1,3 @@ - # Frequently Asked Questions ## Mixnet nodes diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 31cff54c22..026e7afde0 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -1,7 +1,3 @@ - # Gateways > The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 1cfee00e9b..049b139de6 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -1,7 +1,3 @@ - # Network Requesters > The Nym gateway was built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. diff --git a/documentation/operators/src/nodes/setup-guides.md b/documentation/operators/src/nodes/setup-guides.md index 37955a6549..ca86dd99f4 100644 --- a/documentation/operators/src/nodes/setup-guides.md +++ b/documentation/operators/src/nodes/setup-guides.md @@ -1,10 +1,3 @@ - # Node Setup Guides To setup any type of Nym's node, start with building [Nym's platform](../binaries/building-nym.md) on the machine (VPS) where you want to run the node. Nodes will need to be bond to Nym's wallet, setup one [here](https://nymtech.net/docs/wallet/desktop-wallet.html). diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 1c843a4cab..9e233808d7 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -1,11 +1,3 @@ - # Validators > Nym has two main codebases: From 99a321c54debef1a9ccbf908e053c119476fef7f Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:43:57 +0200 Subject: [PATCH 086/146] reinit the book, delete *.html in /src --- .../operators/src/binaries/building-nym.html | 350 ------------------ .../src/binaries/init-and-config.html | 290 --------------- .../src/binaries/pre-built-binaries.html | 286 -------------- 3 files changed, 926 deletions(-) delete mode 100644 documentation/operators/src/binaries/building-nym.html delete mode 100644 documentation/operators/src/binaries/init-and-config.html delete mode 100644 documentation/operators/src/binaries/pre-built-binaries.html diff --git a/documentation/operators/src/binaries/building-nym.html b/documentation/operators/src/binaries/building-nym.html deleted file mode 100644 index 2f73af4b4f..0000000000 --- a/documentation/operators/src/binaries/building-nym.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Building from Source - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Building from Source

-
-

Nym runs on Mac OS X, Linux, and Windows. All nodes except the Desktop Wallet and NymConnect on Windows should be considered experimental - it works fine if you’re an app developer but isn’t recommended for running nodes.

-
-

Building Nym

-

Nym has two main codebases:

-
    -
  • the Nym platform, written in Rust. This contains all of our code except for the validators.
  • -
  • the Nym validators, written in Go.
  • -
-
-

This page details how to build the main Nym platform code. If you want to build and run a validator, go here instead.

-
-

Prerequisites

-
    -
  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
  • -
-
apt install pkg-config build-essential libssl-dev curl jq git
-
-
    -
  • Arch/Manjaro: base-devel
  • -
-
pacman -S base-devel
-
-
    -
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git -Running the following the script installs Homebrew and the above dependencies:
  • -
-
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
-
-
    -
  • Rust & cargo >= 1.66
  • -
-

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

-

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

-

Download and build Nym binaries

-

The following commands will compile binaries into the nym/target/release directory:

-
rustup update
-git clone https://github.com/nymtech/nym.git
-cd nym
-
-git reset --hard # in case you made any changes on your branch
-git pull # in case you've checked it out before
-
-git checkout release/v1.1.22 # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks
-
-cargo build --release # build your binaries with **mainnet** configuration
-NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration
-
-

Quite a bit of stuff gets built. The key working parts are:

- -

The repository also contains Typescript applications which aren’t built in this process. These can be built by following the instructions on their respective docs pages.

- -
-

You cannot build from GitHub’s .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn’t a Git repository). Check the code out from github using git clone instead.

-
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/operators/src/binaries/init-and-config.html b/documentation/operators/src/binaries/init-and-config.html deleted file mode 100644 index 147c89cc2d..0000000000 --- a/documentation/operators/src/binaries/init-and-config.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - Binary Initialisation and Configuration - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Binary Initialisation and Configuration

-

All Nym binaries must first be initialised with init before being run.

-

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

-

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will not overwrite existing keypairs if they are present.

-

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

-

Once you have run init, you can start your binary with the run command, usually only accompanied by the id of the binary that you specified.

-

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/operators/src/binaries/pre-built-binaries.html b/documentation/operators/src/binaries/pre-built-binaries.html deleted file mode 100644 index 3497c15d85..0000000000 --- a/documentation/operators/src/binaries/pre-built-binaries.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - Pre-built Binaries - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Pre-built Binaries

-

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

-

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - From d2e59f12f6109c5b4f94c157233bccc0ec1c9aa9 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:37:12 +0200 Subject: [PATCH 087/146] operators: book built, no {comments} left, cmdrun and admonish not working --- documentation/operators/book.toml | 118 + documentation/operators/last-changed.css | 6 + documentation/operators/mdbook-admonish.css | 352 ++ documentation/operators/theme/css/chrome.css | 538 +++ documentation/operators/theme/css/general.css | 203 + .../operators/theme/css/variables.css | 3257 +++++++++++++++++ documentation/operators/theme/index.hbs | 1063 ++++++ documentation/operators/theme/pagetoc.css | 47 + documentation/operators/theme/pagetoc.js | 68 + 9 files changed, 5652 insertions(+) create mode 100644 documentation/operators/last-changed.css create mode 100644 documentation/operators/mdbook-admonish.css create mode 100644 documentation/operators/theme/css/chrome.css create mode 100644 documentation/operators/theme/css/general.css create mode 100644 documentation/operators/theme/css/variables.css create mode 100644 documentation/operators/theme/index.hbs create mode 100644 documentation/operators/theme/pagetoc.css create mode 100644 documentation/operators/theme/pagetoc.js diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 45ffb514ae..3a0a9f722b 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -5,3 +5,121 @@ description = "Guides to setup Nym infrastructure" language = "en" multilingual = false # for the moment - ideally work on chinese, brazillian, spanish next src = "src" + +################# +# PREPROCESSORS # +################# + +# Note if changing these fields: +# - make sure you aren't running `mdbook serve` +# - change value of `turn-off = true` to `false`. This is set to `true` usually to avoid a known constant-reload bug with `mdbook serve` and this preprocessor +# - delete `./theme/` dir +# - change the preprocessor values that you want to edit +# - run `mdbook build`: this will rebuild the `./theme` directory +# - change value of `turn-off` back to `true` +[preprocessor.theme] +pagetoc = true +# some variables related (defined in theme/css/variables.css) +pagetoc-width = "13%" +content-max-width = "70%" # 82 +pagetoc-fontsize = "14.5px" +sidebar-width = "300px" +menu-bar-height = "40px" # memu-bar = the bar on the top +page-padding = "20px" +mobile-content-max-width = "98%" + +# layout +content-padding = "0 10px" +content-main-margin-left = "10%" +content-main-margin-right = "10%" +nav-chapters-max-width = "auto" +nav-chapters-min-width = "auto" +chapter-line-height = "2em" +section-line-height = "1.5em" + +# if true, never read and touch the files in theme dir: this is used to stop the looping reload issue referred to in the readme +turn-off = false + +[preprocessor.admonish] +command = "mdbook-admonish" +assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` + +# variables preprocessor: import variables into files +# https://gitlab.com/tglman/mdbook-variables/ +[preprocessor.variables.variables] +minimum_rust_version = "1.66" +# vars for links: TODO think on how to streamline updating +platform_release_version = "v1.1.22" +wallet_release_version = "v1.2.5" + + +# [preprocessor.last-changed] +# command = "mdbook-last-changed" +# renderer = ["html"] + + +# used for grabbing output of binary commands for automation +# https://github.com/FauconFan/mdbook-cmdrun +[preprocessor.cmdrun] + +# more pre-processor plugins to look into from https://github.com/rust-lang/mdBook/wiki/Third-party-plugins & https://lib.rs/keywords/mdbook-preprocessor +# mdbook-i18n + +######### +# BUILD # +######### + +[build] +build-dir = "book" # the directory where the output is placed +create-missing = true # whether or not to create missing pages +use-default-preprocessors = true # use the default preprocessors +extra-watch-dirs = [] # directories to watch for triggering builds + +########## +# OUTPUT # +########## + +[output.html] +theme = "theme" # this is the default if not explicitly set +default-theme = "coal" +preferred-dark-theme = "coal" +curly-quotes = true +# mathjax-support = false # useful if we want to pull equations in +copy-fonts = true +no-section-label = false +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./last-changed.css"] +additional-js = ["theme/pagetoc.js"] +git-repository-url = "https://github.com/nymtech/nym" +git-repository-icon = "fa-github" +# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" +# site-url = "/docs/" +# cname = "nymtech.net" +# input-404 = "not-found.md" # todo make custom 404 page + +[output.html.fold] +enable = true # whether or not to enable section folding +level = 0 # the depth to start folding + +# controlling rust sample code blocks +[output.html.playground] +editable = false # allows editing the source code +copyable = true # include the copy button for copying code snippets +copy-js = true # includes the JavaScript for the code editor +line-numbers = false # displays line numbers for editable code +runnable = true # displays a run button for rust code + +# options for the built in text search +[output.html.search] +enable = true # enables the search feature +limit-results = 30 # maximum number of search results +teaser-word-count = 30 # number of words used for a search result teaser +use-boolean-and = true # multiple search terms must all match +boost-title = 2 # ranking boost factor for matches in headers +boost-hierarchy = 1 # ranking boost factor for matches in page names +boost-paragraph = 1 # ranking boost factor for matches in text +expand = true # partial words will match longer terms +heading-split-level = 3 # link results to heading levels +copy-js = true # include Javascript code for search + +# [output.linkcheck] +# warning-policy = "warn" diff --git a/documentation/operators/last-changed.css b/documentation/operators/last-changed.css new file mode 100644 index 0000000000..0c4228de32 --- /dev/null +++ b/documentation/operators/last-changed.css @@ -0,0 +1,6 @@ +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 5px 0; + } \ No newline at end of file diff --git a/documentation/operators/mdbook-admonish.css b/documentation/operators/mdbook-admonish.css new file mode 100644 index 0000000000..5e360387df --- /dev/null +++ b/documentation/operators/mdbook-admonish.css @@ -0,0 +1,352 @@ +@charset "UTF-8"; +:root { + --md-admonition-icon--note: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--abstract: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--info: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--tip: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--success: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--question: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--warning: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--failure: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--danger: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--bug: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--example: + url("data:image/svg+xml;charset=utf-8,"); + --md-admonition-icon--quote: + url("data:image/svg+xml;charset=utf-8,"); + --md-details-icon: + url("data:image/svg+xml;charset=utf-8,"); +} + +:is(.admonition) { + display: flow-root; + margin: 1.5625em 0; + padding: 0 1.2rem; + color: var(--fg); + page-break-inside: avoid; + background-color: var(--bg); + border: 0 solid black; + border-inline-start-width: 0.4rem; + border-radius: 0.2rem; + box-shadow: 0 0.2rem 1rem rgba(0, 0, 0, 0.05), 0 0 0.1rem rgba(0, 0, 0, 0.1); +} +@media print { + :is(.admonition) { + box-shadow: none; + } +} +:is(.admonition) > * { + box-sizing: border-box; +} +:is(.admonition) :is(.admonition) { + margin-top: 1em; + margin-bottom: 1em; +} +:is(.admonition) > .tabbed-set:only-child { + margin-top: 0; +} +html :is(.admonition) > :last-child { + margin-bottom: 1.2rem; +} + +a.admonition-anchor-link { + display: none; + position: absolute; + left: -1.2rem; + padding-right: 1rem; +} +a.admonition-anchor-link:link, a.admonition-anchor-link:visited { + color: var(--fg); +} +a.admonition-anchor-link:link:hover, a.admonition-anchor-link:visited:hover { + text-decoration: none; +} +a.admonition-anchor-link::before { + content: "§"; +} + +:is(.admonition-title, summary) { + position: relative; + margin-block: 0; + margin-inline: -1.6rem -1.2rem; + padding-block: 0.8rem; + padding-inline: 4.4rem 1.2rem; + font-weight: 700; + background-color: rgba(68, 138, 255, 0.1); + display: flex; +} +:is(.admonition-title, summary) p { + margin: 0; +} +html :is(.admonition-title, summary):last-child { + margin-bottom: 0; +} +:is(.admonition-title, summary)::before { + position: absolute; + top: 0.625em; + inset-inline-start: 1.6rem; + width: 2rem; + height: 2rem; + background-color: #448aff; + mask-image: url('data:image/svg+xml;charset=utf-8,'); + -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; +} +:is(.admonition-title, summary):hover a.admonition-anchor-link { + display: initial; +} + +details.admonition > summary.admonition-title::after { + position: absolute; + top: 0.625em; + inset-inline-end: 1.6rem; + height: 2rem; + width: 2rem; + background-color: currentcolor; + mask-image: var(--md-details-icon); + -webkit-mask-image: var(--md-details-icon); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-size: contain; + content: ""; + transform: rotate(0deg); + transition: transform 0.25s; +} +details[open].admonition > summary.admonition-title::after { + transform: rotate(90deg); +} + +:is(.admonition):is(.note) { + border-color: #448aff; +} + +:is(.note) > :is(.admonition-title, summary) { + background-color: rgba(68, 138, 255, 0.1); +} +:is(.note) > :is(.admonition-title, summary)::before { + background-color: #448aff; + mask-image: var(--md-admonition-icon--note); + -webkit-mask-image: var(--md-admonition-icon--note); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.abstract, .summary, .tldr) { + border-color: #00b0ff; +} + +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary) { + background-color: rgba(0, 176, 255, 0.1); +} +:is(.abstract, .summary, .tldr) > :is(.admonition-title, summary)::before { + background-color: #00b0ff; + mask-image: var(--md-admonition-icon--abstract); + -webkit-mask-image: var(--md-admonition-icon--abstract); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.info, .todo) { + border-color: #00b8d4; +} + +:is(.info, .todo) > :is(.admonition-title, summary) { + background-color: rgba(0, 184, 212, 0.1); +} +:is(.info, .todo) > :is(.admonition-title, summary)::before { + background-color: #00b8d4; + mask-image: var(--md-admonition-icon--info); + -webkit-mask-image: var(--md-admonition-icon--info); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.tip, .hint, .important) { + border-color: #00bfa5; +} + +:is(.tip, .hint, .important) > :is(.admonition-title, summary) { + background-color: rgba(0, 191, 165, 0.1); +} +:is(.tip, .hint, .important) > :is(.admonition-title, summary)::before { + background-color: #00bfa5; + mask-image: var(--md-admonition-icon--tip); + -webkit-mask-image: var(--md-admonition-icon--tip); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.success, .check, .done) { + border-color: #00c853; +} + +:is(.success, .check, .done) > :is(.admonition-title, summary) { + background-color: rgba(0, 200, 83, 0.1); +} +:is(.success, .check, .done) > :is(.admonition-title, summary)::before { + background-color: #00c853; + mask-image: var(--md-admonition-icon--success); + -webkit-mask-image: var(--md-admonition-icon--success); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.question, .help, .faq) { + border-color: #64dd17; +} + +:is(.question, .help, .faq) > :is(.admonition-title, summary) { + background-color: rgba(100, 221, 23, 0.1); +} +:is(.question, .help, .faq) > :is(.admonition-title, summary)::before { + background-color: #64dd17; + mask-image: var(--md-admonition-icon--question); + -webkit-mask-image: var(--md-admonition-icon--question); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.warning, .caution, .attention) { + border-color: #ff9100; +} + +:is(.warning, .caution, .attention) > :is(.admonition-title, summary) { + background-color: rgba(255, 145, 0, 0.1); +} +:is(.warning, .caution, .attention) > :is(.admonition-title, summary)::before { + background-color: #ff9100; + mask-image: var(--md-admonition-icon--warning); + -webkit-mask-image: var(--md-admonition-icon--warning); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.failure, .fail, .missing) { + border-color: #ff5252; +} + +:is(.failure, .fail, .missing) > :is(.admonition-title, summary) { + background-color: rgba(255, 82, 82, 0.1); +} +:is(.failure, .fail, .missing) > :is(.admonition-title, summary)::before { + background-color: #ff5252; + mask-image: var(--md-admonition-icon--failure); + -webkit-mask-image: var(--md-admonition-icon--failure); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.danger, .error) { + border-color: #ff1744; +} + +:is(.danger, .error) > :is(.admonition-title, summary) { + background-color: rgba(255, 23, 68, 0.1); +} +:is(.danger, .error) > :is(.admonition-title, summary)::before { + background-color: #ff1744; + mask-image: var(--md-admonition-icon--danger); + -webkit-mask-image: var(--md-admonition-icon--danger); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.bug) { + border-color: #f50057; +} + +:is(.bug) > :is(.admonition-title, summary) { + background-color: rgba(245, 0, 87, 0.1); +} +:is(.bug) > :is(.admonition-title, summary)::before { + background-color: #f50057; + mask-image: var(--md-admonition-icon--bug); + -webkit-mask-image: var(--md-admonition-icon--bug); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.example) { + border-color: #7c4dff; +} + +:is(.example) > :is(.admonition-title, summary) { + background-color: rgba(124, 77, 255, 0.1); +} +:is(.example) > :is(.admonition-title, summary)::before { + background-color: #7c4dff; + mask-image: var(--md-admonition-icon--example); + -webkit-mask-image: var(--md-admonition-icon--example); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +:is(.admonition):is(.quote, .cite) { + border-color: #9e9e9e; +} + +:is(.quote, .cite) > :is(.admonition-title, summary) { + background-color: rgba(158, 158, 158, 0.1); +} +:is(.quote, .cite) > :is(.admonition-title, summary)::before { + background-color: #9e9e9e; + mask-image: var(--md-admonition-icon--quote); + -webkit-mask-image: var(--md-admonition-icon--quote); + mask-repeat: no-repeat; + -webkit-mask-repeat: no-repeat; + mask-size: contain; + -webkit-mask-repeat: no-repeat; +} + +.navy :is(.admonition) { + background-color: var(--sidebar-bg); +} + +.ayu :is(.admonition), .coal :is(.admonition) { + background-color: var(--theme-hover); +} + +.rust :is(.admonition) { + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.rust .admonition-anchor-link:link, .rust .admonition-anchor-link:visited { + color: var(--sidebar-fg); +} diff --git a/documentation/operators/theme/css/chrome.css b/documentation/operators/theme/css/chrome.css new file mode 100644 index 0000000000..febd1d40a6 --- /dev/null +++ b/documentation/operators/theme/css/chrome.css @@ -0,0 +1,538 @@ +/* CSS for UI elements (a.k.a. chrome) */ + +@import 'variables.css'; + +::-webkit-scrollbar { + background: var(--bg); +} +::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} +html { + scrollbar-color: var(--scrollbar) var(--bg); +} +#searchresults a, +.content a:link, +a:visited, +a > .hljs { + color: var(--links); +} + +/* Menu Bar */ + +#menu-bar, +#menu-bar-hover-placeholder { + z-index: 101; + margin: auto calc(0px - var(--page-padding)); +} +#menu-bar { + position: relative; + display: flex; + flex-wrap: wrap; + background-color: var(--bg); + border-bottom-color: var(--bg); + border-bottom-width: 1px; + border-bottom-style: solid; +} +#menu-bar.sticky, +.js #menu-bar-hover-placeholder:hover + #menu-bar, +.js #menu-bar:hover, +.js.sidebar-visible #menu-bar { + position: -webkit-sticky; + position: sticky; + top: 0 !important; +} +#menu-bar-hover-placeholder { + position: sticky; + position: -webkit-sticky; + top: 0; + height: var(--menu-bar-height); +} +#menu-bar.bordered { + border-bottom-color: var(--table-border-color); +} +#menu-bar i, #menu-bar .icon-button { + position: relative; + padding: 0 8px; + z-index: 10; + line-height: var(--menu-bar-height); + cursor: pointer; + transition: color 0.5s; +} +@media only screen and (max-width: 420px) { + #menu-bar i, #menu-bar .icon-button { + padding: 0 5px; + } +} + +.icon-button { + border: none; + background: none; + padding: 0; + color: inherit; +} +.icon-button i { + margin: 0; +} + +.right-buttons { + margin: 0 15px; +} +.right-buttons a { + text-decoration: none; +} + +.left-buttons { + display: flex; + margin: 0 5px; +} +.no-js .left-buttons { + display: none; +} + +.menu-title { + display: inline-block; + font-weight: 200; + font-size: 2.4rem; + line-height: var(--menu-bar-height); + text-align: center; + margin: 0; + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.js .menu-title { + cursor: pointer; +} + +.menu-bar, +.menu-bar:visited, +.nav-chapters, +.nav-chapters:visited, +.mobile-nav-chapters, +.mobile-nav-chapters:visited, +.menu-bar .icon-button, +.menu-bar a i { + color: var(--icons); +} + +.menu-bar i:hover, +.menu-bar .icon-button:hover, +.nav-chapters:hover, +.mobile-nav-chapters i:hover { + color: var(--icons-hover); +} + +/* Nav Icons */ + +.nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + + position: fixed; + top: 0; + bottom: 0; + margin: 0; + max-width: auto; + min-width: auto; + + display: flex; + justify-content: center; + align-content: center; + flex-direction: column; + + transition: color 0.5s, background-color 0.5s; +} + +.nav-chapters:hover { + text-decoration: none; + background-color: var(--theme-hover); + transition: background-color 0.15s, color 0.15s; +} + +.nav-wrapper { + margin-top: 50px; + display: none; +} + +.mobile-nav-chapters { + font-size: 2.5em; + text-align: center; + text-decoration: none; + width: 90px; + border-radius: 5px; + background-color: var(--sidebar-bg); +} + +.previous { + float: left; +} + +.next { + float: right; + right: var(--page-padding); +} + +@media only screen and (max-width: 1080px) { + .nav-wide-wrapper { display: none; } + .nav-wrapper { display: block; } +} + +@media only screen and (max-width: 1380px) { + .sidebar-visible .nav-wide-wrapper { display: none; } + .sidebar-visible .nav-wrapper { display: block; } +} + +/* Inline code */ + +:not(pre) > .hljs { + display: inline; + padding: 0.1em 0.3em; + border-radius: 3px; +} + +:not(pre):not(a) > .hljs { + color: var(--inline-code-color); + overflow-x: initial; +} + +a:hover > .hljs { + text-decoration: underline; +} + +pre { + position: relative; +} +pre > .buttons { + position: absolute; + z-index: 100; + right: 0px; + top: 2px; + margin: 0px; + padding: 2px 0px; + + color: var(--sidebar-fg); + cursor: pointer; + visibility: hidden; + opacity: 0; + transition: visibility 0.1s linear, opacity 0.1s linear; +} +pre:hover > .buttons { + visibility: visible; + opacity: 1 +} +pre > .buttons :hover { + color: var(--sidebar-active); + border-color: var(--icons-hover); + background-color: var(--theme-hover); +} +pre > .buttons i { + margin-left: 8px; +} +pre > .buttons button { + cursor: inherit; + margin: 0px 5px; + padding: 3px 5px; + font-size: 14px; + + border-style: solid; + border-width: 1px; + border-radius: 4px; + border-color: var(--icons); + background-color: var(--theme-popup-bg); + transition: 100ms; + transition-property: color,border-color,background-color; + color: var(--icons); +} +@media (pointer: coarse) { + pre > .buttons button { + /* On mobile, make it easier to tap buttons. */ + padding: 0.3rem 1rem; + } +} +pre > code { + padding: 1rem; +} + +/* FIXME: ACE editors overlap their buttons because ACE does absolute + positioning within the code block which breaks padding. The only solution I + can think of is to move the padding to the outer pre tag (or insert a div + wrapper), but that would require fixing a whole bunch of CSS rules. +*/ +.hljs.ace_editor { + padding: 0rem 0rem; +} + +pre > .result { + margin-top: 10px; +} + +/* Search */ + +#searchresults a { + text-decoration: none; +} + +mark { + border-radius: 2px; + padding: 0 3px 1px 3px; + margin: 0 -3px -1px -3px; + background-color: var(--search-mark-bg); + transition: background-color 300ms linear; + cursor: pointer; +} + +mark.fade-out { + background-color: rgba(0,0,0,0) !important; + cursor: auto; +} + +.searchbar-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); +} + +#searchbar { + width: 100%; + margin: 5px auto 0px auto; + padding: 10px 16px; + transition: box-shadow 300ms ease-in-out; + border: 1px solid var(--searchbar-border-color); + border-radius: 3px; + background-color: var(--searchbar-bg); + color: var(--searchbar-fg); +} +#searchbar:focus, +#searchbar.active { + box-shadow: 0 0 3px var(--searchbar-shadow-color); +} + +.searchresults-header { + font-weight: bold; + font-size: 1em; + padding: 18px 0 0 5px; + color: var(--searchresults-header-fg); +} + +.searchresults-outer { + margin-left: auto; + margin-right: auto; + max-width: var(--content-max-width); + border-bottom: 1px dashed var(--searchresults-border-color); +} + +ul#searchresults { + list-style: none; + padding-left: 20px; +} +ul#searchresults li { + margin: 10px 0px; + padding: 2px; + border-radius: 2px; +} +ul#searchresults li.focus { + background-color: var(--searchresults-li-bg); +} +ul#searchresults span.teaser { + display: block; + clear: both; + margin: 5px 0 0 20px; + font-size: 0.8em; +} +ul#searchresults span.teaser em { + font-weight: bold; + font-style: normal; +} + +/* Sidebar */ + +.sidebar { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: var(--sidebar-width); + font-size: 1em; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; + overscroll-behavior-y: contain; + background-color: var(--sidebar-bg); + color: var(--sidebar-fg); +} +.sidebar-resizing { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} +.js:not(.sidebar-resizing) .sidebar { + transition: transform 0.3s; /* Animation: slide away */ +} +.sidebar code { + line-height: 2em; +} +.sidebar .sidebar-scrollbox { + overflow-y: auto; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + padding: 10px 10px; +} +.sidebar .sidebar-resize-handle { + position: absolute; + cursor: col-resize; + width: 0; + right: 0; + top: 0; + bottom: 0; +} +.js .sidebar .sidebar-resize-handle { + cursor: col-resize; + width: 5px; +} +.sidebar-hidden .sidebar { + transform: translateX(calc(0px - var(--sidebar-width))); +} +.sidebar::-webkit-scrollbar { + background: var(--sidebar-bg); +} +.sidebar::-webkit-scrollbar-thumb { + background: var(--scrollbar); +} + +.sidebar-visible .page-wrapper { + transform: translateX(var(--sidebar-width)); +} +@media only screen and (min-width: 620px) { + .sidebar-visible .page-wrapper { + transform: none; + margin-left: var(--sidebar-width); + } +} + +.chapter { + list-style: none outside none; + padding-left: 0; + line-height: 2em; +} + +.chapter ol { + width: 100%; +} + +.chapter li { + display: flex; + color: var(--sidebar-non-existant); +} +.chapter li a { + display: block; + padding: 0; + text-decoration: none; + color: var(--sidebar-fg); +} + +.chapter li a:hover { + color: var(--sidebar-active); +} + +.chapter li a.active { + color: var(--sidebar-active); +} + +.chapter li > a.toggle { + cursor: pointer; + display: block; + margin-left: auto; + padding: 0 10px; + user-select: none; + opacity: 0.68; +} + +.chapter li > a.toggle div { + transition: transform 0.5s; +} + +/* collapse the section */ +.chapter li:not(.expanded) + li > ol { + display: none; +} + +.chapter li.chapter-item { + line-height: 1.5em; + margin-top: 0.6em; +} + +.chapter li.expanded > a.toggle div { + transform: rotate(90deg); +} + +.spacer { + width: 100%; + height: 3px; + margin: 5px 0px; +} +.chapter .spacer { + background-color: var(--sidebar-spacer); +} + +@media (-moz-touch-enabled: 1), (pointer: coarse) { + .chapter li a { padding: 5px 0; } + .spacer { margin: 10px 0; } +} + +.section { + list-style: none outside none; + padding-left: 20px; + line-height: 1.5em; +} + +/* Theme Menu Popup */ + +.theme-popup { + position: absolute; + left: 10px; + top: var(--menu-bar-height); + z-index: 1000; + border-radius: 4px; + font-size: 0.7em; + color: var(--fg); + background: var(--theme-popup-bg); + border: 1px solid var(--theme-popup-border); + margin: 0; + padding: 0; + list-style: none; + display: none; + /* Don't let the children's background extend past the rounded corners. */ + overflow: hidden; +} +.theme-popup .default { + color: var(--icons); +} +.theme-popup .theme { + width: 100%; + border: 0; + margin: 0; + padding: 2px 20px; + line-height: 25px; + white-space: nowrap; + text-align: left; + cursor: pointer; + color: inherit; + background: inherit; + font-size: inherit; +} +.theme-popup .theme:hover { + background-color: var(--theme-hover); +} + +.theme-selected::before { + display: inline-block; + content: "✓"; + margin-left: -14px; + width: 14px; +} diff --git a/documentation/operators/theme/css/general.css b/documentation/operators/theme/css/general.css new file mode 100644 index 0000000000..a06db43965 --- /dev/null +++ b/documentation/operators/theme/css/general.css @@ -0,0 +1,203 @@ +/* Base styles and content styles */ + +@import 'variables.css'; + +:root { + /* Browser default font-size is 16px, this way 1 rem = 10px */ + font-size: 70%; +} + +html { + font-family: "Open Sans", sans-serif; + color: var(--fg); + background-color: var(--bg); + text-size-adjust: none; + -webkit-text-size-adjust: none; +} + +body { + margin: 0; + font-size: 1.5rem; + overflow-x: hidden; +} + +code { + font-family: var(--mono-font) !important; + font-size: 0.9em; +} + +/* make long words/inline code not x overflow */ +main { + overflow-wrap: break-word; +} + +/* make wide tables scroll if they overflow */ +.table-wrapper { + overflow-x: auto; +} + +/* Don't change font size in headers. */ +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + font-size: unset; +} + +.left { float: left; } +.right { float: right; } +.boring { opacity: 0.6; } +.hide-boring .boring { display: none; } +.hidden { display: none !important; } + +h2, h3 { margin-top: 2.5em; } +h4, h5 { margin-top: 2em; } + +.header + .header h3, +.header + .header h4, +.header + .header h5 { + margin-top: 1em; +} + +h1:target::before, +h2:target::before, +h3:target::before, +h4:target::before, +h5:target::before, +h6:target::before { + display: inline-block; + content: "»"; + margin-left: -30px; + width: 30px; +} + +/* This is broken on Safari as of version 14, but is fixed + in Safari Technology Preview 117 which I think will be Safari 14.2. + https://bugs.webkit.org/show_bug.cgi?id=218076 +*/ +:target { + scroll-margin-top: calc(var(--menu-bar-height) + 0.5em); +} + +.page { + outline: 0; + padding: 0 var(--page-padding); + margin-top: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */ +} +.page-wrapper { + box-sizing: border-box; +} +.js:not(.sidebar-resizing) .page-wrapper { + transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */ +} + +.content { + overflow-y: auto; + padding: 0 10px; +} +.content main { + margin-left: 10%; + margin-right: 10%; + max-width: var(--content-max-width); +} +.content p { line-height: 1.45em; } +.content ol { line-height: 1.45em; } +.content ul { line-height: 1.45em; } +.content a { text-decoration: none; } +.content a:hover { text-decoration: underline; } +.content img, .content video { max-width: 100%; } +.content .header:link, +.content .header:visited { + color: var(--fg); +} +.content .header:link, +.content .header:visited:hover { + text-decoration: none; +} + +table { + margin: 0 auto; + border-collapse: collapse; +} +table td { + padding: 3px 20px; + border: 1px var(--table-border-color) solid; +} +table thead { + background: var(--table-header-bg); +} +table thead td { + font-weight: 700; + border: none; +} +table thead th { + padding: 3px 20px; +} +table thead tr { + border: 1px var(--table-header-bg) solid; +} +/* Alternate background colors for rows */ +table tbody tr:nth-child(2n) { + background: var(--table-alternate-bg); +} + + +blockquote { + margin: 20px 0; + padding: 0 20px; + color: var(--fg); + background-color: var(--quote-bg); + border-top: .1em solid var(--quote-border); + border-bottom: .1em solid var(--quote-border); +} + +kbd { + background-color: var(--table-border-color); + border-radius: 4px; + border: solid 1px var(--theme-popup-border); + box-shadow: inset 0 -1px 0 var(--theme-hover); + display: inline-block; + font-size: var(--code-font-size); + font-family: var(--mono-font); + line-height: 10px; + padding: 4px 5px; + vertical-align: middle; +} + +:not(.footnote-definition) + .footnote-definition, +.footnote-definition + :not(.footnote-definition) { + margin-top: 2em; +} +.footnote-definition { + font-size: 0.9em; + margin: 0.5em 0; +} +.footnote-definition p { + display: inline; +} + +.tooltiptext { + position: absolute; + visibility: hidden; + color: #fff; + background-color: #333; + transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */ + left: -8px; /* Half of the width of the icon */ + top: -35px; + font-size: 0.8em; + text-align: center; + border-radius: 6px; + padding: 5px 8px; + margin: 5px; + z-index: 1000; +} +.tooltipped .tooltiptext { + visibility: visible; +} + +.chapter li.part-title { + color: var(--sidebar-fg); + margin: 5px 0px; + font-weight: bold; +} + +.result-no-output { + font-style: italic; +} diff --git a/documentation/operators/theme/css/variables.css b/documentation/operators/theme/css/variables.css new file mode 100644 index 0000000000..8dfcf92239 --- /dev/null +++ b/documentation/operators/theme/css/variables.css @@ -0,0 +1,3257 @@ + +/* Globals */ + +:root { + --sidebar-width: 300px; + --page-padding: 20px; + --content-max-width: 70%; + --menu-bar-height: 40px; + --mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace; + --code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */ + --pagetoc-width: 13%; + --pagetoc-fontsize: 14.5px; +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +@media only screen and (max-width:1439px) { + :root{ + --content-max-width: 98%; + } +} + +/* Themes */ + +.ayu { + --bg: hsl(210, 25%, 8%); + --fg: #c5c5c5; + + --sidebar-bg: #14191f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #5c6773; + --sidebar-active: #ffb454; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #0096cf; + + --inline-code-color: #ffb454; + + --theme-popup-bg: #14191f; + --theme-popup-border: #5c6773; + --theme-hover: #191f26; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(210, 25%, 13%); + --table-header-bg: hsl(210, 25%, 28%); + --table-alternate-bg: hsl(210, 25%, 11%); + + --searchbar-border-color: #848484; + --searchbar-bg: #424242; + --searchbar-fg: #fff; + --searchbar-shadow-color: #d4c89f; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #252932; + --search-mark-bg: #e3b171; +} + +.coal { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; +} + +.light { + --bg: hsl(0, 0%, 100%); + --fg: hsl(0, 0%, 0%); + + --sidebar-bg: #fafafa; + --sidebar-fg: hsl(0, 0%, 0%); + --sidebar-non-existant: #aaaaaa; + --sidebar-active: #1f1fff; + --sidebar-spacer: #f4f4f4; + + --scrollbar: #8F8F8F; + + --icons: #747474; + --icons-hover: #000000; + + --links: #1f1fff; + + --inline-code-color: #F42C4C; + + --theme-popup-bg: #fafafa; + --theme-popup-border: #cccccc; + --theme-hover: #e6e6e6; + + --quote-bg: hsl(197, 37%, 96%); + --quote-border: hsl(197, 37%, 91%); + + --table-border-color: hsl(0, 0%, 95%); + --table-header-bg: hsl(0, 0%, 80%); + --table-alternate-bg: hsl(0, 0%, 97%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #e4f2fe; + --search-mark-bg: #a2cff5; +} + +.navy { + --bg: hsl(226, 23%, 11%); + --fg: #bcbdd0; + + --sidebar-bg: #282d3f; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505274; + --sidebar-active: #2b79a2; + --sidebar-spacer: #2d334f; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #b7b9cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #161923; + --theme-popup-border: #737480; + --theme-hover: #282e40; + + --quote-bg: hsl(226, 15%, 17%); + --quote-border: hsl(226, 15%, 22%); + + --table-border-color: hsl(226, 23%, 16%); + --table-header-bg: hsl(226, 23%, 31%); + --table-alternate-bg: hsl(226, 23%, 14%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #aeaec6; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #5f5f71; + --searchresults-border-color: #5c5c68; + --searchresults-li-bg: #242430; + --search-mark-bg: #a2cff5; +} + +.rust { + --bg: hsl(60, 9%, 87%); + --fg: #262625; + + --sidebar-bg: #3b2e2a; + --sidebar-fg: #c8c9db; + --sidebar-non-existant: #505254; + --sidebar-active: #e69f67; + --sidebar-spacer: #45373a; + + --scrollbar: var(--sidebar-fg); + + --icons: #737480; + --icons-hover: #262625; + + --links: #2b79a2; + + --inline-code-color: #6e6b5e; + + --theme-popup-bg: #e1e1db; + --theme-popup-border: #b38f6b; + --theme-hover: #99908a; + + --quote-bg: hsl(60, 5%, 75%); + --quote-border: hsl(60, 5%, 70%); + + --table-border-color: hsl(60, 9%, 82%); + --table-header-bg: #b3a497; + --table-alternate-bg: hsl(60, 9%, 84%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #fafafa; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #888; + --searchresults-li-bg: #dec2a2; + --search-mark-bg: #e69f67; +} + +@media (prefers-color-scheme: dark) { + .light.no-js { + --bg: hsl(200, 7%, 8%); + --fg: #98a3ad; + + --sidebar-bg: #292c2f; + --sidebar-fg: #a1adb8; + --sidebar-non-existant: #505254; + --sidebar-active: #3473ad; + --sidebar-spacer: #393939; + + --scrollbar: var(--sidebar-fg); + + --icons: #43484d; + --icons-hover: #b3c0cc; + + --links: #2b79a2; + + --inline-code-color: #c5c8c6; + + --theme-popup-bg: #141617; + --theme-popup-border: #43484d; + --theme-hover: #1f2124; + + --quote-bg: hsl(234, 21%, 18%); + --quote-border: hsl(234, 21%, 23%); + + --table-border-color: hsl(200, 7%, 13%); + --table-header-bg: hsl(200, 7%, 28%); + --table-alternate-bg: hsl(200, 7%, 11%); + + --searchbar-border-color: #aaa; + --searchbar-bg: #b7b7b7; + --searchbar-fg: #000; + --searchbar-shadow-color: #aaa; + --searchresults-header-fg: #666; + --searchresults-border-color: #98a3ad; + --searchresults-li-bg: #2b2b2f; + --search-mark-bg: #355c7d; + } +} diff --git a/documentation/operators/theme/index.hbs b/documentation/operators/theme/index.hbs new file mode 100644 index 0000000000..06a3731f33 --- /dev/null +++ b/documentation/operators/theme/index.hbs @@ -0,0 +1,1063 @@ + + + + + + {{ title }} + {{#if is_print }} + + {{/if}} + {{#if base_url}} + + {{/if}} + + + + {{> head}} + + + + + + {{#if favicon_svg}} + + {{/if}} + {{#if favicon_png}} + + {{/if}} + + + + {{#if print_enable}} + + {{/if}} + + + + {{#if copy_fonts}} + + {{/if}} + + + + + + + + {{#each additional_css}} + + {{/each}} + + {{#if mathjax_support}} + + + {{/if}} + + + + + + + + + + + + + + + + +
+ +
+ {{> header}} + + + + {{#if search_enabled}} + + {{/if}} + + + + +
+
+ +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + {{{ content }}} +
+ + +
+
+ + + +
+ + {{#if live_reload_endpoint}} + + + {{/if}} + + {{#if google_analytics}} + + + {{/if}} + + {{#if playground_line_numbers}} + + {{/if}} + + {{#if playground_copyable}} + + {{/if}} + + {{#if playground_js}} + + + + + + {{/if}} + + {{#if search_js}} + + + + {{/if}} + + + + + + + {{#each additional_js}} + + {{/each}} + + {{#if is_print}} + {{#if mathjax_support}} + + {{else}} + + {{/if}} + {{/if}} + + + diff --git a/documentation/operators/theme/pagetoc.css b/documentation/operators/theme/pagetoc.css new file mode 100644 index 0000000000..a68e5b8e21 --- /dev/null +++ b/documentation/operators/theme/pagetoc.css @@ -0,0 +1,47 @@ +/* src: https://github.com/JorelAli/mdBook-pagetoc */ + +@media only screen and (max-width:1439px) { + .sidetoc { + display: none; + } +} + +@media only screen and (min-width:1440px) { + main { + position: relative; + } + .sidetoc { + margin-left: auto; + margin-right: auto; + /* left: calc(90% + (var(--content-min-width))/4 - 110px); */ + left: 101%; + position: absolute; + font-size: var(--pagetoc-fontsize); + } + .pagetoc { + position: fixed; + width: var(--pagetoc-width); + } + .pagetoc a { + border-left: 1px solid var(--sidebar-bg); + /* color: var(--fg); */ + /* color: var(--sidebar-fg); */ + color: var(--links); + display: block; + padding-bottom: 5px; + padding-top: 5px; + padding-left: 10px; + text-align: left; + text-decoration: none; + font-weight: normal; + background: var(--sidebar-bg); + } + .pagetoc a:hover, + .pagetoc a.active { + background: var(--sidebar-bg); + /* color: var(--sidebar-fg); */ + color: var(--sidebar-active); + font-weight: bold; + font-size: var(--pagetoc-fontsize); + } +} diff --git a/documentation/operators/theme/pagetoc.js b/documentation/operators/theme/pagetoc.js new file mode 100644 index 0000000000..b11052427e --- /dev/null +++ b/documentation/operators/theme/pagetoc.js @@ -0,0 +1,68 @@ +// src: https://github.com/JorelAli/mdBook-pagetoc + +// Un-active everything when you click it +Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el, i) { + el.addEventHandler("click", function() { + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el, i) { + el.classList.remove("active"); + }); + el.classList.add("active"); + }); +}); + +var updateFunction = function() { + + var id; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function(el, i) { + if (window.pageYOffset >= el.offsetTop) { + id = el; + } + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el, i) { + el.classList.remove("active"); + }); + + Array.prototype.forEach.call(document.getElementsByClassName("pagetoc")[0].children, function(el, i) { + if (id.href.localeCompare(el.href) == 0) { + el.classList.add("active"); + } + }); +}; + +// Populate sidebar on load +window.addEventListener('load', function() { + var pagetoc = document.getElementsByClassName("pagetoc")[0]; + var elements = document.getElementsByClassName("header"); + Array.prototype.forEach.call(elements, function(el, i) { + var link = document.createElement("a"); + + // Indent shows hierarchy + var indent = ""; + switch (el.parentElement.tagName) { + case "H2": + indent = "20px"; + break; + case "H3": + indent = "40px"; + break; + case "H4": + indent = "60px"; + break; + default: + break; + } + + link.appendChild(document.createTextNode(el.text)); + link.style.paddingLeft = indent; + link.href = el.href; + pagetoc.appendChild(link); + }); + updateFunction.call(); +}); + + + +// Handle active elements on scroll +window.addEventListener("scroll", updateFunction); From 99224310e9abbf9e8caed7eb949c680088ad8e29 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 2 Aug 2023 08:04:57 +0200 Subject: [PATCH 088/146] operators: plugins work, ready for final review --- documentation/operators/book.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 3a0a9f722b..28efe62c57 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -53,9 +53,9 @@ platform_release_version = "v1.1.22" wallet_release_version = "v1.2.5" -# [preprocessor.last-changed] -# command = "mdbook-last-changed" -# renderer = ["html"] +[preprocessor.last-changed] +command = "mdbook-last-changed" +renderer = ["html"] # used for grabbing output of binary commands for automation From 3ae803a3437be3d33a27e30f706774883b1f8e57 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Wed, 2 Aug 2023 10:40:26 +0200 Subject: [PATCH 089/146] #3674 feedback implemented --- .../docs/src/binaries/building-nym.html | 350 ------------------ .../docs/src/binaries/init-and-config.html | 290 --------------- .../docs/src/binaries/pre-built-binaries.html | 286 -------------- documentation/docs/src/introduction.md | 3 - documentation/operators/src/introduction.md | 15 +- .../operators/src/nodes/troubleshooting.md | 8 +- .../operators/src/preliminary-steps.md | 8 +- 7 files changed, 7 insertions(+), 953 deletions(-) delete mode 100644 documentation/docs/src/binaries/building-nym.html delete mode 100644 documentation/docs/src/binaries/init-and-config.html delete mode 100644 documentation/docs/src/binaries/pre-built-binaries.html diff --git a/documentation/docs/src/binaries/building-nym.html b/documentation/docs/src/binaries/building-nym.html deleted file mode 100644 index 2f73af4b4f..0000000000 --- a/documentation/docs/src/binaries/building-nym.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - Building from Source - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Building from Source

-
-

Nym runs on Mac OS X, Linux, and Windows. All nodes except the Desktop Wallet and NymConnect on Windows should be considered experimental - it works fine if you’re an app developer but isn’t recommended for running nodes.

-
-

Building Nym

-

Nym has two main codebases:

-
    -
  • the Nym platform, written in Rust. This contains all of our code except for the validators.
  • -
  • the Nym validators, written in Go.
  • -
-
-

This page details how to build the main Nym platform code. If you want to build and run a validator, go here instead.

-
-

Prerequisites

-
    -
  • Debian/Ubuntu: pkg-config, build-essential, libssl-dev, curl, jq, git
  • -
-
apt install pkg-config build-essential libssl-dev curl jq git
-
-
    -
  • Arch/Manjaro: base-devel
  • -
-
pacman -S base-devel
-
-
    -
  • Mac OS X: pkg-config , brew, openss1, protobuf, curl, git -Running the following the script installs Homebrew and the above dependencies:
  • -
-
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
-
-
    -
  • Rust & cargo >= 1.66
  • -
-

We recommend using the Rust shell script installer. Installing cargo from your package manager (e.g. apt) is not recommended as the packaged versions are usually too old.

-

If you really don’t want to use the shell script installer, the Rust installation docs contain instructions for many platforms.

-

Download and build Nym binaries

-

The following commands will compile binaries into the nym/target/release directory:

-
rustup update
-git clone https://github.com/nymtech/nym.git
-cd nym
-
-git reset --hard # in case you made any changes on your branch
-git pull # in case you've checked it out before
-
-git checkout release/v1.1.22 # checkout to the latest release branch: `develop` will most likely be incompatible with deployed public networks
-
-cargo build --release # build your binaries with **mainnet** configuration
-NETWORK=sandbox cargo build --release # build your binaries with **sandbox** configuration
-
-

Quite a bit of stuff gets built. The key working parts are:

- -

The repository also contains Typescript applications which aren’t built in this process. These can be built by following the instructions on their respective docs pages.

- -
-

You cannot build from GitHub’s .zip or .tar.gz archive files on the releases page - the Nym build scripts automatically include the current git commit hash in the built binary during compilation, so the build will fail if you use the archive code (which isn’t a Git repository). Check the code out from github using git clone instead.

-
- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/docs/src/binaries/init-and-config.html b/documentation/docs/src/binaries/init-and-config.html deleted file mode 100644 index 147c89cc2d..0000000000 --- a/documentation/docs/src/binaries/init-and-config.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - - Binary Initialisation and Configuration - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Binary Initialisation and Configuration

-

All Nym binaries must first be initialised with init before being run.

-

The init command is usually where you pass flags specifying configuration arguments such as the gateway you wish to communicate with, the ports you wish your binary to listen on, etc.

-

The init command will also create the necessary keypairs and configuration files at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/ if these files do not already exist. It will not overwrite existing keypairs if they are present.

-

You can reconfigure your binaries at any time by editing the config file located at ~/.nym/<BINARY_TYPE>/<BINARY_ID>/config/config.toml and restarting the binary process.

-

Once you have run init, you can start your binary with the run command, usually only accompanied by the id of the binary that you specified.

-

This id is never transmitted over the network, and is used to select which local config and key files to use for startup.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/docs/src/binaries/pre-built-binaries.html b/documentation/docs/src/binaries/pre-built-binaries.html deleted file mode 100644 index 3497c15d85..0000000000 --- a/documentation/docs/src/binaries/pre-built-binaries.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - - Pre-built Binaries - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Pre-built Binaries

-

The Github releases page has pre-built binaries which should work on Ubuntu 20.04 and other Debian-based systems, but at this stage cannot be guaranteed to work everywhere.

-

If the pre-built binaries don’t work or are unavailable for your system, you will need to build the platform yourself.

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/documentation/docs/src/introduction.md b/documentation/docs/src/introduction.md index a6cf38aae7..9e245497f4 100644 --- a/documentation/docs/src/introduction.md +++ b/documentation/docs/src/introduction.md @@ -4,9 +4,6 @@ This is Nym's technical documentation, containing information and setup guides a If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). -If you are looking for information on grants and beta-release Nym apps, check out the [Shipyard](https://shipyard.nymtech.net) site. - - ## Popular pages **Network Architecture:** * [Network Overview](./architecture/network-overview.md) diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index 48b5984eef..acf29f9363 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -4,9 +4,7 @@ This is Nym's operators guide, containing information and setup tutorials about If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). -If you want to go deeper into Nym architecture and various software such as different, application clients, existing applications like the desktop wallet, mixnet explorer or SDKs, visit [Nym's technical documentation](https://nymtech.net/docs/). - -If you are looking for information on grants and beta-release Nym apps, check out the [Shipyard](https://shipyard.nymtech.net) site. +If you want to dive deeper into Nym architecture and such as different clients, existing applications like the desktop wallet, explorers or SDKs, visit [Nym's technical documentation](https://nymtech.net/docs/). ## Popular pages @@ -28,14 +26,3 @@ If you are looking for information on grants and beta-release Nym apps, check ou * [Troubleshooting](./nodes/troubleshooting.md) * [FAQ](./faq.md) - diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index e5333bcfe4..f063d985e0 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -1,9 +1,3 @@ - - # Troubleshooting ## Binary Build Problems @@ -73,6 +67,8 @@ There are 2 community explorers currently, which have been created by [Nodes Gur * [Mainnet](https://mixnet.explorers.guru/) * [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) +[Here](https://github.com/cosmos/chain-registry/blob/master/nyx/chain.json#L158-L187) is a dictionary with Nyx chain registry entry regarding all explorers. + If you want more information, or if your node isn't showing up on the explorer of your choice and you want to double-check, here are some examples on how to check if the node is configured properly. #### Check from your VPS diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index 5cb76d8e19..53f5383838 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,12 +1,12 @@ # Preliminary Steps -> The Nym mixnode, gateway and network requester binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym `mixnode`, `gateway` and `network-requester` binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ## Preliminary steps There are a couple of steps that need completing before starting to set up your mixnode, gateway or a network requester: -- preparing your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) +- preparing your [desktop wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) or [CLI wallet](https://nymtech.net/docs/wallet/cli-wallet.html). - requisitioning a VPS (Virtual Private Server) ### Wallet preparation @@ -32,12 +32,12 @@ For now, see the below rough specs: - Processors: 2 cores are fine. Get the fastest CPUs you can afford. -#### For Nym Mixnode +#### For Mixnode - RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. - Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. -#### For Nym Gateway +#### For Gateway - RAM: Memory requirements depend on the amount of users your Gateway will be serving at any one time. If you're just going to be using it yourself, then minimal RAM is fine. **If you're running your Gateway as part of a Service Grant, get something with at least 4GB RAM.** - Disks: much like the amount of RAM your Gateway could use, the amount of disk space required will vary with the amount of users your Gateway is serving. **If you're running your Gateway as part of a Service Grant, get something with at least 40GB storage.** From fca384fba21cf11d4281300301f9546ae2d07eb4 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 16:31:45 +0200 Subject: [PATCH 090/146] tweaked intro page --- documentation/operators/src/introduction.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index acf29f9363..dc160825d6 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -1,19 +1,17 @@ # Introduction -This is Nym's operators guide, containing information and setup tutorials about the various pieces of Nym mixnet infrastructure nodes, such as mix node, gateway and network requester as well as Nyx chain validators. +This is Nym's Operators guide, containing information and setup guides for the various pieces of Nym mixnet infrastructure (mix node, gateway and network requester) and Nyx blockchain validators. -If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). +If you are new to Nym and want to learn about the mixnet, explore quickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/). -If you want to dive deeper into Nym architecture and such as different clients, existing applications like the desktop wallet, explorers or SDKs, visit [Nym's technical documentation](https://nymtech.net/docs/). +If you want to dive deeper into Nym's architecture, clients, nodes, and SDK examples visit the [technical docs](https://nymtech.net/docs/). ## Popular pages - - - -**Network Architecture:** -* [Network Overview](https://nymtech.net/docs/architecture/network-overview.html) -* [Mixnet Traffic Flow](https://nymtech.net/docs/architecture/traffic-flow.html) +**Binary Information** +* [Building Nym](./binaries/building-nym.md) +* [Pre-built Binaries](./binaries/pre-built-binaries.md) +* [Init & Configuration](./binaries/init-and-config.md) **Node setup and usage guides:** * [Mix nodes](./nodes/mix-node-setup.md) From 089d5e6dbb1558550762c425689785957ca2569b Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 16:43:58 +0200 Subject: [PATCH 091/146] * removed old `wallet-address` flag * 'mixnode' -> 'mix node' for consistency in non-code / non-binary references --- documentation/operators/src/faq.md | 6 +-- .../operators/src/nodes/maintenance.md | 32 ++++++------- .../operators/src/nodes/mix-node-setup.md | 18 ++++---- .../operators/src/nodes/troubleshooting.md | 46 +++++++++---------- .../operators/src/preliminary-steps.md | 12 ++--- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index bc3c210352..a42af22825 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -2,7 +2,7 @@ ## Mixnet nodes -### What determines the rewards when running a mixnode? +### What determines the rewards when running a mix node? The stake required for a mix node to achieve maximum rewards is called mix node saturation point. This is calculated from the staking supply (all circulating supply + part of unlocked tokens). The target level of staking is to have 50% of the staking supply locked in mix nodes. @@ -16,7 +16,7 @@ For more detailed calculation, read our blog post [Nym Token Economics update](h Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. - + ### What's the Sphinx packet size? @@ -32,7 +32,7 @@ Right now only mix nodes are rewarded. We're working on gateway and service paym ### Are mixnodes whitelisted? -Nope, anyone can run a mixnode. Purely reliant on the node's reputation (self stake + delegations) & routing score. +Nope, anyone can run a mix node. Purely reliant on the node's reputation (self stake + delegations) & routing score. ## Validators and tokens diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 26d5375a7d..7ffe1d6d58 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -2,7 +2,7 @@ ``` -The `nym-mixnode` binary is currently one point version ahead of the rest of the platform binaries due to a patch applied between releases. +The `nym-mix node` binary is currently one point version ahead of the rest of the platform binaries due to a patch applied between releases. ## Preliminary steps -Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your mixnode. +Make sure you do the preparation listed in the [preliminary steps page](../preliminary-steps.md) before setting up your mix node. ## Mix node setup -Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mixnode` binary, you can set up your mix node with the instructions below. +Now that you have built the [codebase](../binaries/building-nym.md), set up your [wallet](https://nymtech.net/docs/wallet/desktop-wallet.html), and have a VPS with the `nym-mix node` binary, you can set up your mix node with the instructions below. -To begin, move to `/taget/release` directory from which you run the node commands: +To begin, move to `/target/release` directory from which you run the node commands: ``` cd target/release @@ -63,10 +63,10 @@ To check available configuration options for initializing your node use: ``` ~~~ -Initalise your mixnode with the following command, replacing the value of `--id` with the moniker you wish to give your mixnode, and the `--wallet-address` with the Nym address you created earlier. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. +Initalise your mix node with the following command, replacing the value of `--id` with the moniker you wish to give your mix node. Your `--host` must be publicly routable on the internet in order to mix packets, and can be either an Ipv4 or IPv6 address. The `$(curl ifconfig.me)` command returns your IP automatically using an external service. If you enter your IP address manually, enter it **without** any port information. ``` -./nym-mixnode init --id --host $(curl ifconfig.me) --wallet-address +./nym-mixnode init --id --host $(curl ifconfig.me) ``` @@ -105,7 +105,7 @@ During the `init` process you will have the option to change the `http_api`, `ve ### Bonding your mix node ```admonish caution -From `v1.1.3`, if you unbond your mixnode that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. +From `v1.1.3`, if you unbond your mix node that means you are leaving the mixnet and you will lose all your delegations (permanently). You can join again with the same identity key, however, you will start with **no delegations**. ``` #### Bond via the Desktop wallet (recommended) @@ -183,7 +183,7 @@ Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see mo ## Node Description (optional) -In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mixnode with the following command: +In order to easily identify your node via human-readable information later on in the development of the testnet when delegated staking is implemented, you can `describe` your mix node with the following command: ``` ./nym-mixnode describe --id @@ -311,5 +311,5 @@ For more details see [Troubleshooting FAQ](../nodes/troubleshooting.md) ## Maintenance -For mixnode upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) +For mix node upgrade, firewall setup, port configuration, API endpoints, VPS suggestions, automation and more, see the [maintenance page](./maintenance.md) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index f063d985e0..d8fb566b58 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -78,7 +78,7 @@ Additional details can be obtained via various methods after you connect to your ##### Socket statistics with `ss` ``` -sudo ss -s -t | grep 1789 # if you have specified a different port in your mixnode config, change accordingly +sudo ss -s -t | grep 1789 # if you have specified a different port in your mix node config, change accordingly ``` This command should return a lot of data containing `ESTAB`. This command should work on every unix based system. @@ -90,7 +90,7 @@ This command should return a lot of data containing `ESTAB`. This command should lsof -v # install if not installed sudo apt install lsof -# run against mixnode port +# run against mix node port sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly ``` @@ -110,7 +110,7 @@ nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3: sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed" ``` -If you have created `nym-mixnode.service` file (i.e. you are running your mixnode via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: +If you have created `nym-mixnode.service` file (i.e. you are running your mix node via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: ``` 2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets! @@ -140,7 +140,7 @@ For example `./target/debug/nym-network-requester --no-banner build-info --outpu nmap -p 1789 -Pn ``` -If your mixnode is configured properly it should output something like this: +If your mix node is configured properly it should output something like this: ``` bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn @@ -164,7 +164,7 @@ You can query gateways by replacing `mixnodes` with `gateways` in the above comm #### Check with Network API -We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mixnode, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). +We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mix node, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](./maintenance.md#metrics--api-endpoints). ### Why is my node not mixing any packets? @@ -172,24 +172,24 @@ If you are still unable to see your node on the dashboard, or your node is decla - The firewall on your host machine is not configured properly. Checkout the [instructions](./maintenance.md#configure-your-firewall). - You provided incorrect information when bonding your node. -- You are running your mixnode from a VPS without IPv6 support. -- You did not use the `--announce-host` flag while running the mixnode from your local machine behind NAT. -- You did not configure your router firewall while running the mixnode from your local machine behind NAT, or you are lacking IPv6 support. -- Your mixnode is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). +- You are running your mix node from a VPS without IPv6 support. +- You did not use the `--announce-host` flag while running the mix node from your local machine behind NAT. +- You did not configure your router firewall while running the mix node from your local machine behind NAT, or you are lacking IPv6 support. +- Your mix node is not running at all, it has either exited / panicked or you closed the session without making the node persistent. Check out the [instructions](./maintenance.md#automating-your-node-with-tmux-and-systemd). ```admonish caution -Your mixnode **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! +Your mix node **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! ``` #### Incorrect bonding information -Check that you have provided the correct information when bonding your mixnode in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, un-bond and then re-bond your node! +Check that you have provided the correct information when bonding your mix node in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, un-bond and then re-bond your node! -> All delegated stake will be lost when un-bonding! However the mixnode must be operational in the first place for the delegation to have any effect. +> All delegated stake will be lost when un-bonding! However the mix node must be operational in the first place for the delegation to have any effect. #### Missing `announce-host` flag -On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mixnode host. +On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mix node host. If the difference between the two is unclear, contact the help desk of your VPS provider. @@ -222,15 +222,15 @@ bob@nym:~$ hostname -I ### Running on a local machine behind NAT with no fixed IP address -Your ISP has to be IPv6 ready if you want to run a mixnode on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. +Your ISP has to be IPv6 ready if you want to run a mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! -If all goes well and you have IPv6 available, then you will need to `init` the mixnode with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). +If all goes well and you have IPv6 available, then you will need to `init` the mix node with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. Check the your IPv4 in the [section above](./troubleshooting.md#no-ipv6-connectivity). Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support. -Here is a sample of the `init` command example to create the mixnode config. +Here is a sample of the `init` command example to create the mix node config. ``` ./nym-mixnode init --id --host 0.0.0.0 --announce-host 85.160.12.13 @@ -244,7 +244,7 @@ Make sure you check if your node is really mixing. We are aiming to improve the ### Accidentally killing your node process on exiting session -When you close your current terminal session, you need to make sure you don't kill the mixnode process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). +When you close your current terminal session, you need to make sure you don't kill the mix node process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `tmux` or `nohup`, and the more elegant solution is to run the node with `systemd`. Read the automation manual [here](./maintenance.md#automating-your-node-with-tmux-and-systemd). ### Common errors and warnings @@ -273,24 +273,24 @@ Rocket runs on port `8000` by default. Although at this stage we need Rocket to #### `failed to receive reply to our echo packet within 1.5s. Stopping the test` -This relates to the VerLoc implementation that appeared in `0.10.1`, which has a particularly high log sensitivity. This warning means that the echo packet sent to the mixnode was received, but not sent back. _This will not affect the rate of rewards or performance metrics of your mixnode in the testnet at this point._ +This relates to the VerLoc implementation that appeared in `0.10.1`, which has a particularly high log sensitivity. This warning means that the echo packet sent to the mix node was received, but not sent back. _This will not affect the rate of rewards or performance metrics of your mix node in the testnet at this point._ #### `Connection to :1789 seems to be dead` -This warning is normal at the moment, and is _nothing to do with your mixnode!_ It is simply a warning that your node is unable to connect to other peoples' mixnodes for some reason, most likely because they are offline or poorly configured. +This warning is normal at the moment, and is _nothing to do with your mix node!_ It is simply a warning that your node is unable to connect to other peoples' mixnodes for some reason, most likely because they are offline or poorly configured. ---> ### Can I use a port other than 1789 ? Yes! Here is what you will need to do: -Assuming you would like to use port `1337` for your mixnode, you need to open the new port (and close the old one): +Assuming you would like to use port `1337` for your mix node, you need to open the new port (and close the old one): ``` sudo ufw allow 1337 sudo ufw deny 1789 ``` -And then edit the mixnode's config. +And then edit the mix node's config. > If you want to change the port for an already running node, you need to stop the process before editing your config file. @@ -304,9 +304,9 @@ nano ~/.nym/mixnodes/alice-node/config/config.toml You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. -Finally, restart your node. You should see if the mixnode is using the port you have changed in the config.toml file right after you run the node. +Finally, restart your node. You should see if the mix node is using the port you have changed in the config.toml file right after you run the node. -### What is `verloc` and do I have to configure my mixnode to implement it? +### What is `verloc` and do I have to configure my mix node to implement it? `verloc` is short for _verifiable location_. Mixnodes and gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fakeable and trustworthy manner. diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index 53f5383838..d36ca76da4 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,23 +1,23 @@ # Preliminary Steps -> The Nym `mixnode`, `gateway` and `network-requester` binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym `mix node`, `gateway` and `network-requester` binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ## Preliminary steps -There are a couple of steps that need completing before starting to set up your mixnode, gateway or a network requester: +There are a couple of steps that need completing before starting to set up your mix node, gateway or a network requester: - preparing your [desktop wallet](https://nymtech.net/docs/wallet/desktop-wallet.html) or [CLI wallet](https://nymtech.net/docs/wallet/cli-wallet.html). - requisitioning a VPS (Virtual Private Server) ### Wallet preparation #### Mainnet -Before you initialise and run your mixnode, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). +Before you initialise and run your mix node, head to our [website](https://nymtech.net/download/) and download the Nym wallet for your operating system. If pre-compiled binaries for your operating system aren't available, you can build the wallet yourself with instructions [here](https://nymtech.net/docs/wallet/desktop-wallet.html). -If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mixnode is 100 `NYM`, but make sure you have a bit more to account for gas costs. +If you don't already have one, please create a Nym address using the wallet, and fund it with tokens. The minimum amount required to bond a mix node is 100 `NYM`, but make sure you have a bit more to account for gas costs. `NYM` can be purchased via Bity from the wallet itself with BTC or fiat, and is currently present on several [exchanges](https://www.coingecko.com/en/coins/nym#markets). -> Remember that you can **only** use Cosmos `NYM` tokens to bond your mixnode. You **cannot** use ERC20 representations of `NYM` to run a node. +> Remember that you can **only** use Cosmos `NYM` tokens to bond your mix node. You **cannot** use ERC20 representations of `NYM` to run a node. #### Sandbox testnet @@ -32,7 +32,7 @@ For now, see the below rough specs: - Processors: 2 cores are fine. Get the fastest CPUs you can afford. -#### For Mixnode +#### For mix node - RAM: Memory requirements are very low - typically a mix node may use only a few hundred MB of RAM. - Disks: The mixnodes require no disk space beyond a few bytes for the configuration files. From f17d2cec0dab9f4afdd3713cf734d69d1f044625 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 16:46:05 +0200 Subject: [PATCH 092/146] typo fix --- documentation/operators/src/nodes/gateway-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/gateway-setup.md b/documentation/operators/src/nodes/gateway-setup.md index 026e7afde0..f1cb589756 100644 --- a/documentation/operators/src/nodes/gateway-setup.md +++ b/documentation/operators/src/nodes/gateway-setup.md @@ -17,7 +17,7 @@ Make sure you do the preparation listed in the [preliminary steps page](../preli ## Gateway setup Now that you have built the codebase, set up your wallet, and have a VPS with the `nym-gateway` binary, you can set up your gateway with the instructions below. -To begin, move to `/taget/release` directory from which you run the node commands: +To begin, move to `/target/release` directory from which you run the node commands: ``` cd target/release From 1f226682f475df40d1ee7e4fd7837e46c5c3f384 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 19:28:13 +0200 Subject: [PATCH 093/146] added custom 404 + updated platform version --- documentation/docs/book.toml | 4 ++-- documentation/docs/src/not-found.md | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 documentation/docs/src/not-found.md diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index 996a7ec4e4..7dfd751b15 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -49,7 +49,7 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` [preprocessor.variables.variables] minimum_rust_version = "1.66" # vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.25" +platform_release_version = "v1.1.26" wallet_release_version = "v1.2.7" [preprocessor.last-changed] @@ -92,7 +92,7 @@ git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" # site-url = "/docs/" # cname = "nymtech.net" -# input-404 = "not-found.md" # todo make custom 404 page +input-404 = "not-found.md" [output.html.fold] enable = true # whether or not to enable section folding diff --git a/documentation/docs/src/not-found.md b/documentation/docs/src/not-found.md new file mode 100644 index 0000000000..3d203a9bb8 --- /dev/null +++ b/documentation/docs/src/not-found.md @@ -0,0 +1,11 @@ +# Page Not Found + +You seem to have followed a link to a page that no longer exists. Our documentation is changing and growing over time, so this page has most likely been moved somewhere else. + +For node setup guides, see the [Operators Guides book](https://nymtech.net/operators). + +For developer tutorials, app guides, and demo and community apps, see the [Developer Portal](https://nymtech.net/developers). + +If you are looking for information on network architecture traffic flow, clients, the SDKs, or interacting with the Nyx blockchain, check the sitemap on the left hand side of the screen. + +If you still can't find what you're looking for get in touch with us via [Matrix](TODO). \ No newline at end of file From 6d5ff1146bf6563fc881ae724f0c6a8076923cb8 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 19:28:37 +0200 Subject: [PATCH 094/146] * deleted old setup guides * added new info on operator guides * adding stubs for in-depth node pages --- documentation/docs/src/SUMMARY.md | 13 +- documentation/docs/src/nodes/gateway.md | 1 + documentation/docs/src/nodes/mixnode.md | 17 + .../docs/src/nodes/network-requester.md | 1 + documentation/docs/src/nodes/overview.md | 9 + documentation/docs/src/nodes/setup-guides.md | 8 - .../docs/src/nodes/troubleshooting.md | 368 ---------- .../docs/src/nodes/validator-setup.md | 669 ------------------ documentation/docs/src/nodes/validator.md | 12 + 9 files changed, 46 insertions(+), 1052 deletions(-) create mode 100644 documentation/docs/src/nodes/gateway.md create mode 100644 documentation/docs/src/nodes/mixnode.md create mode 100644 documentation/docs/src/nodes/network-requester.md create mode 100644 documentation/docs/src/nodes/overview.md delete mode 100644 documentation/docs/src/nodes/setup-guides.md delete mode 100644 documentation/docs/src/nodes/troubleshooting.md delete mode 100644 documentation/docs/src/nodes/validator-setup.md create mode 100644 documentation/docs/src/nodes/validator.md diff --git a/documentation/docs/src/SUMMARY.md b/documentation/docs/src/SUMMARY.md index 8d9c174f5a..c9fc9c6d1d 100644 --- a/documentation/docs/src/SUMMARY.md +++ b/documentation/docs/src/SUMMARY.md @@ -14,12 +14,11 @@ # Nodes -- [Node Setup Guides](nodes/setup-guides.md) - - [Mix Node](nodes/mix-node-setup.md) - - [Gateway](nodes/gateway-setup.md) - - [Network Requester](nodes/network-requester-setup.md) - - [Validator](nodes/validator-setup.md) -- [Troubleshooting](nodes/troubleshooting.md) +- [Node Types (Previously Setup Guides)](nodes/overview.md) + - [Mix Node](nodes/mixnode.md) + - [Gateway](nodes/gateway.md) + - [Network Requester](nodes/network-requester.md) + - [Validator](nodes/validator.md) # Clients - [Clients Overview](clients/overview.md) @@ -40,7 +39,7 @@ - [Mixnet Explorer](explorers/mixnet-explorer.md) # Nyx Blockchain - +- [Interacting with Nyx Chain and Smart Contracts](nyx/interacting-with-chain.md) - [Smart Contracts](nyx/smart-contracts.md) - [Mixnet Contract](nyx/mixnet-contract.md) - [Vesting Contract](nyx/vesting-contract.md) diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md new file mode 100644 index 0000000000..f4ee68e242 --- /dev/null +++ b/documentation/docs/src/nodes/gateway.md @@ -0,0 +1 @@ +# Gateway diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md new file mode 100644 index 0000000000..159251ad3e --- /dev/null +++ b/documentation/docs/src/nodes/mixnode.md @@ -0,0 +1,17 @@ +# Mix Node + +> The mix node setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). + +Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing' or performing the 'poisson mix'. + +Mix nodes perform one task: receiving packets, decrypting their outer 'layer', and holding them for a variable amount of time before passing them to their next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were recieved. + +The aim of this mixing is to protect against timing-based deanonymisation attempts by a global adversary able to monitor the entire network with a 'God's Eye View'. + +## (Coming soon) Mixing: a Step-by-Step Breakdown + +## Further reading +TODO +*
+* +* diff --git a/documentation/docs/src/nodes/network-requester.md b/documentation/docs/src/nodes/network-requester.md new file mode 100644 index 0000000000..797dfd7795 --- /dev/null +++ b/documentation/docs/src/nodes/network-requester.md @@ -0,0 +1 @@ +# Network Requester diff --git a/documentation/docs/src/nodes/overview.md b/documentation/docs/src/nodes/overview.md new file mode 100644 index 0000000000..497a347365 --- /dev/null +++ b/documentation/docs/src/nodes/overview.md @@ -0,0 +1,9 @@ +# Node Types + +> This section was previously the node setup guides. These have been migrated to their own [**Operator Guides**](https://nymtech.net/operators) book. +> +> For setup and maintenance guides, go to the Operators book linked above. +> +> This section is a little spartan for the moment, but we will be adding detailed information about how exactly each node functions, as well as references to any literature and technical specs in the near future. + +This section contains information on the different node types of the mixnet and blockchain. \ No newline at end of file diff --git a/documentation/docs/src/nodes/setup-guides.md b/documentation/docs/src/nodes/setup-guides.md deleted file mode 100644 index 02a23ebff6..0000000000 --- a/documentation/docs/src/nodes/setup-guides.md +++ /dev/null @@ -1,8 +0,0 @@ -# Node Setup Guides - -This section contains setup guides for the following node types: -* [Mix node](./mix-node-setup.md) -* [Gateway](./gateway-setup.md) -* [Network Requester](./network-requester-setup.md) -* [Validator](./validator-setup.md) - diff --git a/documentation/docs/src/nodes/troubleshooting.md b/documentation/docs/src/nodes/troubleshooting.md deleted file mode 100644 index e832edbc39..0000000000 --- a/documentation/docs/src/nodes/troubleshooting.md +++ /dev/null @@ -1,368 +0,0 @@ -# Troubleshooting - - -## Binary Build Problems - -### I am trying to build from the GitHub archive files and the build fails - -GitHub automatically includes .zip and tar.gz files of the Nym repository in its release. You cannot extract these and build - you'll see something like this: - -``` - process didn't exit successfully: `/build/nym/src/nym-0.12.1/target/release/build/nym-socks5-client-c1d0f76a8c7d7e9a/build-script-build` (exit status: 101) - --- stderr - thread 'main' panicked at 'failed to extract build metadata: could not find repository from '/build/nym/src/nym-0.12.1/clients/socks5'; class=Repository (6); code=NotFound (-3)', clients/socks5/build.rs:7:31 - note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -warning: build failed, waiting for other jobs to finish... -error: build failed -``` - -Why does this happen? - -We have scripts which automatically include the Git commit hash and Git tag in the binary for easier debugging later. If you download a .zip and try building from that, it's not a Git repository and build will fail as above. - -## General Node Config - -### Where can I find my private and public keys and config? - -All config and keys files are stored in a directory named after your `id` which you chose during the `init` process, and can be found at the following PATH: `$HOME/.nym//` where `$HOME` is a home directory of the user (your current user in this case) that launched the node or client. - -The directory structure for each node will be roughly as follows: - -``` -bob@nym:~$ tree /home/nym/.nym/mixnodes/ -/home/nym/.nym/mixnodes/ -|-- nym010 -| |-- config -| | `-- config.toml -| `-- data -| |-- private_identity.pem -| |-- private_sphinx.pem -| |-- public_identity.pem -| `-- public_sphinx.pem -``` - -> If you `cat` the `public_sphinx.pem key`, the output will be different from the public key you will see on Nym [dashboard](https://sandbox-explorer.nymtech.net/). The reason for this is that `.pem` files are encoded in **base64**, however on the web they are in **base58**. Don't be confused if your keys look different. They are the same keys, just with different encoding :) - - -## Mix Nodes - -### How can I tell my node is up and running and mixing traffic? - -First of all check the 'Mixnodes' section of either the Nym Network Explorers: -* [Mainnet](https://explorer.nymtech.net/overview) -* [Sandbox testnet](https://sandbox-explorer.nymtech.net/) - -Enter your **identity key** to find your node. Check the contents of the 'mixnode stats' and 'uptime story' sections. - -There are 2 community explorers currently, which have been created by [Nodes Guru](https://nodes.guru): -* [Mainnet](https://mixnet.explorers.guru/) -* [Sandbox testnet](https://sandbox.mixnet.explorers.guru/) - -If you want more information, or if your node isn't showing up on the explorer of your choice and you want to double-check, here are some examples on how to check if the node is configured properly. - -#### Check from your VPS - -Additional details can be obtained via various methods after you connect to your VPS: - -##### Socket statistics with `ss` - -``` -sudo ss -s -t | grep 1789 # if you have specified a different port in your mixnode config, change accordingly -``` - -This command should return a lot of data containing `ESTAB`. This command should work on every unix based system. - -##### List open files and reliant processes with `lsof` - -``` -# check if lsof is installed: -lsof -v -# install if not installed -sudo apt install lsof -# run against mixnode port -sudo lsof -i TCP:1789 # if you have specified a different port in your mixnode config, change accordingly -``` - -This command should return something like this: - -``` -nym-mixno 103349 root 53u IPv6 1333229972 0t0 TCP [2a03:b0c0:3:d0::ff3:f001]:57844->[2a01:4f9:c011:38ae::5]:1789 (ESTABLISHED) -nym-mixno 103349 root 54u IPv4 1333229973 0t0 TCP nym:57104->194.5.78.73:1789 (ESTABLISHED) -nym-mixno 103349 root 55u IPv4 1333229974 0t0 TCP nym:48130->static.236.109.119.168.clients.your-server.de:1789 (ESTABLISHED) -nym-mixno 103349 root 56u IPv4 1333229975 0t0 TCP nym:52548->vmi572614.contaboserver.net:1789 (ESTABLISHED) -nym-mixno 103349 root 57u IPv6 1333229976 0t0 TCP [2a03:b0c0:3:d0::ff3:f001]:43244->[2600:1f18:1031:2401:c04b:2f25:ca79:fef3]:1789 (ESTABLISHED) -``` - -##### Query `systemd` journal with `journalctl` - -``` -sudo journalctl -u nym-mixnode -o cat | grep "Since startup mixed" -``` - -If you have created `nym-mixnode.service` file (i.e. you are running your mixnode via `systemd`) then this command shows you how many packets have you mixed so far, and should return a list of messages like this: - -``` -2021-05-18T12:35:24.057Z INFO nym_mixnode::node::metrics > Since startup mixed 233639 packets! -2021-05-18T12:38:02.178Z INFO nym_mixnode::node::metrics > Since startup mixed 233739 packets! -2021-05-18T12:40:32.344Z INFO nym_mixnode::node::metrics > Since startup mixed 233837 packets! -2021-05-18T12:46:08.549Z INFO nym_mixnode::node::metrics > Since startup mixed 234081 packets! -2021-05-18T12:56:57.129Z INFO nym_mixnode::node::metrics > Since startup mixed 234491 packets! -``` - -You can add ` | tail` to the end of the command to watch for new entries in real time if needed. - -#### Check from your local machine - -##### Scan ports with `nmap`: - -``` -nmap -p 1789 -Pn -``` - -If your mixnode is configured properly it should output something like this: - -``` -bob@desktop:~$ nmap -p 1789 95.296.134.220 -Pn - -Host is up (0.053s latency). - -PORT STATE SERVICE -1789/tcp open hello -``` - -##### Query online nodes: - -``` -curl --location --request GET 'https://validator.nymtech.net/api/v1/mixnodes/' -``` - -Will return a list all nodes currently online. - -You can query gateways by replacing `mixnodes` with `gateways` in the above command, and can query for the mixnodes and gatways on the Sandbox testnet by replacing `validator` with `sandbox-validator`. - - -#### Check with Network API - -We currently have an API set up returning our metrics tests of the network. There are two endpoints to ping for information about your mixnode, `report` and `history`. Find more information about this in the [Mixnodes metrics documentation](../nodes/mix-node-setup.md#metrics--api-endpoints). - -### Why is my node not mixing any packets? - -If you are still unable to see your node on the dashboard, or your node is declaring it has not mixed any packets, there are several potential issues: - -- The firewall on your host machine is not configured properly. -- You provided incorrect information when bonding your node. -- You are running your mixnode from a VPS without IPv6 support. -- You did not use the `--announce-host` flag while running the mixnode from your local machine behind NAT. -- You did not configure your router firewall while running the mixnode from your local machine behind NAT, or you are lacking IPv6 support. -- Your mixnode is not running at all, it has either exited / panicked or you closed the session without making the node persistent. - -```admonish caution -Your mixnode **must speak both IPv4 and IPv6** in order to cooperate with other nodes and route traffic. This is a common reason behind many errors we are seeing among node operators, so check with your provider that your VPS is able to do this! -``` - -#### Incorrectly configured firewall - -The most common reason your mixnode might not be mixing packets is due to a poorly configured firewall. The following commands will allow you to set up a firewall using `ufw`. - -``` -# check if you have ufw installed -ufw version -# if it is not installed, install with -sudo apt install ufw -y -# enable ufw -sudo ufw enable -# check the status of the firewall -sudo ufw status -``` - -Finally open your mixnode's p2p port, as well as ports for ssh, http, and https connections, and ports `8000` and `1790` for verloc and measurement pings: - -``` -sudo ufw allow 1789,1790,8000,22,80,443/tcp -# check the status of the firewall -sudo ufw status -``` - -#### Incorrect bonding information - -Check that you have provided the correct information when bonding your mixnode in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, unbond and then rebond your node! - -#### Missing `announce-host` flag - -On certain cloud providers such as AWS and Google Cloud, you need to do some additional configuration of your firewall and use `--host` with your **local ip** and `--announce-host` with the **public ip** of your mixnode host. - -#### No IPv6 connectivity - -Make sure that your VPS has IPv6 connectivity available with whatever provider you are using. - -To get all ip addresses of your host, try following commands: - -``` -hostname -i -``` - -Will return your **local ip** address. - -``` -hostname -I -``` - -Will return all of the ip addresses of your host. This output should look something like this: - -``` -bob@nym:~$ hostname -I -88.36.11.23 172.18.0.1 2a01:28:ca:102::1:641 -``` - -- The first **ipv4** is the public ip you need to use for the `--announce-host` flag. -- The second **ipv4** is the local ip you need to use for the `--host` flag. -- The 3rd output should confirm if your machine has ipv6 available. - -### Running on a local machine behind NAT with no fixed IP address - -Your ISP has to be IPv6 ready if you want to run a mixnode on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. - -Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! - -If all goes well and you have IPv6 available, then you will need to `init` the mixnode with an extra flag, `--announce-host`. You will also need to edit your `config.toml` file each time your IPv4 address changes, that could be a few days or a few weeks. - -Additional configuration on your router might also be needed to allow traffic in and out to port 1789 and IPv6 support. - -Here is a sample of the `init` command to create the mixnode config. - -``` -./target/release/nym-mixnode init --id nym-nat --host 0.0.0.0 --announce-host 85.160.12.13 --layer 3 -``` - -- `--host 0.0.0.0` should work everytime even if your local machine IPv4 address changes. For example on Monday your router gives your machine an address `192.168.0.13` and on Wednesday, the DHCP lease will end and you will be asigned `192.168.0.14`. Using `0.0.0.0` should avoid this without having to set any static ip in your router`s configuration. - -- you can get your current IPv4 address by either using `curl ipinfo.io` if you're on MacOS or Linux or visiting [whatsmyip site](https://www.whatsmyip.org/). Simply copy it and use it as `--anounce-host` address. - -Make sure you check if your node is really mixing. You will need a bit of luck to set this up from your home behind NAT. - -### Accidentally killing your node process on exiting session - -When you close your current terminal session, you need to make sure you don't kill the mixnode process! There are multiple ways on how to make it persistent even after exiting your ssh session, the easiest solution is to use `nohup`, and the more elegant solution is to run the node with `systemd`. - -### Running your mixnode as a background process with `nohup` - -`nohup` is a command with which your terminal is told to ignore the `HUP` or 'hangup' signal. This will stop the mixnode process ending if you kill your session. - -``` -nohup ./nym-mixnode run --id NYM # where `--id NYM` is the id you set during the `init` command. -``` - -### Running your mixnode as a background process with `systemd` - -The most reliable and elegant solution is to create a `systemd.service` file and run the nym-mixnode with `systemctl` command. - -Create a file with `nano` at `/etc/systemd/system/nym-mixnode.service` containing the following: - -```ini -[Unit] -Description=nym mixnode service -After=network.target - -[Service] -Type=simple -User=nym # change as appropriate -LimitNOFILE=65536 -ExecStart=/home/nym/nym-mixnode run --id nym # change as appropriate -KillSignal=SIGINT -Restart=on-failure -RestartSec=30 -Restart=on-abort -[Install] -WantedBy=multi-user.target -``` - -``` -# enable the service -sudo systemctl enable nym-mixnode -# start the service -sudo systemctl start nym-mixnode -# check if the service is running properly and mixnode is mixing -sudo systemctl status nym-mixnode -``` - -Now your node should be mixing all the time, and restart if you reboot your server! - -Anytime you change your `systemd` service file you need to `sudo systemctl daemon-reload` in order to restart the service. - -### Network configuration seems fine but log still claims `Since startup mixed 0 packets!` - -This behavior is most likely caused by a mismatch between your node configuration and the bonding information. Unbond and then rebond your node. - -Also make sure to enter all the information in the web wallet exactly as it appears in the log when you start the mixnode process. In particular, the `host` field must contain the _port_ on which your mixnode will listen: - -- correct host: `34.12.3.43:1789` -- incorrect host:`34.12.3.43` - -### Common errors and warnings - -Most of the `ERROR` and `WARN` messages in your node logs are benign - as long as your node outputs `since startup mixed X packets!` in your logs (and this number increases over time), your node is mixing packets. If you want to be sure, check the Nym [dashboard](https://sandbox-explorer.nymtech.net/) or see other ways on how to check if your node is mixing properly as outlined in the section **How can I tell my node is up and running and mixing traffic?** above. - -More specific errors and warnings are covered below. - -#### `tokio runtime worker` error - -If you are running into issues with an error including the following: - -``` -thread 'tokio-runtime-worker' panicked at 'Failed to create TCP listener: Os { code: 99, kind: AddrNotAvailable, message: "Cannot assign requested address" }' -``` - -Then you need to `--announce-host ` and ``--host ` on startup. This issue arises because of your use of a provider like AWS or Google Cloud, and the fact that your VPS' available bind address is not the same as the public IP address (see [Virtual IPs and hosting via Google and AWS](../nodes/mix-node-setup.md#virtual-ips-and-hosting-via-google--aws) for more information on this issue). - -#### `rocket::launch` warnings -These warnings are not an issue, please ignore them. Rocket is a web framework for rust which we are using to provide mixnodes with `/verloc` and `/description` http APIs. - -Find more information about this in the [Mixnodes metrics documentation](../nodes/mix-node-setup.md#metrics--api-endpoints). - -Rocket runs on port `8000` by default. Although at this stage of the testnet we need Rocket to be reachable via this port, in the future customization of the particular port it uses will be possible. - -#### `failed to receive reply to our echo packet within 1.5s. Stopping the test` - -This relates to the VerLoc implementation that appeared in `0.10.1`, which has a particularly high log sensitivity. This warning means that the echo packet sent to the mixnode was received, but not sent back. _This will not affect the rate of rewards or performance metrics of your mixnode in the testnet at this point._ - -#### `Connection to :1789 seems to be dead` - -This warning is normal at the moment, and is _nothing to do with your mixnode!_ It is simply a warning that your node is unable to connect to other peoples' mixnodes for some reason, most likely because they are offline or poorly configured. - -### Can I use a port other than 1789 ? - -Yes! Here is what you will need to do: - -Assuming you would like to use port `1337` for your mixnode, you need to open the new port (and close the old one): - -``` -sudo ufw allow 1337 -sudo ufw deny 1789 -``` - -And then edit the mixnode's config. - -> If you want to change the port for an already running node, you need to stop the process before editing your config file. - -Assuming your node name is `nym`, the config file is located at `~/.nym/mixnodes/nym/config/config.toml`. - -``` -nano ~/.nym/mixnodes/nym/config/config.toml -``` - -You will need to edit two parts of the file. `announce_address` and `listening_address` in the config.toml file. Simply replace `:1789` (the default port) with `:1337` (your new port) after your IP address. - -Finally, restart your node. You should see if the mixnode is using the port you have changed in the config.toml file right after you run the node. - -### What is `verloc` and do I have to configure my mixnode to implement it? - -`verloc` is short for _verifiable location_. Mixnodes and gateways now measure speed-of-light distances to each other, in an attempt to verify how far apart they are. In later releases, this will allow us to algorithmically verify node locations in a non-fakeable and trustworthy manner. - -You don't have to do any additional configuration for your node to implement this, it is a passive process that runs in the background of the mixnet from version `0.10.1` onwards. - - -### Where can I get more help? - -The fastest way to reach one of us or get a help from the community, visit our [Telegram help chat](https://t.me/nymchan_help_chat) or head to our [Discord](https://Discord.gg/nym) - -For more tech heavy questions join our Keybase channel. Get Keybase [here](https://keybase.io/), then click Teams -> Join a team. Type nymtech.friends into the team name and hit continue. For general chat, hang out in the #general channel. diff --git a/documentation/docs/src/nodes/validator-setup.md b/documentation/docs/src/nodes/validator-setup.md deleted file mode 100644 index 053a19253d..0000000000 --- a/documentation/docs/src/nodes/validator-setup.md +++ /dev/null @@ -1,669 +0,0 @@ -# Validators - -The validator is built using [Cosmos SDK](https://cosmos.network) and [Tendermint](https://tendermint.com), with a [CosmWasm](https://cosmwasm.com) smart contract controlling the directory service, node bonding, and delegated mixnet staking. - -## Building your validator -### Prerequisites -#### `git`, `gcc`, `jq` -* Debian-based systems: -``` -apt install git build-essential jq - -# optional additional manual pages can be installed with: -apt-get install manpages-dev -``` - -* Arch-based systems: -Install `git`, `gcc` and `jq` with the following: -``` -pacman -S git gcc jq -``` - -#### `Go` -`Go` can be installed via the following commands (taken from the [Agoric SDK docs](https://github.com/Agoric/agoric-sdk/wiki/Validator-Guide-for-Incentivized-Testnet#install-go)): - -``` -# First remove any existing old Go installation -sudo rm -rf /usr/local/go - -# Install correct Go version -curl https://dl.google.com/go/go1.20.4.linux-amd64.tar.gz | sudo tar -C/usr/local -zxvf - - -# Update environment variables to include go -cat <<'EOF' >>$HOME/.profile -export GOROOT=/usr/local/go -export GOPATH=$HOME/go -export GO111MODULE=on -export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin -EOF -source $HOME/.profile -``` - -Verify `Go` is installed with: - -``` -go version -# Should return something like: -go version go1.20.4 linux/amd64 -``` - -### Download a precompiled validator binary -You can find pre-compiled binaries for Ubuntu `22.04` and `20.04` [here](https://github.com/nymtech/nyxd/releases). - -```admonish caution title="" -There are seperate releases for Mainnet and the Sandbox testnet - make sure to download the correct binary to avoid `bech32Prefix` mismatches. -``` - -### Manually compiling your validator binary -The codebase for the Nyx validators can be found [here](https://github.com/nymtech/nyxd). - -The validator binary can be compiled by running the following commands: -``` -git clone https://github.com/nymtech/nyxd.git -cd nyxd -git checkout release/ - -# Mainnet -make build - -# Sandbox testnet -BECH32_PREFIX=nymt make build -``` - -At this point, you will have a copy of the `nyxd` binary in your `build/` directory. Test that it's compiled properly by running: - -``` -./build/nyxd -``` - -You should see help text print out. - -### Linking `nyxd` to `libwasmvm.so` - -`libwasmvm.so` is the wasm virtual machine which is needed to execute smart contracts in `v0.26.1`. This file is renamed in `libwasmvm.x86_64.so` in `v0.31.1`. - -If you downloaded your `nyxd` binary from Github, you will have seen this file when un-`tar`-ing the `.tar.gz` file from the releases page. - -If you are seeing an error concerning this file when trying to run `nyxd`, then you need to move the `libwasmvm.so` file to correct location. - -Simply `cp` or `mv` that file to `/lib/x86_64-linux-gnu/` and re-run `nyxd`. - -### Adding `nyxd` to your `$PATH` -You'll need to set `LD_LIBRARY_PATH` in your user's `~/.bashrc` file, and add that to our path. Replace `/home/youruser/path/to/nym/binaries` in the command below to the locations of `nyxd` and `libwasmvm.so` and run it. If you have compiled these on the server, they will be in the `build/` folder: - -``` -NYX_BINARIES=/home/youruser/path/to/validator/binary - -# if you are using another shell like zsh replace '.bashrc' with the relevant config file -echo 'export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:'NYX_BINARIES >> ~/.bashrc -echo 'export PATH=$PATH:'${NYX_BINARIES} >> ~/.bashrc -source ~/.bashrc -``` - -Test everything worked: - -``` -nyxd -``` - -This should return the regular help text. - -## Initialising your validator -### Prerequisites: - -- FQDN Domain name -- IPv4 and IPv6 connectivity - -Choose a name for your validator and use it in place of `` in the following command: - -``` -# Mainnet -nyxd init --chain-id=nyx - -# Sandbox testnet -nyxd init --chain-id=sandbox -``` - -```admonish caution title="" -`init` generates `priv_validator_key.json` and `node_key.json`. - -If you have already set up a validator on a network, **make sure to back up the key located at** -`~/.nyxd/config/priv_validator_key.json`. - -If you don't save the validator key, then it can't sign blocks and will be jailed all the time, and -there is no way to deterministically (re)generate this key. -``` - -At this point, you have a new validator, with its own genesis file located at `$HOME/.nyxd/config/genesis.json`. You will need to replace the contents of that file that with either the Nyx Mainnet or Sandbox Testnet genesis file. - -You can use the following command to download them for the correct network: - -``` -# Mainnet -wget -O $HOME/.nyxd/config/genesis.json https://nymtech.net/genesis/genesis.json - -# Sandbox testnet -wget -O $HOME/.nyxd/config/genesis.json https://sandbox-validator1.nymtech.net/snapshots/genesis.json -``` - -### `config.toml` configuration - -Edit the following config options in `$HOME/.nyxd/config/config.toml` to match the information below for your network: - -``` -# Mainnet -persistent_peers = "ee03a6777fb76a2efd0106c3769daaa064a3fcb5@51.79.21.187:26656" -create_empty_blocks = false -laddr = "tcp://0.0.0.0:26656" -``` - -``` -# Sandbox testnet -cors_allowed_origins = ["*"] -persistent_peers = "8421c0a3d90d490e27e8061f2abcb1276c8358b6@sandbox-validator1.nymtech.net:26666" -create_empty_blocks = false -laddr = "tcp://0.0.0.0:26656" -``` - -These affect the following: -* `persistent_peers = "@.nymtech.net:26666"` allows your validator to start pulling blocks from other validators. **The main sandbox validator listens on `26666` instead of the default `26656` for debugging**. It is recommended you do not change your port from `26656`. -* `create_empty_blocks = false` will save space -* `laddr = "tcp://0.0.0.0:26656"` is in your p2p configuration options - -Optionally, if you want to enable [Prometheus](https://prometheus.io/) metrics then the following must also match in the `config.toml`: - -- `prometheus = true` -- `prometheus_listen_addr = ":26660"` - -> Remember to enable metrics in the 'Configuring Prometheus metrics' section below as well. - -And if you wish to add a human-readable moniker to your node: - -- `moniker = "yourname"` - -Finally, if you plan on using [Cockpit](https://cockpit-project.org/documentation.html) on your server, change the `grpc` port from `9090` as this is the port used by Cockpit. - -### `app.toml` configuration -In the file `$HOME/nyxd/config/app.toml`, set the following values: - -``` -# Mainnet -minimum-gas-prices = "0.025unym,0.025unyx" -enable = true in the `[api]` section to get the API server running -``` -``` -# Sandbox Testnet -minimum-gas-prices = "0.025unymt,0.025unyxt" -enable = true` in the `[api]` section to get the API server running -``` - -### Setting up your validator's admin user -You'll need an admin account to be in charge of your validator. Set that up with: - -``` -nyxd keys add nyxd-admin -``` - -This will add keys for your administrator account to your system's keychain and log your name, address, public key, and mnemonic. As the instructions say, remember to **write down your mnemonic**. - -You can get the admin account's address with: - -``` -nyxd keys show nyxd-admin -a -``` - -Type in your keychain **password**, not the mnemonic, when asked. - -## Starting your validator - -```admonish caution title="" -If you are running a Sandbox testnet validator, please skip the `validate-genesis` command: it will fail due to the size of the genesis file as this is a fork of an existing chain state. -``` - -Everything should now be ready to go. You've got the validator set up, all changes made in `config.toml` and `app.toml`, the Nym genesis file copied into place (replacing the initial auto-generated one). Now let's validate the whole setup: - -``` -nyxd validate-genesis -``` - -If this check passes, you should receive the following output: - -``` -File at /path/to/genesis.json is a valid genesis file -``` - -> If this test did not pass, check that you have replaced the contents of `/path/to/.nymd/config/genesis.json` with that of the correct genesis file. - -Before starting the validator, we will need to open the firewall ports: - -``` -# if ufw is not already installed: -sudo apt install ufw -sudo ufw enable -sudo ufw allow 1317,26656,26660,22,80,443/tcp -# to check everything worked -sudo ufw status -``` - -Ports `22`, `80`, and `443` are for ssh, http, and https connections respectively. The rest of the ports are documented [here](https://docs.cosmos.network/v0.42/core/grpc_rest.html). - -For more information about your validator's port configuration, check the [validator port reference table](#validator-port-reference) below. - -> If you are planning to use [Cockpit](https://cockpit-project.org/) on your validator server then you will have defined a different `grpc` port in your `config.toml` above: remember to open this port as well. - -Start the validator: - -``` -nyxd start -``` - -Once your validator starts, it will start requesting blocks from other validators. This may take several hours. Once it's up to date, you can issue a request to join the validator set with the command below. - -### Syncing from a snapshot -If you wish to sync from a snapshot on **mainnet** use Polkachu's [mainnet](https://polkachu.com/networks/nym) resources. - -If you wish to sync from a snapshot on **Sandbox testnet** use the below commands, which are a modified version of Polkachu's excellent resources. These commands assume you are running an OS with `apt` as the package manager: - -``` -# install lz4 if necessary -sudo apt install snapd -y -sudo snap install lz4 - -# download the snapshot -wget -O nyxd-sandbox-snapshot-data.tar.lz4 https://sandbox-validator1.nymtech.net/snapshots/nyxd-sandbox-snapshot-data.tar.lz4 - -# reset your validator state -nyxd tendermint unsafe-reset-all - -# unpack the snapshot -lz4 -c -d nyxd-sandbox-snapshot-data.tar.lz4 | tar -x -C $HOME/.nyxd -``` - -You can then restart `nyxd` - it should start syncing from a block > 2000000. - -### Joining Consensus -```admonish caution title="" -When joining consensus, make sure that you do not disrupt (or worse - halt) the network by coming in with a disproportionately large amount of staked tokens. - -Please initially stake a small amount of tokens compared to existing validators, then delegate to yourself in tranches over time. -``` - -Once your validator has synced and you have received tokens, you can join consensus and produce blocks. - -``` -# Mainnet -nyxd tx staking create-validator - --amount=10000000unyx - --fees=0unyx - --pubkey=$(/home/youruser/path/to/nyxd/binaries/nyxd tendermint show-validator) - --moniker="whatever you called your validator" - --chain-id=nyx - --commission-rate="0.10" - --commission-max-rate="0.20" - --commission-max-change-rate="0.01" - --min-self-delegation="1" - --gas="auto" - --gas-adjustment=1.15 - --from="KEYRING_NAME" - --node https://rpc-1.nyx.nodes.guru:443 -``` -``` -# Sandbox Testnet -nyxd tx staking create-validator - --amount=10000000unyxt - --fees=5000unyxt - --pubkey=$(/home/youruser/path/to/nym/binaries/nyxd tendermint show-validator) - --moniker="whatever you called your validator" - --chain-id=sandbox - --commission-rate="0.10" - --commission-max-rate="0.20" - --commission-max-change-rate="0.01" - --min-self-delegation="1" - --gas="auto" - --gas-adjustment=1.15 - --from="KEYRING_NAME" - --node https://sandbox-validator1.nymtech.net:443 -``` - -You'll need either `unyxt` tokens on Sandbox, or `unyx` tokens on mainnet to perform this command. - -> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. - -If you want to edit some details for your node you will use a command like this: - -``` -# Mainnet -nyxd tx staking edit-validator - --chain-id=nyx - --moniker="whatever you called your validator" - --details="Nyx validator" - --security-contact="your email" - --identity="your identity" - --gas="auto" - --gas-adjustment=1.15 - --from="KEYRING_NAME" - --fees 2000unyx -``` -``` -# Sandbox testnet -nyxd tx staking edit-validator - --chain-id=sandbox - --moniker="whatever you called your validator" - --details="Sandbox testnet validator" - --security-contact="your email" - --identity="your identity" - --gas="auto" - --gas-adjustment=1.15 - --from="KEYRING_NAME" - --fees 2000unyxt -``` - -With above command you can specify the `gpg` key last numbers (as used in `keybase`) as well as validator details and your email for security contact. - -### Automating your validator with systemd -You will most likely want to automate your validator restarting if your server reboots. Below is a systemd unit file to place at `/etc/systemd/system/nymd.service`: - -```ini -[Unit] -Description=Nyxd -StartLimitInterval=350 -StartLimitBurst=10 - -[Service] -User=nyx # change to your user -Type=simple -Environment="LD_LIBRARY_PATH=/home/youruser/path/to/nyx/binaries" # change to correct path -ExecStart=/home/youruser/path/to/nyx/binaries/nymd start # change to correct path -Restart=on-failure -RestartSec=30 -LimitNOFILE=infinity - -[Install] -WantedBy=multi-user.target -``` - -Proceed to start it with: - -``` -systemctl daemon-reload # to pickup the new unit file -systemctl enable nymd # to enable the service -systemctl start nymd # to actually start the service -journalctl -f # to monitor system logs showing the service start -``` - -### Installing and configuring nginx for HTTPS -#### Setup -[Nginx](https://www.nginx.com/resources/glossary/nginx/#:~:text=NGINX%20is%20open%20source%20software,%2C%20media%20streaming%2C%20and%20more.&text=In%20addition%20to%20its%20HTTP,%2C%20TCP%2C%20and%20UDP%20servers.) is an open source software used for operating high-performance web servers. It allows us to set up reverse proxying on our validator server to improve performance and security. - -Install `nginx` and allow the 'Nginx Full' rule in your firewall: - -``` -sudo ufw allow 'Nginx Full' -``` - -Check nginx is running via systemctl: - -``` -systemctl status nginx -``` - -Which should return: - -``` -● nginx.service - A high performance web server and a reverse proxy server - Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled) - Active: active (running) since Fri 2018-04-20 16:08:19 UTC; 3 days ago - Docs: man:nginx(8) - Main PID: 2369 (nginx) - Tasks: 2 (limit: 1153) - CGroup: /system.slice/nginx.service - ├─2369 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; - └─2380 nginx: worker process -``` - -#### Configuration - -Proxying your validator's port `26657` to nginx port `80` can then be done by creating a file with the following at `/etc/nginx/conf.d/validator.conf`: - -``` -server { - listen 80; - listen [::]:80; - server_name "domain_name"; - - location / { - proxy_pass http://127.0.0.1:26657; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } -} -``` - -Followed by: - -``` -sudo apt install certbot nginx python3 -certbot --nginx -d nym-validator.yourdomain.com -m you@yourdomain.com --agree-tos --noninteractive --redirect -``` - -```admonish caution title="" -If using a VPS running Ubuntu 20: replace `certbot nginx python3` with `python3-certbot-nginx` -``` - -These commands will get you an https encrypted nginx proxy in front of the API. - -### Configuring Prometheus metrics (optional) - -Configure Prometheus with the following commands (adapted from NodesGuru's [Agoric setup guide](https://nodes.guru/agoric/setup-guide/en)): - -``` -echo 'export OTEL_EXPORTER_PROMETHEUS_PORT=9464' >> $HOME/.bashrc -source ~/.bashrc -sed -i '/\[telemetry\]/{:a;n;/enabled/s/false/true/;Ta}' $HOME/.nymd/config/app.toml -sed -i "s/prometheus-retention-time = 0/prometheus-retention-time = 60/g" $HOME/.nymd/config/app.toml -sudo ufw allow 9464 -echo 'Metrics URL: http://'$(curl -s ifconfig.me)':26660/metrics' -``` - -Your validator's metrics will be available to you at the returned 'Metrics URL'. - -~~~admonish example collapsible=true title="Console output" -``` -# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles. -# TYPE go_gc_duration_seconds summary -go_gc_duration_seconds{quantile="0"} 6.7969e-05 -go_gc_duration_seconds{quantile="0.25"} 7.864e-05 -go_gc_duration_seconds{quantile="0.5"} 8.4591e-05 -go_gc_duration_seconds{quantile="0.75"} 0.000115919 -go_gc_duration_seconds{quantile="1"} 0.001137591 -go_gc_duration_seconds_sum 0.356555301 -go_gc_duration_seconds_count 2448 -# HELP go_goroutines Number of goroutines that currently exist. -# TYPE go_goroutines gauge -go_goroutines 668 -# HELP go_info Information about the Go environment. -# TYPE go_info gauge -go_info{version="go1.15.7"} 1 -# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use. -# TYPE go_memstats_alloc_bytes gauge -go_memstats_alloc_bytes 1.62622216e+08 -# HELP go_memstats_alloc_bytes_total Total number of bytes allocated, even if freed. -# TYPE go_memstats_alloc_bytes_total counter -go_memstats_alloc_bytes_total 2.09341707264e+11 -# HELP go_memstats_buck_hash_sys_bytes Number of bytes used by the profiling bucket hash table. -# TYPE go_memstats_buck_hash_sys_bytes gauge -go_memstats_buck_hash_sys_bytes 5.612319e+06 -# HELP go_memstats_frees_total Total number of frees. -# TYPE go_memstats_frees_total counter -go_memstats_frees_total 2.828263344e+09 -# HELP go_memstats_gc_cpu_fraction The fraction of this program's available CPU time used by the GC since the program started. -# TYPE go_memstats_gc_cpu_fraction gauge -go_memstats_gc_cpu_fraction 0.03357798610671518 -# HELP go_memstats_gc_sys_bytes Number of bytes used for garbage collection system metadata. -# TYPE go_memstats_gc_sys_bytes gauge -go_memstats_gc_sys_bytes 1.3884192e+07 -``` -~~~ - -### Setting the ulimit -Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. - -`ulimit` is 1024 by default on most systems. It needs to be set higher, because validators make and receive a lot of connections to other nodes. - -If you see errors such as: - -``` -Failed to accept incoming connection - Os { code: 24, kind: Other, message: "Too many open files" } -``` - -This means that the operating system is preventing network connections from being made. - -##### Set the ulimit via `systemd` service file -Query the `ulimit` of your validator with: - -``` -grep -i "open files" /proc/$(ps -A -o pid,cmd|grep nymd | grep -v grep |head -n 1 | awk '{print $1}')/limits -``` - -You'll get back the hard and soft limits, which looks something like this: - -``` -Max open files 65536 65536 files -``` - -If your output is **the same as above**, your node will not encounter any `ulimit` related issues. - -However if either value is `1024`, you must raise the limit via the systemd service file. Add the line: - -``` -LimitNOFILE=65536 -``` - -Reload the daemon: - -``` -systemctl daemon-reload -``` - -or execute this as root for system-wide setting of `ulimit`: - -``` -echo "DefaultLimitNOFILE=65535" >> /etc/systemd/system.conf -``` - -Reboot your machine and restart your node. When it comes back, use `cat /proc/$(pidof nym-validator)/limits | grep "Max open files"` to make sure the limit has changed to 65535. - -##### Set the ulimit on `non-systemd` based distributions -Edit `etc/security/conf` and add the following lines: - -``` -# Example hard limit for max opened files -username hard nofile 4096 -# Example soft limit for max opened files -username soft nofile 4096 -``` - -Then reboot your server and restart your validator. - -## Using your validator -### Unjailing your validator -If your validator gets jailed, you can fix it with the following command: - -``` -# Mainnet -nyxd tx slashing unjail - --broadcast-mode=block - --from="KEYRING_NAME" - --chain-id=nyx - --gas=auto - --gas-adjustment=1.4 - --fees=7000unyx -``` -``` -# Sandbox Testnet -nyxd tx slashing unjail - --broadcast-mode=block - --from="KEYRING_NAME" - --chain-id=sandbox - --gas=auto - --gas-adjustment=1.4 - --fees=7000unyxt -``` - -### Upgrading your validator - -Upgrading from `v0.31.1` -> `v0.32.0` process is fairly simple. Grab the `v0.32.0` release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files: - -- the new validator (`nyxd`) v0.32.0 -- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`) - -Wait for the upgrade height to be reached and the chain to halt awaiting upgrade, then: - -* copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`) replacing your existing file with the same name. -* swap in your new `nyxd` binary and restart. - -You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/9). - -Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. - -#### Common reasons for your validator being jailed - -The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs. - -Running the command `df -H` will return the size of the various partitions of your VPS. - -If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog archives and restart your validator process. - -### Day 2 operations with your validator - -You can check your current balances with: - -``` -nymd query bank balances ${ADDRESS} -``` - -For example, on the Sanbox testnet this would return: - -```yaml -balances: -- amount: "919376" -denom: unymt -pagination: -next_key: null -total: "0" -``` - -You can, of course, stake back the available balance to your validator with the following command. - -> Remember to save some tokens for gas costs! - -``` -# Mainnet -nyxd tx staking delegate VALOPERADDRESS AMOUNTunym - --from="KEYRING_NAME" - --keyring-backend=os - --chain-id=nyx - --gas="auto" - --gas-adjustment=1.15 - --fees 5000unyx -``` -``` -# Sandbox Testnet -nyxd tx staking delegate VALOPERADDRESS AMOUNTunymt - --from="KEYRING_NAME" - --keyring-backend=os - --chain-id=sandbox - --gas="auto" - --gas-adjustment=1.15 - --fees 5000unyxt -``` - -## Validator port reference -All validator-specific port configuration can be found in `$HOME/.nymd/config/config.toml`. If you do edit any port configs, remember to restart your validator. - -| Default port | Use | -|--------------|--------------------------------------| -| 1317 | REST API server endpoint | -| 26656 | Listen for incoming peer connections | -| 26660 | Listen for Prometheus connections | diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md new file mode 100644 index 0000000000..6b7af1913a --- /dev/null +++ b/documentation/docs/src/nodes/validator.md @@ -0,0 +1,12 @@ +# Validator + +> The validator setup and maintenance guide has moved to the [Operator Guides book](TO_DO). + +Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. + +The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` token used to incentivise node operators is one of two native tokens of the chain, and the chain is where the [Mixnet](../nyx/mixnet-contract.md) and [Vesting](../nyx/vesting-contract.md) smart contracts are deployed. + +## Further Reading +* TODO section of whitepaper +* TODO blogpost +* TODO gaiad link(s) \ No newline at end of file From e8506f6d53816bc2edcc05345a8c6b56d632205d Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 19:51:03 +0200 Subject: [PATCH 095/146] cont. --- documentation/docs/src/nodes/gateway.md | 13 ++++++++++++- documentation/docs/src/nodes/mixnode.md | 7 +++++-- documentation/docs/src/nodes/validator.md | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md index f4ee68e242..ad2da8e8ca 100644 --- a/documentation/docs/src/nodes/gateway.md +++ b/documentation/docs/src/nodes/gateway.md @@ -1 +1,12 @@ -# Gateway +# Gateways + +> The gateway setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). + +Gateways are key to both the usability of the mixnet, and the operation of the mixnet's tokenomics. They serve two main functions: +* (When the mixnet is no longer in 'free' mode) to act literally as gateways; checking for zkNym credentials (previously referred to as [Coconut Credentials](../bandwidth-credentials.md)) that prove a user has 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 (because of their quality of service) the higher the rewards. 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 egress point for mixnet traffic, and always receive mixnet traffic from it (see the [mixnet traffic flow page](../architecture/traffic-flow.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 +* TODO whitepaper section +* TODO loopix paper section +* TODO blogpost \ No newline at end of file diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index 159251ad3e..14e42a54b9 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -1,4 +1,4 @@ -# Mix Node +# Mix Nodes > The mix node setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). @@ -8,10 +8,13 @@ Mix nodes perform one task: receiving packets, decrypting their outer 'layer', a The aim of this mixing is to protect against timing-based deanonymisation attempts by a global adversary able to monitor the entire network with a 'God's Eye View'. +Mix nodes are rewarded according to their quality of service, and their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) affected by this (as well as their delegation-based reputation - see [further reading](#further-reading) for more on this). + ## (Coming soon) Mixing: a Step-by-Step Breakdown ## Further reading TODO -*
+* TODO SECTION OF WHITEPAPER +* TODO LOOPIX PAPER SECTION * * diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index 6b7af1913a..0ef86744a8 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -1,4 +1,4 @@ -# Validator +# Validators > The validator setup and maintenance guide has moved to the [Operator Guides book](TO_DO). From c85f7d2565d9e384a395fff31631c12fdcb4b040 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Thu, 3 Aug 2023 21:15:58 +0200 Subject: [PATCH 096/146] skeleton of NR page --- documentation/docs/src/nodes/network-requester.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/documentation/docs/src/nodes/network-requester.md b/documentation/docs/src/nodes/network-requester.md index 797dfd7795..747efbe62a 100644 --- a/documentation/docs/src/nodes/network-requester.md +++ b/documentation/docs/src/nodes/network-requester.md @@ -1 +1,9 @@ -# Network Requester +# Network Requesters + +> The network requester setup and maintenance guide has moved to the [Operator Guides book](TO_DO). + +Network requesters are the first instance of the catch-all term 'service', or 'service providers'. In essence, think of services as being the part of the mixnet infrastructure that let you _do_ something, such as access emails, messaging service backends, or blockchains via the mixnet. + +Network requesters, in essence, act as a form of proxy (somewhat analagous to a Tor exit node) + + From 2711e6f679e14f5b6df71ddb7512fb2b5462b2e8 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 4 Aug 2023 13:18:12 +0200 Subject: [PATCH 097/146] filled/docs/validators.md --- .../docs/src/images/nym-token-flow.png | Bin 0 -> 174671 bytes documentation/docs/src/nodes/gateway.md | 4 +-- documentation/docs/src/nodes/mixnode.md | 2 +- .../docs/src/nodes/network-requester.md | 2 +- documentation/docs/src/nodes/validator.md | 23 ++++++++++++++---- .../operators/src/nodes/maintenance.md | 3 ++- .../operators/src/preliminary-steps.md | 2 +- 7 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 documentation/docs/src/images/nym-token-flow.png diff --git a/documentation/docs/src/images/nym-token-flow.png b/documentation/docs/src/images/nym-token-flow.png new file mode 100644 index 0000000000000000000000000000000000000000..eb026e23258efb6830022aef1b5af8566c8ecec1 GIT binary patch literal 174671 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

rAqPF^d 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 U$$MSzw1{bxnWbsjCAZ)H1LKK-6#xJL literal 0 HcmV?d00001 diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md index ad2da8e8ca..ebdae64574 100644 --- a/documentation/docs/src/nodes/gateway.md +++ b/documentation/docs/src/nodes/gateway.md @@ -1,6 +1,6 @@ # Gateways -> The gateway setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). +> The gateway setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/operators/nodes/gateway-setup.html). Gateways are key to both the usability of the mixnet, and the operation of the mixnet's tokenomics. They serve two main functions: * (When the mixnet is no longer in 'free' mode) to act literally as gateways; checking for zkNym credentials (previously referred to as [Coconut Credentials](../bandwidth-credentials.md)) that prove a user has 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 (because of their quality of service) the higher the rewards. 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. @@ -9,4 +9,4 @@ Gateways are key to both the usability of the mixnet, and the operation of the m ## Further Reading * TODO whitepaper section * TODO loopix paper section -* TODO blogpost \ No newline at end of file +* TODO blogpost diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index 14e42a54b9..2d1911a990 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -1,6 +1,6 @@ # Mix Nodes -> The mix node setup and maintenance guide has migrated to the [Operator Guides book](TO_DO). +> The mix node setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/developers/nodes/mix-node-setup.html). Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing' or performing the 'poisson mix'. diff --git a/documentation/docs/src/nodes/network-requester.md b/documentation/docs/src/nodes/network-requester.md index 747efbe62a..83778e18a4 100644 --- a/documentation/docs/src/nodes/network-requester.md +++ b/documentation/docs/src/nodes/network-requester.md @@ -1,6 +1,6 @@ # Network Requesters -> The network requester setup and maintenance guide has moved to the [Operator Guides book](TO_DO). +> The network requester setup and maintenance guide has moved to the [Operator Guides book](https://nymtech.net/developers/nodes/network-requester-setup.html). Network requesters are the first instance of the catch-all term 'service', or 'service providers'. In essence, think of services as being the part of the mixnet infrastructure that let you _do_ something, such as access emails, messaging service backends, or blockchains via the mixnet. diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index 0ef86744a8..ac3d896bca 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -1,12 +1,25 @@ +- [x] TODO section of whitepaper +- [x] TODO blogpost +- [ ] TODO gaias link(s) + # Validators -> The validator setup and maintenance guide has moved to the [Operator Guides book](TO_DO). +> The validator setup and maintenance guide has moved to the [Operator Guides book](https://nymtech.net/operators/nodes/validator-setup.html). -Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. +> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. + + +Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx blockchain records the ledger of NYM transactions and executes the smart contracts for distributing NYM rewards. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` token used to incentivise node operators is one of two native tokens of the chain, and the chain is where the [Mixnet](../nyx/mixnet-contract.md) and [Vesting](../nyx/vesting-contract.md) smart contracts are deployed. +![Nym Token Flow](../images/nym-token-flow.png) + ## Further Reading -* TODO section of whitepaper -* TODO blogpost -* TODO gaiad link(s) \ No newline at end of file + +* Detailed info on Nyx Validators and token flow can be found in [Nym Reward Sharing for Mixnets document](https://nymtech.net/nym-cryptoecon-paper.pdf) in section 2.3 and 2.4. +* For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). +* More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). +* [Here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. +* Our [quarterly update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. + diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 7ffe1d6d58..05723461f2 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -7,7 +7,8 @@ TODO - copy that dir over to the new vps - re-run init - remember that init doesn't overwrite existing keys - to generate a config with the new listening address etc - change the node info via the wallet - - Since otherwise their keys will point to the old IP address in the smart contract, and their node will (a) not be able to be connected to, and (b) fail uptime checks + - Since otherwise their keys will point to the old IP address in the smart contract, and their node will (a) not be able to be connected to, and (b) fail uptime checks +- [ ] Test the scp -3 command in the moving a node section ---> ## Useful commands diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index d36ca76da4..ec13e7ea59 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,6 +1,6 @@ # Preliminary Steps -> The Nym `mix node`, `gateway` and `network-requester` binaries were built in the [building nym](../binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. +> The Nym `mix node`, `gateway` and `network-requester` binaries were built in the [building nym](./binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. ## Preliminary steps From c43344d489948976edded8d422bc62e6a19e8f17 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Fri, 4 Aug 2023 13:19:29 +0200 Subject: [PATCH 098/146] remove reduntant nym/docs/ --- docs/src/binaries/building-nym.html | 242 ---------------------- docs/src/binaries/building-nym.md | 1 - docs/src/binaries/init-and-config.html | 242 ---------------------- docs/src/binaries/init-and-config.md | 1 - docs/src/binaries/pre-built-binaries.html | 242 ---------------------- docs/src/binaries/pre-built-binaries.md | 1 - 6 files changed, 729 deletions(-) delete mode 100644 docs/src/binaries/building-nym.html delete mode 100644 docs/src/binaries/building-nym.md delete mode 100644 docs/src/binaries/init-and-config.html delete mode 100644 docs/src/binaries/init-and-config.md delete mode 100644 docs/src/binaries/pre-built-binaries.html delete mode 100644 docs/src/binaries/pre-built-binaries.md diff --git a/docs/src/binaries/building-nym.html b/docs/src/binaries/building-nym.html deleted file mode 100644 index 90e9c937cc..0000000000 --- a/docs/src/binaries/building-nym.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - Building from Source - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Building from Source

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/src/binaries/building-nym.md b/docs/src/binaries/building-nym.md deleted file mode 100644 index f195be32f9..0000000000 --- a/docs/src/binaries/building-nym.md +++ /dev/null @@ -1 +0,0 @@ -# Building from Source diff --git a/docs/src/binaries/init-and-config.html b/docs/src/binaries/init-and-config.html deleted file mode 100644 index 2a9390a316..0000000000 --- a/docs/src/binaries/init-and-config.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - Binary Initialisation and Configuration - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Binary Initialisation and Configuration

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/src/binaries/init-and-config.md b/docs/src/binaries/init-and-config.md deleted file mode 100644 index 9087d5cf00..0000000000 --- a/docs/src/binaries/init-and-config.md +++ /dev/null @@ -1 +0,0 @@ -# Binary Initialisation and Configuration diff --git a/docs/src/binaries/pre-built-binaries.html b/docs/src/binaries/pre-built-binaries.html deleted file mode 100644 index a02f51d2bd..0000000000 --- a/docs/src/binaries/pre-built-binaries.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - Pre-built Binaries - Nym Operators Guides - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - - - - - -
-
- {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- - {comment} -
- -

Pre-built Binaries

- -
- - -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - -
- - diff --git a/docs/src/binaries/pre-built-binaries.md b/docs/src/binaries/pre-built-binaries.md deleted file mode 100644 index 8c52595ce9..0000000000 --- a/docs/src/binaries/pre-built-binaries.md +++ /dev/null @@ -1 +0,0 @@ -# Pre-built Binaries From 1e2de5067a6802d578b15fdeea791b67d0a83dfa Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:08:18 +0200 Subject: [PATCH 099/146] correct go installation - guide finished --- .../operators/src/nodes/validator-setup.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 9e233808d7..4726b4c11c 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -41,19 +41,6 @@ rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.6.linux-amd64.tar.gz export PATH=$PATH:/usr/local/go/bin source $HOME/.profile ``` - Verify `Go` is installed with: From 77f8eadd0eb527531eab041f0b66f3e5bdaae003 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:19:34 +0200 Subject: [PATCH 100/146] scp automation tested - doc finished --- documentation/operators/src/nodes/maintenance.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 05723461f2..a9a90ccaa6 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -1,15 +1,5 @@ # Maintenance - ## Useful commands > Adding `--no-banner` startup flag will prevent Nym banner being printed even if run in tty environment. From d13116bda0f2e7a14ae9a241d79c1dd7f2563e10 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:36:19 +0200 Subject: [PATCH 101/146] old typos edits --- documentation/docs/src/sdk/rust.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/docs/src/sdk/rust.md b/documentation/docs/src/sdk/rust.md index 035d8b37b5..70015751e4 100644 --- a/documentation/docs/src/sdk/rust.md +++ b/documentation/docs/src/sdk/rust.md @@ -77,12 +77,12 @@ In order to reply to an incoming message using SURBs, you can construct a `recip ``` ### 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 peforming 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`). +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 ususally do (under the hood): +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}} From 9c0317ab289ae91fb6b0a1bf3bd966a9da89e465 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:38:10 +0200 Subject: [PATCH 102/146] correcting links, typos - doc finished --- documentation/operators/src/nodes/troubleshooting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index d8fb566b58..50f9406ff3 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -183,7 +183,7 @@ Your mix node **must speak both IPv4 and IPv6** in order to cooperate with other #### Incorrect bonding information -Check that you have provided the correct information when bonding your mix node in the web wallet [interface](https://sandbox-wallet.nymtech.net/). When in doubt, un-bond and then re-bond your node! +Check that you have provided the correct information when bonding your mix node in the web wallet interface. When in doubt, un-bond and then re-bond your node! > All delegated stake will be lost when un-bonding! However the mix node must be operational in the first place for the delegation to have any effect. @@ -222,7 +222,7 @@ bob@nym:~$ hostname -I ### Running on a local machine behind NAT with no fixed IP address -Your ISP has to be IPv6 ready if you want to run a mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is a extra paid service or they simply don't offer it. +Your ISP has to be IPv6 ready if you want to run a mix node on your local machine. Sadly, in 2020, most of them are not and you won't get an IPv6 address by default from your ISP. Usually it is an extra paid service or they simply don't offer it. Before you begin, check if you have IPv6 [here](https://test-ipv6.cz/) or by running command explained in the [section above](./troubleshooting.md#no-ipv6-connectivity). If not, then don't waste your time to run a node which won't ever be able to mix any packet due to this limitation. Call your ISP and ask for IPv6, there is a plenty of it for everyone! From 9652060c57074cb35db45f95208d719ef0a64dec Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:40:28 +0200 Subject: [PATCH 103/146] correction of typos --- documentation/docs/src/tools/nym-cli.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/documentation/docs/src/tools/nym-cli.md b/documentation/docs/src/tools/nym-cli.md index f516190002..b6ed36bfa7 100644 --- a/documentation/docs/src/tools/nym-cli.md +++ b/documentation/docs/src/tools/nym-cli.md @@ -4,14 +4,14 @@ This is a CLI tool for interacting with: * the Nyx blockchain (account management, querying the chain state, etc) -* the smart contracts deployed on Nyx (bonding and unbonding mixnodes, collecting rewards, etc) +* the smart contracts deployed on Nyx (bonding and un-bonding mixnodes, collecting rewards, etc) It provides a convenient wrapper around the `nymd` client, and has similar functionality to the `nyxd` binary for querying the chain or executing smart contract methods. ## Building The `nym-cli` binary can be built by running `cargo build --release` in the `nym/tools/nym-cli` directory. -### Useage +### Usage You can see all available commands with: ``` @@ -225,9 +225,9 @@ Bonding a mix node is a process that takes a few steps due to the need to sign a ./nym-cli --mnemonic mixnet operators gateway bond --amount 100000000 --mix-port 1789 --version "1.1.13" --host "85.163.111.99" --identity-key "B6pWscxYb8sPAdKTci8zPy5AgMzn5Zx8KpWwQNCyUSU7" --location "nym-town" --sphinx-key "o6MmKHzRewpNzVwaV37ZX9G3BfK4AmfYvsQfyoyAFRk" --signature "2TujBZfer8r5QM639Yb8coD9xH6f5eXzjAT5dD7wMom9fH8D1u36d7UpPdVaaZrWsCynmYpobwMWqiMKr5kM6CprD" ``` -### Unbond a node +### Un-bond a node -Unbond a mix node or gateway. +Un-bond a mix node or gateway. ``` ./nym-cli mixnet operators gateway unbound --mnemonic ``` @@ -270,7 +270,7 @@ Delegate to a mix node. ./nym-cli mixnet delegators delegate --amount –mix-id --mnemonic ``` -### Undelegate Stake +### Un-delegate Stake Remove stake from a mix node. ``` @@ -321,10 +321,10 @@ Query for vesting schedule in the [vesting smart contract](../nyx/vesting-contra ## Staking on someone's behalf (for custodians) -There is a limitation the the staking address can only perform the following actions (and are visible via the Nym Wallet: +There is a limitation the staking address can only perform the following actions (and are visible via the Nym Wallet: -- Bond on the gaƒteway's or mix node's behalf. -- Delegate or Undelegate (to a mix node in order to begin receiving rewards) +- Bond on the gateway's or mix node's behalf. +- Delegate or Un-delegate (to a mix node in order to begin receiving rewards) - Claiming the rewards on the account ```admonish note title="" @@ -333,7 +333,7 @@ The staking address has no ability to withdraw any coins from the parent's accou The staking address must maintain the same level of security as the parent mnemonic; while the parent mnemonic's delegations and bonding events will be visible to the parent owner, the staking address will be the only account capable of undoing the bonding and delegating from the mix nodes or gateway. -Query for staking on behlaf of someone else +Query for staking on behalf of someone else ``` ./nym-cli --mnemonic mixnet delegators delegate --mix-id --identity-key --amount ``` From ce81f0c841946e4757a848384ad66825f6fd9e3d Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 12:47:29 +0200 Subject: [PATCH 104/146] operators-guides final review of links and typos --- documentation/operators/src/faq.md | 2 +- documentation/operators/src/introduction.md | 2 +- documentation/operators/src/nodes/mix-node-setup.md | 8 +------- .../operators/src/nodes/network-requester-setup.md | 4 ++-- documentation/operators/src/nodes/troubleshooting.md | 2 +- documentation/operators/src/nodes/validator-setup.md | 4 ++-- 6 files changed, 8 insertions(+), 14 deletions(-) diff --git a/documentation/operators/src/faq.md b/documentation/operators/src/faq.md index a42af22825..9bb2c6dec9 100644 --- a/documentation/operators/src/faq.md +++ b/documentation/operators/src/faq.md @@ -14,7 +14,7 @@ For more detailed calculation, read our blog post [Nym Token Economics update](h ### Which VPS providers would you recommend? -Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We recieve some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. +Consider in which jurisdiction you reside and where do you want to run a mix node. Do you want to pay by crypto or not and what are the other important particularities for your case? We always recommend operators to try to chose smaller and decentralized VPS providers over the most known ones controlling a majority of the internet. We receive some good feedback on these: Hertzner, DigitalOcean, Linode, Ghandi and Exoscale. Do your own research and share with the community. diff --git a/documentation/operators/src/introduction.md b/documentation/operators/src/introduction.md index dc160825d6..4050fe141c 100644 --- a/documentation/operators/src/introduction.md +++ b/documentation/operators/src/introduction.md @@ -2,7 +2,7 @@ This is Nym's Operators guide, containing information and setup guides for the various pieces of Nym mixnet infrastructure (mix node, gateway and network requester) and Nyx blockchain validators. -If you are new to Nym and want to learn about the mixnet, explore quickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/). +If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/). If you want to dive deeper into Nym's architecture, clients, nodes, and SDK examples visit the [technical docs](https://nymtech.net/docs/). diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 2dccc52258..1c70383a61 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -173,12 +173,6 @@ If everything worked, you'll see your node running on the either the [Sandbox te Note that your node's public identity key is displayed during startup, you can use it to identify your node in the list. - - Have a look at the saved configuration files in `$HOME/.nym/mixnodes/` to see more configuration options. ## Node Description (optional) @@ -298,7 +292,7 @@ Once you've started your mix node and it connects to the validator, your node wi - [Mainnet](https://explorer.nymtech.net/overview) - [Sandbox testnet](https://sandbox-explorer.nymtech.net/) -Enter your **identity key** to find your node. There are numerous statistics about your node on that page that are useful for checking your uptime history, packets mixed, and any delegations your node may have. +Enter your **identity key** to find your node. There are numerous statistics about your node on that page that are useful for checking your up-time history, packets mixed, and any delegations your node may have. There are also 2 community explorers which have been created by [Nodes Guru](https://nodes.guru): diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 049b139de6..15cacd3266 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -22,7 +22,7 @@ Any request to a URL which is not on this list will be blocked. On startup, if this file is not present, the requester will grab the default whitelist from [Nym's default list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) automatically. -This default whitelist is useful for knowing that the majority of network requesters are able to support certain apps 'out of the box'. +This default whitelist is useful for knowing that the majority of Network requesters are able to support certain apps 'out of the box'. **Operators of a network requester are of course free to edit this file and add the URLs of services they wish to support to it!** You can find instructions below on adding your own URLs or IPs to this list. @@ -77,7 +77,7 @@ matrix.org ``` ## Network Requester Directory -You can find a list of Network Requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. +You can find a list of Network requesters running the default whitelist in the [explorer](https://explorer.nymtech.net/network-components/service-providers). This list comprises of the NRs running as infrastructure for NymConnect. > We are currently working on a smart-contract based solution more in line with how Mix nodes and Gateways announce themselves to the network. diff --git a/documentation/operators/src/nodes/troubleshooting.md b/documentation/operators/src/nodes/troubleshooting.md index 50f9406ff3..20b98970df 100644 --- a/documentation/operators/src/nodes/troubleshooting.md +++ b/documentation/operators/src/nodes/troubleshooting.md @@ -236,7 +236,7 @@ Here is a sample of the `init` command example to create the mix node config. ./nym-mixnode init --id --host 0.0.0.0 --announce-host 85.160.12.13 ``` -- `--host 0.0.0.0` should work every time even if your local machine IPv4 address changes. For example on Monday your router gives your machine an address `192.168.0.13` and on Wednesday, the DHCP lease will end and you will be asigned `192.168.0.14`. Using `0.0.0.0` should avoid this without having to set any static ip in your router`s configuration. +- `--host 0.0.0.0` should work every time even if your local machine IPv4 address changes. For example on Monday your router gives your machine an address `192.168.0.13` and on Wednesday, the DHCP lease will end and you will be assigned `192.168.0.14`. Using `0.0.0.0` should avoid this without having to set any static IP in your router`s configuration. - you can get your current IPv4 address by either using `curl ipinfo.io` if you're on MacOS or Linux or visiting [whatsmyip site](https://www.whatsmyip.org/). Simply copy it and use it as `--anounce-host` address. diff --git a/documentation/operators/src/nodes/validator-setup.md b/documentation/operators/src/nodes/validator-setup.md index 4726b4c11c..ca35c0b2b9 100644 --- a/documentation/operators/src/nodes/validator-setup.md +++ b/documentation/operators/src/nodes/validator-setup.md @@ -455,7 +455,7 @@ If you want to set up a reverse proxying on the validator server to improve secu Linux machines limit how many open files a user is allowed to have. This is called a `ulimit`. We need to set it to a higher value than the default 1024. Follow the instructions in the [maintenance page](./maintenance.md#Setting-the-ulimit) to change the `ulimit` value for validators. ## Using your validator -### Unjailing your validator +### Un-jailing your validator If your validator gets jailed, you can fix it with the following command: ``` @@ -499,7 +499,7 @@ You can check your current balances with: nymd query bank balances ${ADDRESS} ``` -For example, on the Sanbox testnet this would return: +For example, on the Sandbox testnet this would return: ```yaml balances: From 567d3c81733294a78e1361a10d8fd04afed12d8d Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:13:11 +0200 Subject: [PATCH 105/146] socks5: new commands from #3699 --- documentation/docs/src/clients/socks5-client.md | 12 +++++++++++- documentation/operators/src/nodes/maintenance.md | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/documentation/docs/src/clients/socks5-client.md b/documentation/docs/src/clients/socks5-client.md index e7163347cb..e8bce0e948 100644 --- a/documentation/docs/src/clients/socks5-client.md +++ b/documentation/docs/src/clients/socks5-client.md @@ -82,7 +82,7 @@ You can check that your binaries are properly compiled with: You can check the necessary parameters for the available commands by running: ``` -./nym-client --help +./nym-client --help ``` ### Initialising a new client instance @@ -169,3 +169,13 @@ 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. diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index a9a90ccaa6..911a6825af 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -661,7 +661,7 @@ All ``-specific port configuration can be found in `$HOME/.nym// Date: Mon, 7 Aug 2023 15:52:48 +0200 Subject: [PATCH 106/146] added links --- documentation/docs/src/nodes/gateway.md | 9 ++++----- documentation/docs/src/nodes/mixnode.md | 15 ++++++--------- documentation/docs/src/nodes/validator.md | 6 +----- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md index ebdae64574..814c550d4c 100644 --- a/documentation/docs/src/nodes/gateway.md +++ b/documentation/docs/src/nodes/gateway.md @@ -3,10 +3,9 @@ > The gateway setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/operators/nodes/gateway-setup.html). Gateways are key to both the usability of the mixnet, and the operation of the mixnet's tokenomics. They serve two main functions: -* (When the mixnet is no longer in 'free' mode) to act literally as gateways; checking for zkNym credentials (previously referred to as [Coconut Credentials](../bandwidth-credentials.md)) that prove a user has 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 (because of their quality of service) the higher the rewards. 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 egress point for mixnet traffic, and always receive mixnet traffic from it (see the [mixnet traffic flow page](../architecture/traffic-flow.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. +* 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. 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 egress point for mixnet traffic, and always receive mixnet traffic from it (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. ## Further Reading -* TODO whitepaper section -* TODO loopix paper section -* TODO blogpost +* [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 4.2 +* [Nym Blog: Gateways to Privacy](https://blog.nymtech.net/gateways-to-privacy-51196005bf5) diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index 2d1911a990..e849b141b1 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -2,19 +2,16 @@ > The mix node setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/developers/nodes/mix-node-setup.html). -Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing' or performing the 'poisson mix'. +Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing'. -Mix nodes perform one task: receiving packets, decrypting their outer 'layer', and holding them for a variable amount of time before passing them to their next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were recieved. - -The aim of this mixing is to protect against timing-based deanonymisation attempts by a global adversary able to monitor the entire network with a 'God's Eye View'. +Mix nodes, after receiving a packet, decrypt its outer 'layer', and hold them for a variable amount of time before passing them to their next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were received. Mix nodes are rewarded according to their quality of service, and their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) affected by this (as well as their delegation-based reputation - see [further reading](#further-reading) for more on this). ## (Coming soon) Mixing: a Step-by-Step Breakdown ## Further reading -TODO -* TODO SECTION OF WHITEPAPER -* TODO LOOPIX PAPER SECTION -* -* +* [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 4 +* [Nym Blog: Mix node deepdive](https://blog.nymtech.net/nym-mixnodes-deep-dive-d2b91917f097) +* [Mixnet Traffic Flow overview](../architecture/traffic-flow.md) +* [Reward Sharing for Mixnets](https://nymtech.net/nym-cryptoecon-paper.pdf) \ No newline at end of file diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index ac3d896bca..ceb0abdf8a 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -1,6 +1,4 @@ - [x] TODO section of whitepaper -- [x] TODO blogpost -- [ ] TODO gaias link(s) # Validators @@ -8,7 +6,6 @@ > We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. - Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx blockchain records the ledger of NYM transactions and executes the smart contracts for distributing NYM rewards. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` token used to incentivise node operators is one of two native tokens of the chain, and the chain is where the [Mixnet](../nyx/mixnet-contract.md) and [Vesting](../nyx/vesting-contract.md) smart contracts are deployed. @@ -16,10 +13,9 @@ The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` ![Nym Token Flow](../images/nym-token-flow.png) ## Further Reading - * Detailed info on Nyx Validators and token flow can be found in [Nym Reward Sharing for Mixnets document](https://nymtech.net/nym-cryptoecon-paper.pdf) in section 2.3 and 2.4. * For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). * More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). * [Here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. * Our [quarterly update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. - +* [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 3.1 \ No newline at end of file From 8fe549daa595dff1b4c2fc68e0aae562745f0cf9 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 7 Aug 2023 16:06:39 +0200 Subject: [PATCH 107/146] more links, fleshed out intro --- documentation/docs/src/introduction.md | 23 +++++++++++++-------- documentation/docs/src/wallet/cli-wallet.md | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/documentation/docs/src/introduction.md b/documentation/docs/src/introduction.md index 9e245497f4..9964ec5b75 100644 --- a/documentation/docs/src/introduction.md +++ b/documentation/docs/src/introduction.md @@ -2,24 +2,29 @@ This is Nym's technical documentation, containing information and setup guides about the various pieces of Nym software such as different mixnet infrastructure nodes, application clients, and existing applications like the desktop wallet and mixnet explorer. -If you are new to Nym and want to learn about the mixnet, how to integrate with the network, developer tutorials and quickstart guides, check out the [Developer Portal](https://nymtech.net/developers/). +If you are looking for information and setup guides for the various pieces of Nym mixnet infrastructure (mix nodes, gateways and network requesters) and Nyx blockchain validators see the **new [Operators Guides](https://nymtech.net/operators)** book. + +If you are new to Nym and want to learn about the mixnet, explore kickstart options and demos, learn how to integrate with the network, and follow developer tutorials check out the [Developer Portal](https://nymtech.net/developers/). ## Popular pages **Network Architecture:** * [Network Overview](./architecture/network-overview.md) * [Mixnet Traffic Flow](./architecture/traffic-flow.md) -**Node setup and usage guides:** -* [Mix nodes](./nodes/mix-node-setup.md) -* [Gateways](./nodes/gateway-setup.md) -* [Network requesters](./nodes/network-requester-setup.md) -* [Validators](./nodes/validator-setup.md) +**SDK examples:** +* [Typescript SDK](./sdk/typescript.md) +* [Rust SDK](./sdk/rust.md) + +**Nyx** +* [Interacting with the Nyx chain](./nyx/interacting-with-chain.md) +* [Ledger Live setup](./nyx/ledger-live.md) +* [RPC Node](./nyx/rpc-node.md) **Client setup and usage guides:** * [Websocket client](./clients/websocket-client.md) * [Socks5 client](./clients/socks5-client.md) * [Webassembly client](./clients/webassembly-client.md) -**SDK guides:** -* [Typescript SDK](./sdk/typescript.md) -* [Rust SDK](./sdk/rust.md) +**Wallets** +* [Desktop](./wallet/desktop-wallet.md) +* [CLI](./wallet/cli-wallet.md) \ No newline at end of file diff --git a/documentation/docs/src/wallet/cli-wallet.md b/documentation/docs/src/wallet/cli-wallet.md index e4d2468068..3f713b1937 100644 --- a/documentation/docs/src/wallet/cli-wallet.md +++ b/documentation/docs/src/wallet/cli-wallet.md @@ -5,4 +5,4 @@ If you have already read our validator setup and maintenance [documentation](../ ### Using `nyxd` binary as a CLI wallet You can use the `nyxd` as a minimal CLI wallet if you want to set up an account (or multiple accounts). Just compile the binary as per the documentation, **stopping after** the [building your validator](../nodes/validator-setup.md#building-your-validator) step is complete. You can then run `nyxd keys --help` to see how you can set up and store different keypairs with which to interact with the Nyx blockchain. - +For more on interacting with the chain, see the [Interacting with Nyx Chain and Smart Contracts](../nyx/interacting-with-chain.md) page. From d3d5346cfe6bd346e3adf93ee294958e34d3909d Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 7 Aug 2023 16:38:02 +0200 Subject: [PATCH 108/146] typo fix --- documentation/operators/src/nodes/network-requester-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/operators/src/nodes/network-requester-setup.md b/documentation/operators/src/nodes/network-requester-setup.md index 15cacd3266..e840bb357a 100644 --- a/documentation/operators/src/nodes/network-requester-setup.md +++ b/documentation/operators/src/nodes/network-requester-setup.md @@ -83,7 +83,7 @@ You can find a list of Network requesters running the default whitelist in the [ ## Viewing command help -To begin, move to `/taget/release` directory from which you run the node commands: +To begin, move to `/target/release` directory from which you run the node commands: ``` cd target/release From 7a606e11f4fe45f4ac3fe3b01971f967ca17b347 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Mon, 7 Aug 2023 16:38:13 +0200 Subject: [PATCH 109/146] NR page --- .../docs/src/nodes/network-requester.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/documentation/docs/src/nodes/network-requester.md b/documentation/docs/src/nodes/network-requester.md index 83778e18a4..ac083a3143 100644 --- a/documentation/docs/src/nodes/network-requester.md +++ b/documentation/docs/src/nodes/network-requester.md @@ -1,9 +1,22 @@ -# Network Requesters +# Network Requester > The network requester setup and maintenance guide has moved to the [Operator Guides book](https://nymtech.net/developers/nodes/network-requester-setup.html). Network requesters are the first instance of the catch-all term 'service', or 'service providers'. In essence, think of services as being the part of the mixnet infrastructure that let you _do_ something, such as access emails, messaging service backends, or blockchains via the mixnet. -Network requesters, in essence, act as a form of proxy (somewhat analagous to a Tor exit node) +## Domain filtering +Network requesters, in essence, act as a form of proxy (somewhat analagous to a Tor exit node). If you have access to a server, you can run the network requester, which allows Nym users to send outbound requests from their local machine through the mixnet to a server, which then makes the request on their behalf, shielding them (and their metadata) from clearnet, untrusted and unknown infrastructure, such as email or message client servers. +By default the network requester is **not** an open proxy (although it can be used as one). It uses a whitelist for outbound requests. +Any request to a URL which is not on this local list (modified by the node operator) or [Nym's default list](https://nymtech.net/.wellknown/network-requester/standard-allowed-list.txt) will be blocked. + +This default whitelist is useful for knowing that the majority of Network requesters are able to support certain apps 'out of the box', and the local whitelist allows operators to include their own whitelisted domains. + +> Substantial changes are on the horizon concerning how Network Requesters manage incoming requests - if you are an operator and have experience running software such as Tor exit nodes or p2p nodes get in touch via our [Matrix server](https://matrix.to/#/#dev:nymtech.chat). + +## (Coming soon) Consuming credentials for anonymous service payment + +## Further reading +* [Nym Blog: Network Requester deepdive](https://blog.nymtech.net/tech-deepdive-network-requesters-e5359a6cc31c) +* [Nym Blog: Choose Your Character](https://blog.nymtech.net/choose-your-character-an-overview-of-nym-network-actors-19e6a9808540) \ No newline at end of file From 32bfceacb5fef9dc2098b536625f1fbfa26c82a1 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 8 Aug 2023 13:59:53 +0200 Subject: [PATCH 110/146] added custom 404 page for all books --- documentation/dev-portal/book.toml | 2 +- documentation/dev-portal/src/not-found.md | 11 +++++++++++ documentation/docs/src/not-found.md | 4 ++-- documentation/operators/book.toml | 4 ++-- documentation/operators/src/not-found.md | 11 +++++++++++ 5 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 documentation/dev-portal/src/not-found.md create mode 100644 documentation/operators/src/not-found.md diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index cf434a31f5..d8ede22a4a 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -84,7 +84,7 @@ git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" site-url = "/developers/" # cname = "nymtech.net" -# input-404 = "not-found.md" # todo make custom 404 page +input-404 = "not-found.md" [output.html.fold] enable = true # whether or not to enable section folding diff --git a/documentation/dev-portal/src/not-found.md b/documentation/dev-portal/src/not-found.md new file mode 100644 index 0000000000..704da5ec19 --- /dev/null +++ b/documentation/dev-portal/src/not-found.md @@ -0,0 +1,11 @@ +# Page Not Found + +You seem to have followed a link to a page that no longer exists. Our documentation is changing and growing over time, so this page has most likely been moved somewhere else. + +For node setup guides, see the [Operator Guides book](https://nymtech.net/operators). + +For information on network architecture traffic flow, clients, the SDKs, or interacting with the Nyx blockchain see the [Technical Documentation](https://nymtech.net/docs). + +If you are looking for information on developer tutorials, app guides, and demo and community apps, check the sitemap on the left hand side of the screen. + +If you still can't find what you're looking for get in touch with us via [Matrix](https://matrix.to/#/#nym-community:nymtech.chat). \ No newline at end of file diff --git a/documentation/docs/src/not-found.md b/documentation/docs/src/not-found.md index 3d203a9bb8..af87d6dd59 100644 --- a/documentation/docs/src/not-found.md +++ b/documentation/docs/src/not-found.md @@ -2,10 +2,10 @@ You seem to have followed a link to a page that no longer exists. Our documentation is changing and growing over time, so this page has most likely been moved somewhere else. -For node setup guides, see the [Operators Guides book](https://nymtech.net/operators). +For node setup guides, see the [Operator Guides book](https://nymtech.net/operators). For developer tutorials, app guides, and demo and community apps, see the [Developer Portal](https://nymtech.net/developers). If you are looking for information on network architecture traffic flow, clients, the SDKs, or interacting with the Nyx blockchain, check the sitemap on the left hand side of the screen. -If you still can't find what you're looking for get in touch with us via [Matrix](TODO). \ No newline at end of file +If you still can't find what you're looking for get in touch with us via [Matrix](https://matrix.to/#/#nym-community:nymtech.chat). \ No newline at end of file diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 28efe62c57..2ce49e37bb 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -92,9 +92,9 @@ additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" # edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}" -# site-url = "/docs/" +site-url = "/operators/" # cname = "nymtech.net" -# input-404 = "not-found.md" # todo make custom 404 page +input-404 = "not-found.md" [output.html.fold] enable = true # whether or not to enable section folding diff --git a/documentation/operators/src/not-found.md b/documentation/operators/src/not-found.md new file mode 100644 index 0000000000..aafb70cba5 --- /dev/null +++ b/documentation/operators/src/not-found.md @@ -0,0 +1,11 @@ +# Page Not Found + +You seem to have followed a link to a page that no longer exists. Our documentation is changing and growing over time, so this page has most likely been moved somewhere else. + +For node setup guides, see the [Operator Guides book](https://nymtech.net/operators). + +For developer tutorials, app guides, and demo and community apps, see the [Developer Portal](https://nymtech.net/developers). + +If you are looking for information on setting up and maintaining infrastructure nodes, check the sitemap on the left hand side of the screen. + +If you still can't find what you're looking for get in touch with us via [Matrix](https://matrix.to/#/#nym-community:nymtech.chat). \ No newline at end of file From 3da3f66ea38c6f41cd49210c88cef342acb24071 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 8 Aug 2023 14:10:44 +0200 Subject: [PATCH 111/146] * tweaked mixnode doc * removed token diagram from nyx validator doc --- documentation/docs/src/nodes/mixnode.md | 2 +- documentation/docs/src/nodes/validator.md | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index e849b141b1..44dc924d86 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -4,7 +4,7 @@ Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix mining', otherwise known simply as 'mixing'. -Mix nodes, after receiving a packet, decrypt its outer 'layer', and hold them for a variable amount of time before passing them to their next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were received. +Mix nodes, after receiving a packet, decrypt its outer 'layer' and hold it for a variable amount of time before passing it to its next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were received. Mix nodes are rewarded according to their quality of service, and their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) affected by this (as well as their delegation-based reputation - see [further reading](#further-reading) for more on this). diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index ceb0abdf8a..eba1666351 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -1,17 +1,11 @@ -- [x] TODO section of whitepaper - # Validators > The validator setup and maintenance guide has moved to the [Operator Guides book](https://nymtech.net/operators/nodes/validator-setup.html). -> We are currently working towards building up a closed set of reputable validators. You can ask us for coins to get in, but please don't be offended if we say no - validators are part of our system's core security and we are starting out with people we already know or who have a solid reputation. - -Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx blockchain records the ledger of NYM transactions and executes the smart contracts for distributing NYM rewards. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. +Validators secure the Nyx blockchain via Proof of Stake consensus. The Nyx blockchain records the ledger of `NYM` transactions and executes the smart contracts for distributing `NYM` rewards. The Nyx validators are run via the `nyxd` binary ([codebase](https://github.com/nymtech/nyxd)), maintaining a CosmWasm- and IBC-enabled blockchain. The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` token used to incentivise node operators is one of two native tokens of the chain, and the chain is where the [Mixnet](../nyx/mixnet-contract.md) and [Vesting](../nyx/vesting-contract.md) smart contracts are deployed. -![Nym Token Flow](../images/nym-token-flow.png) - ## Further Reading * Detailed info on Nyx Validators and token flow can be found in [Nym Reward Sharing for Mixnets document](https://nymtech.net/nym-cryptoecon-paper.pdf) in section 2.3 and 2.4. * For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). From 534c8f49d1f006cf5d400f7d0efc91fc9ebcdbbe Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 8 Aug 2023 14:16:48 +0200 Subject: [PATCH 112/146] added notes to ws and socks client subsections re: rust sdk --- documentation/docs/src/clients/overview.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/documentation/docs/src/clients/overview.md b/documentation/docs/src/clients/overview.md index 4bfc125b5c..c8d2db1503 100644 --- a/documentation/docs/src/clients/overview.md +++ b/documentation/docs/src/clients/overview.md @@ -23,19 +23,23 @@ At present, there are three Nym clients: 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 runs as a persistent process on a desktop or server machine. You can connect to it with **any language that supports websockets**. +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.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 [sdk](../sdk/typescript.md). +_The webassembly client is most easily used via the [Typescript SDK](../sdk/typescript.md)_. ### The SOCKS5 client -This client (`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). +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). -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. +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.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. From a93de8b4c59fadb702a3cf5ddcd4023cf682ff77 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Tue, 8 Aug 2023 14:19:29 +0200 Subject: [PATCH 113/146] updated vars in all books for next release version --- documentation/dev-portal/book.toml | 2 +- documentation/docs/book.toml | 2 +- documentation/operators/book.toml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index d8ede22a4a..8f44c978f4 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -49,8 +49,8 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` [preprocessor.variables.variables] minimum_rust_version = "1.66" # vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.25" wallet_release_version = "v1.2.7" +platform_release_version = "v1.1.27" [preprocessor.last-changed] command = "mdbook-last-changed" diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index 7dfd751b15..cda7e3db07 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -49,7 +49,7 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` [preprocessor.variables.variables] minimum_rust_version = "1.66" # vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.26" +platform_release_version = "v1.1.27" wallet_release_version = "v1.2.7" [preprocessor.last-changed] diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 2ce49e37bb..c39af18a65 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -49,8 +49,8 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install` [preprocessor.variables.variables] minimum_rust_version = "1.66" # vars for links: TODO think on how to streamline updating -platform_release_version = "v1.1.22" -wallet_release_version = "v1.2.5" +platform_release_version = "v1.1.27" +wallet_release_version = "v1.2.7" [preprocessor.last-changed] From ee14dfc75e7f79b20bd79572a3b8ba98ec29cd5f Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 11:29:34 +0200 Subject: [PATCH 114/146] added coc and license --- documentation/operators/src/SUMMARY.md | 5 +++++ documentation/operators/src/coc.md | 17 +++++++++++++++++ documentation/operators/src/licensing.md | 5 +++++ 3 files changed, 27 insertions(+) create mode 100644 documentation/operators/src/coc.md create mode 100644 documentation/operators/src/licensing.md diff --git a/documentation/operators/src/SUMMARY.md b/documentation/operators/src/SUMMARY.md index a3f55376c8..82345c6f49 100644 --- a/documentation/operators/src/SUMMARY.md +++ b/documentation/operators/src/SUMMARY.md @@ -20,3 +20,8 @@ - [Troubleshooting](./nodes/troubleshooting.md) - [FAQ](./faq.md) +--- +# Misc. +- [Code of Conduct](coc.md) +- [Licensing](licensing.md) +--- diff --git a/documentation/operators/src/coc.md b/documentation/operators/src/coc.md new file mode 100644 index 0000000000..f8771a73bf --- /dev/null +++ b/documentation/operators/src/coc.md @@ -0,0 +1,17 @@ +# Code of Conduct + +We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic. + +Please avoid using overtly sexual aliases or other nicknames that might detract from a friendly, safe and welcoming environment for all. + +Please be kind and courteous. There’s no need to be mean or rude. + +Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer. + +Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. + +We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behaviour. We interpret the term “harassment” as including the definition in the Citizen Code of Conduct; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don’t tolerate behaviour that excludes people in socially marginalized groups. + +Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the Rust moderation team immediately. Whether you’re a regular contributor or a newcomer, we care about making this community a safe place for you and we’ve got your back. + +Likewise any spamming, trolling, flaming, baiting or other attention-stealing behaviour is not welcome. diff --git a/documentation/operators/src/licensing.md b/documentation/operators/src/licensing.md new file mode 100644 index 0000000000..2e8612d4d4 --- /dev/null +++ b/documentation/operators/src/licensing.md @@ -0,0 +1,5 @@ +# Licensing + +Nym is Free Software released under the Apache License V2. + +All of the contributions of the Nym core developers are © Nym Technologies SA. If you are interested in talking to us about other licenses, please get in touch. From 7065f870ebc6be75cf26151bad67211c64a28515 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 11:29:57 +0200 Subject: [PATCH 115/146] removed glossary file: needs rework --- documentation/dev-portal/src/SUMMARY.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/dev-portal/src/SUMMARY.md b/documentation/dev-portal/src/SUMMARY.md index 0e0c02bc58..8184038624 100644 --- a/documentation/dev-portal/src/SUMMARY.md +++ b/documentation/dev-portal/src/SUMMARY.md @@ -45,10 +45,9 @@ - [Community Applications and Guides](community-resources/community-applications-and-guides.md) - [Change Service Grantee Information](info-request.md) - [Rewards FAQ](community-resources/rewards-faq.md) ---- +--- # Misc. -- [Glossary](glossary.md) - [Code of Conduct](coc.md) - [Licensing](licensing.md) --- From 905318ad27cf63ec611fe23b74bd558d47d7c672 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 11:30:12 +0200 Subject: [PATCH 116/146] final tweaks --- documentation/docs/src/nodes/gateway.md | 4 ++-- documentation/docs/src/nodes/mixnode.md | 2 +- documentation/docs/src/nodes/validator.md | 3 --- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/documentation/docs/src/nodes/gateway.md b/documentation/docs/src/nodes/gateway.md index 814c550d4c..3634c36652 100644 --- a/documentation/docs/src/nodes/gateway.md +++ b/documentation/docs/src/nodes/gateway.md @@ -3,8 +3,8 @@ > The gateway setup and maintenance guide has migrated to the [Operator Guides book](https://nymtech.net/operators/nodes/gateway-setup.html). 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. 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 egress point for mixnet traffic, and always receive mixnet traffic from it (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. +* 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. ## Further Reading * [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 4.2 diff --git a/documentation/docs/src/nodes/mixnode.md b/documentation/docs/src/nodes/mixnode.md index 44dc924d86..b093c6f0b4 100644 --- a/documentation/docs/src/nodes/mixnode.md +++ b/documentation/docs/src/nodes/mixnode.md @@ -6,7 +6,7 @@ Mix nodes are the backbone of the mixnet. These are the nodes that perform 'mix Mix nodes, after receiving a packet, decrypt its outer 'layer' and hold it for a variable amount of time before passing it to its next destination - either another mix node, or a gateway. In doing so, they 'mix' packets by sending them to their next destination in a different order than they were received. -Mix nodes are rewarded according to their quality of service, and their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) affected by this (as well as their delegation-based reputation - see [further reading](#further-reading) for more on this). +Mix nodes are rewarded according to their quality of service, and the probability of their inclusion in the active set (i.e. the nodes that mix traffic for the next epoch) is also affected by this (as well as their delegation-based reputation - see the [Mix node deepdive](#further-reading) below for more on this). ## (Coming soon) Mixing: a Step-by-Step Breakdown diff --git a/documentation/docs/src/nodes/validator.md b/documentation/docs/src/nodes/validator.md index eba1666351..855cf21700 100644 --- a/documentation/docs/src/nodes/validator.md +++ b/documentation/docs/src/nodes/validator.md @@ -8,8 +8,5 @@ The blockchain plays a supporting but fundamental role in the mixnet: the `NYM` ## Further Reading * Detailed info on Nyx Validators and token flow can be found in [Nym Reward Sharing for Mixnets document](https://nymtech.net/nym-cryptoecon-paper.pdf) in section 2.3 and 2.4. -* For more detailed calculation, read our blog post [Nym Token Economics update](https://blog.nymtech.net/nym-token-economics-update-fedff0ed5267). -* More info on staking can be found [here](https://blog.nymtech.net/staking-in-nym-introducing-mainnet-mixmining-f9bb1cbc7c36). -* [Here](https://blog.nymtech.net/want-to-stake-in-nym-here-is-how-to-choose-a-mix-node-to-delegate-nym-to-c3b862add165) is more info on how to choose a mix node for delegation. * Our [quarterly update](https://blog.nymtech.net/quarterly-token-economic-parameter-update-b2862948710f) on token economics from July 2023. * [Nym Whitepaper](https://nymtech.net/nym-whitepaper.pdf) section 3.1 \ No newline at end of file From b1c3264f69894685bbb24f004481c9a41cff4e4f Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 11:47:11 +0200 Subject: [PATCH 117/146] removed doubled header --- documentation/operators/src/preliminary-steps.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/documentation/operators/src/preliminary-steps.md b/documentation/operators/src/preliminary-steps.md index ec13e7ea59..2f7cb2008b 100644 --- a/documentation/operators/src/preliminary-steps.md +++ b/documentation/operators/src/preliminary-steps.md @@ -1,8 +1,6 @@ # Preliminary Steps -> The Nym `mix node`, `gateway` and `network-requester` binaries were built in the [building nym](./binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. - -## Preliminary steps +> The Nym `mixnode`, `gateway` and `network-requester` binaries were built in the [building nym](./binaries/building-nym.md) section. If you haven't yet built Nym and want to run the code, go there first. There are a couple of steps that need completing before starting to set up your mix node, gateway or a network requester: From 074e27291b75e14b2639ba683817add8e0fdf935 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 12:51:34 +0200 Subject: [PATCH 118/146] updated links in operator binaries compilation list --- documentation/operators/src/binaries/building-nym.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/binaries/building-nym.md b/documentation/operators/src/binaries/building-nym.md index 8610fcb63a..20c157ad21 100644 --- a/documentation/operators/src/binaries/building-nym.md +++ b/documentation/operators/src/binaries/building-nym.md @@ -55,12 +55,12 @@ NETWORK=sandbox cargo build --release # build your binaries with **sandbox** con Quite a bit of stuff gets built. The key working parts are: -* [mix node](../nodes/mix-node-setup.md): `nym-mixnode` -* [gateway node](../nodes/gateway-setup.md): `nym-gateway` +* [mix node](../nodes/mix-node.md): `nym-mixnode` +* [gateway node](../nodes/gateway.md): `nym-gateway` * [websocket client](https://nymtech.net/docs/clients/websocket-client.html): `nym-client` * [socks5 client](https://nymtech.net/docs/clients/socks5-client.html): `nym-socks5-client` * [webassembly client](https://nymtech.net/docs/clients/webassembly-client.html): `webassembly-client` -* [network requester](../nodes/network-requester-setup.md): `nym-network-requester` +* [network requester](../nodes/network-requester.md): `nym-network-requester` * [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli` The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages. From 740846befcfbb8567bb3fb282a95816e032b09d4 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 13:25:37 +0200 Subject: [PATCH 119/146] fixed links --- documentation/operators/src/binaries/building-nym.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/documentation/operators/src/binaries/building-nym.md b/documentation/operators/src/binaries/building-nym.md index 20c157ad21..8610fcb63a 100644 --- a/documentation/operators/src/binaries/building-nym.md +++ b/documentation/operators/src/binaries/building-nym.md @@ -55,12 +55,12 @@ NETWORK=sandbox cargo build --release # build your binaries with **sandbox** con Quite a bit of stuff gets built. The key working parts are: -* [mix node](../nodes/mix-node.md): `nym-mixnode` -* [gateway node](../nodes/gateway.md): `nym-gateway` +* [mix node](../nodes/mix-node-setup.md): `nym-mixnode` +* [gateway node](../nodes/gateway-setup.md): `nym-gateway` * [websocket client](https://nymtech.net/docs/clients/websocket-client.html): `nym-client` * [socks5 client](https://nymtech.net/docs/clients/socks5-client.html): `nym-socks5-client` * [webassembly client](https://nymtech.net/docs/clients/webassembly-client.html): `webassembly-client` -* [network requester](../nodes/network-requester.md): `nym-network-requester` +* [network requester](../nodes/network-requester-setup.md): `nym-network-requester` * [nym-cli tool](https://nymtech.net/docs/tools/nym-cli.html): `nym-cli` The repository also contains Typescript applications which aren't built in this process. These can be built by following the instructions on their respective docs pages. From df9aec15546a1929b2c1723109fbee85314c0bac Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 14:11:06 +0200 Subject: [PATCH 120/146] updated grantee info update link --- documentation/dev-portal/src/info-request.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/documentation/dev-portal/src/info-request.md b/documentation/dev-portal/src/info-request.md index 551da83bf3..e3edbdc3de 100644 --- a/documentation/dev-portal/src/info-request.md +++ b/documentation/dev-portal/src/info-request.md @@ -1,6 +1,6 @@ # Change Service Grantee Information -The Nym Service Grantees User Information Update Form allows Service Grantees to update their information with the Nym team. The form allows grantees to update their current: +If you wish to update any of the following information: - `Email Address` - `NYM address` - `Network Requester` @@ -9,10 +9,6 @@ The Nym Service Grantees User Information Update Form allows Service Grantees to - `Service` - `Payment Address` -Complete and submit your form so the Nym team to keep track of the service grantees and your current information, ensuring that deliver payments and handle other logistics smooth and accurately. - -> ⚠️ Service Grantee User Information will be updated by our team by 5pm UTC between Mon - Fri. - - +Please reach out either in the `#service-grantees` channel on Discord or on [Matrix](https://matrix.to/#/#nym-community:nymtech.chat). From 035535058e228079cd22dfd820532d7f70a9246b Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 14:24:57 +0200 Subject: [PATCH 121/146] fixed incorrect import path for chat app --- documentation/docs/src/sdk/typescript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/docs/src/sdk/typescript.md b/documentation/docs/src/sdk/typescript.md index eed1167692..5ce939e858 100644 --- a/documentation/docs/src/sdk/typescript.md +++ b/documentation/docs/src/sdk/typescript.md @@ -47,7 +47,7 @@ There are multiple example projects in [`nym/sdk/typescript/examples/`](https:// The best place to start if you just want to quickly get a basic frontend up and running with which to experiment is `examples/plain-html`: ```typescript -{{#include ../../../../sdk/typescript/examples/plain-html/src/index.ts}} +{{#include ../../../../sdk/typescript/examples/chat-app/plain-html/src/index.ts}} ``` As you can see, all that is required to create an ephemeral keypair and connect to the mixnet is creating a client and then subscribing to the mixnet events coming down the websocket, and adding logic to deal with them. From 230d8aa170ad2121557033edaa42a26b9d226d53 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Wed, 9 Aug 2023 14:25:29 +0200 Subject: [PATCH 122/146] changed out of date var 'mix_node_release_version' to 'platform_release_version --- documentation/operators/src/nodes/maintenance.md | 2 +- documentation/operators/src/nodes/mix-node-setup.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index 911a6825af..bb7a0f0ea7 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -230,7 +230,7 @@ Here's a systemd service file to do that: ```ini [Unit] -Description=Nym Mixnode ({{mix_node_release_version}}) +Description=Nym Mixnode ({{platform_release_version}}) StartLimitInterval=350 StartLimitBurst=10 diff --git a/documentation/operators/src/nodes/mix-node-setup.md b/documentation/operators/src/nodes/mix-node-setup.md index 1c70383a61..a50c5cac13 100644 --- a/documentation/operators/src/nodes/mix-node-setup.md +++ b/documentation/operators/src/nodes/mix-node-setup.md @@ -87,13 +87,13 @@ Mixnode configuration completed. |_| |_|\__, |_| |_| |_| |___/ - (nym-mixnode - version {{mix_node_release_version}}) + (nym-mixnode - version {{platform_release_version}}) -Identity Key: DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"{{mix_node_release_version}}"},"cost_params +Identity Key: DhmUYedPZvhP9MMwXdNpPaqCxxTQgjAg78s2nqtTTiNF","version":"{{platform_release_version}}"},"cost_params Sphinx Key: CfZSy1jRfrfiVi9JYexjFWPqWkKoY72t7NdpWaq37K8Z Host: 62.240.134.189 (bind address: 62.240.134.189) -Version: {{mix_node_release_version}} +Version: {{platform_release_version}} Mix Port: 1789, Verloc port: 1790, Http Port: 8000 ``` ~~~ @@ -134,7 +134,7 @@ It will look something like this: |_| |_|\__, |_| |_| |_| |___/ - (nym-mixnode - version {{mix_node_release_version}}) + (nym-mixnode - version {{platform_release_version}}) >>> attempting to sign 22Z9wt4PyiBCbMiErxj5bBa4VCCFsjNawZ1KnLyMeV9pMUQGyksRVANbXHjWndMUaXNRnAuEVJW6UCxpRJwZe788hDt4sicsrv7iAXRajEq19cWPVybbUqgeo76wbXbCbRdg1FvVKgYZGZZp8D72p5zWhKSBRD44qgCrqzfV1SkiFEhsvcLUvZATdLRocAUL75KmWivyRiQjCE1XYEWyRH9yvRYn4TymWwrKVDtEB63zhHjATN4QEi2E5qSrSbBcmmqatXsKakbgSbQoLsYygcHx7tkwbQ2HDYzeiKP1t16Rhcjn6Ftc2FuXUNnTcibk2LQ1hiqu3FAq31bHUbzn2wiaPfm4RgqTwGM4eqnjBofwR3251wQSxbYwKUYwGsrkweRcoPuEaovApR9R19oJ7GVG5BrKmFwZWX3XFVuECe8vt1x9MY7DbQ3xhAapsHhThUmzN6JPPU4qbQ3PdMt3YVWy6oRhap97ma2dPMBaidebfgLJizpRU3Yu7mtb6E8vgi5Xnehrgtd35gitoJqJUY5sB1p6TDPd6vk3MVU1zqusrke7Lvrud4xKfCLqp672Bj9eGb2wPwow643CpHuMkhigfSWsv9jDq13d75EGTEiprC2UmWTzCJWHrDH7ka68DZJ5XXAW67DBewu7KUm1jrJkNs55vS83SWwm5RjzQLVhscdtCH1Bamec6uZoFBNVzjs21o7ax2WHDghJpGMxFi6dmdMCZpqn618t4 From a2445183bf3d90c146655cee90ed103c342f0abb Mon Sep 17 00:00:00 2001 From: Gala Date: Wed, 9 Aug 2023 17:56:36 +0200 Subject: [PATCH 123/146] theme change --- documentation/dev-portal/book.toml | 6 ++-- documentation/dev-portal/custom.css | 38 +++++++++++++++++++++++ documentation/dev-portal/last-changed.css | 6 ---- 3 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 documentation/dev-portal/custom.css delete mode 100644 documentation/dev-portal/last-changed.css diff --git a/documentation/dev-portal/book.toml b/documentation/dev-portal/book.toml index 8f44c978f4..172868cbe8 100644 --- a/documentation/dev-portal/book.toml +++ b/documentation/dev-portal/book.toml @@ -17,7 +17,7 @@ src = "src" # - run `mdbook build`: this will rebuild the `./theme` directory # - change value of `turn-off` back to `true` [preprocessor.theme] -pagetoc = true +pagetoc = true # some variables related (defined in theme/css/variables.css) # `content-max-width` + `pagetoc-width` = 95% seems the best pagetoc-width = "13%" @@ -37,7 +37,7 @@ nav-chapters-min-width = "auto" chapter-line-height = "2em" section-line-height = "1.5em" -# # if true, never read and touch the files in theme dir +# if true, never read and touch the files in theme dir turn-off = false [preprocessor.admonish] @@ -77,7 +77,7 @@ curly-quotes = true # mathjax-support = false # useful if we want to pull equations in ? copy-fonts = true no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "custom.css"] additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" diff --git a/documentation/dev-portal/custom.css b/documentation/dev-portal/custom.css new file mode 100644 index 0000000000..0174c7796c --- /dev/null +++ b/documentation/dev-portal/custom.css @@ -0,0 +1,38 @@ +:root { + --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", + monospace, monospace; +} +.coal { + --bg: #121726; + --fg: #f2f2f2; + + --sidebar-bg: #121726; + --sidebar-fg: #f2f2f2; + --sidebar-active: #fb6e4e; + + --icons: #f2f2f2; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +.light { + --bg: #f4f6f8; + --fg: #121726; + + --sidebar-bg: #f4f6f8; + --sidebar-fg: #121726; + --sidebar-active: #fb6e4e; + + --icons: #121726; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 5px 0; +} \ No newline at end of file diff --git a/documentation/dev-portal/last-changed.css b/documentation/dev-portal/last-changed.css deleted file mode 100644 index 0c4228de32..0000000000 --- a/documentation/dev-portal/last-changed.css +++ /dev/null @@ -1,6 +0,0 @@ -footer { - font-size: 0.8em; - text-align: center; - border-top: 1px solid black; - padding: 5px 0; - } \ No newline at end of file From 8b65e44767eea8948a4e0f9d937cf3c0653a519d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 10 Aug 2023 14:40:15 +0100 Subject: [PATCH 124/146] using stricter version requirements for mdbook and mdbook-variables --- .github/workflows/ci-dev.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-dev.yml b/.github/workflows/ci-dev.yml index 80688c2ccc..90470e8c3e 100644 --- a/.github/workflows/ci-dev.yml +++ b/.github/workflows/ci-dev.yml @@ -23,10 +23,13 @@ jobs: with: toolchain: stable - name: Install mdbook - run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook) + # to make sure we don't run into toml dependency issue, make sure to pull fixed mdbook that depends on old 0.5 + # and OLD mdbook-variables that uses the same dependency + # (mdbook-variables 0.2.3 updated to 0.7 which was used by mdbook incorrectly and extremely briefly) + run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) - name: Install mdbook plugins run: | - cargo install --vers "^0.2.0" mdbook-variables && cargo install \ + cargo install --vers "=0.2.2" mdbook-variables && cargo install \ --vers "^1.8.0" mdbook-admonish && cargo install --vers \ "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ && cargo install --vers "^0.7.7" mdbook-linkcheck From b0d5bacafd04de56c354396a844122b53e9a8d1c Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:31:56 +0200 Subject: [PATCH 125/146] picked theme changes:dev-portal -> operators; theme finished --- documentation/operators/book.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index c39af18a65..52d1379fa8 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -18,7 +18,7 @@ src = "src" # - run `mdbook build`: this will rebuild the `./theme` directory # - change value of `turn-off` back to `true` [preprocessor.theme] -pagetoc = true +pagetoc = true # some variables related (defined in theme/css/variables.css) pagetoc-width = "13%" content-max-width = "70%" # 82 @@ -87,7 +87,7 @@ curly-quotes = true # mathjax-support = false # useful if we want to pull equations in copy-fonts = true no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./last-changed.css"] +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css","./custom.css"] additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" From 1f2a2c37ab29de430bde0ab81d33689f6c8385f0 Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:32:13 +0200 Subject: [PATCH 126/146] picked theme changes:dev-portal -> operators; theme finished --- documentation/operators/custom.css | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 documentation/operators/custom.css diff --git a/documentation/operators/custom.css b/documentation/operators/custom.css new file mode 100644 index 0000000000..170e91dd26 --- /dev/null +++ b/documentation/operators/custom.css @@ -0,0 +1,38 @@ +:root { + --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", + monospace, monospace; +} +.coal { + --bg: #121726; + --fg: #f2f2f2; + + --sidebar-bg: #121726; + --sidebar-fg: #f2f2f2; + --sidebar-active: #fb6e4e; + + --icons: #f2f2f2; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +.light { + --bg: #f4f6f8; + --fg: #121726; + + --sidebar-bg: #f4f6f8; + --sidebar-fg: #121726; + --sidebar-active: #fb6e4e; + + --icons: #121726; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 5px 0; +} From 54ff3ee987bac964f106299a82821b524c2d1bcd Mon Sep 17 00:00:00 2001 From: serinko <97586125+serinko@users.noreply.github.com> Date: Thu, 10 Aug 2023 18:39:04 +0200 Subject: [PATCH 127/146] applied theme changes:dev-portal -> docs --- documentation/docs/book.toml | 2 +- documentation/docs/custom.css | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 documentation/docs/custom.css diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index cda7e3db07..ce666bddf2 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -85,7 +85,7 @@ curly-quotes = true # mathjax-support = false # useful if we want to pull equations in copy-fonts = true no-section-label = false -additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"] +additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "./custom.css"] additional-js = ["theme/pagetoc.js"] git-repository-url = "https://github.com/nymtech/nym" git-repository-icon = "fa-github" diff --git a/documentation/docs/custom.css b/documentation/docs/custom.css new file mode 100644 index 0000000000..170e91dd26 --- /dev/null +++ b/documentation/docs/custom.css @@ -0,0 +1,38 @@ +:root { + --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", + monospace, monospace; +} +.coal { + --bg: #121726; + --fg: #f2f2f2; + + --sidebar-bg: #121726; + --sidebar-fg: #f2f2f2; + --sidebar-active: #fb6e4e; + + --icons: #f2f2f2; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +.light { + --bg: #f4f6f8; + --fg: #121726; + + --sidebar-bg: #f4f6f8; + --sidebar-fg: #121726; + --sidebar-active: #fb6e4e; + + --icons: #121726; + --icons-hover: #fb6e4e; + + --links: #fb6e4e; +} + +footer { + font-size: 0.8em; + text-align: center; + border-top: 1px solid black; + padding: 5px 0; +} From f569ba1c1725136b5ad9893e0a9c69eab06287b7 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 10:16:37 +0200 Subject: [PATCH 128/146] pull fix from ci-dev.yml to ci-docs.yml --- .github/workflows/ci-docs.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index 2523013204..5d7874833b 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -27,14 +27,13 @@ jobs: command: build args: --workspace --release --all - name: Install mdbook - run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook) + run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) - name: Install mdbook plugins run: | - cargo install --vers "^0.2.0" mdbook-variables && cargo install \ + cargo install --vers "=0.2.2" mdbook-variables && cargo install \ --vers "^1.8.0" mdbook-admonish && cargo install --vers \ - "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \ - mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \ - cargo install --vers "^0.5.0" mdbook-cmdrun + "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ + && cargo install --vers "^0.7.7" mdbook-linkcheck - name: Clean website run: cd documentation/docs && mdbook clean - name: Build website From 84ad777c4209ce46d0d100b856bb2670c50df290 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 10:53:34 +0200 Subject: [PATCH 129/146] added workflow_dispatch to ci for dev-portal and docs --- .github/workflows/cd-dev.yml | 1 + .github/workflows/cd-docs.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/cd-dev.yml b/.github/workflows/cd-dev.yml index 0ca463345f..664f3cd79e 100644 --- a/.github/workflows/cd-dev.yml +++ b/.github/workflows/cd-dev.yml @@ -1,6 +1,7 @@ name: CD dev-portal on: + workflow_dispatch: push: branches: master paths: diff --git a/.github/workflows/cd-docs.yml b/.github/workflows/cd-docs.yml index 782a2c196d..b3f15ab265 100644 --- a/.github/workflows/cd-docs.yml +++ b/.github/workflows/cd-docs.yml @@ -1,6 +1,7 @@ name: CD docs on: + workflow_dispatch: push: branches: master paths: From 96e2712039df26af696239c0e88acb2ee5c8af3b Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 12:29:20 +0200 Subject: [PATCH 130/146] reintroduced linkchecker + fixed broken links --- documentation/docs/book.toml | 4 ++-- documentation/docs/src/architecture/network-overview.md | 2 +- documentation/docs/src/binaries/building-nym.md | 2 +- documentation/docs/src/clients/socks5-client.md | 6 +++--- documentation/docs/src/nyx/ledger-live.md | 2 +- documentation/docs/src/nyx/rpc-node.md | 2 +- documentation/docs/src/wallet/cli-wallet.md | 4 ++-- documentation/operators/book.toml | 4 ++-- documentation/operators/src/nodes/maintenance.md | 2 +- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/documentation/docs/book.toml b/documentation/docs/book.toml index ce666bddf2..6d22440ee3 100644 --- a/documentation/docs/book.toml +++ b/documentation/docs/book.toml @@ -119,5 +119,5 @@ expand = true # partial words will match longer terms heading-split-level = 3 # link results to heading levels copy-js = true # include Javascript code for search -# [output.linkcheck] -# warning-policy = "warn" +[output.linkcheck] +warning-policy = "warn" diff --git a/documentation/docs/src/architecture/network-overview.md b/documentation/docs/src/architecture/network-overview.md index fab4655e09..3a69f78be7 100644 --- a/documentation/docs/src/architecture/network-overview.md +++ b/documentation/docs/src/architecture/network-overview.md @@ -26,7 +26,7 @@ The mixnet - the different pieces of software that your traffic will pass throug * **Gateways** act as message storage for clients which may go offline and come back online again, and defend against denial of service attacks. The default gateway implementation included in the Nym platform code holds packets for later retrieval. For many applications (such as simple chat), this is usable out of the box, as it provides a place that potentially offline clients can retrieve packets from. The access token allows clients to pull messages from the gateway node. -* **Services** are applications that communicate with nym clients, listening and sending traffic to the mixnet. This is an umbrella term for a variety of different pieces of code, such as the [network requester](../nodes/network-requester-setup.md) binary. +* **Services** are applications that communicate with nym clients, listening and sending traffic to the mixnet. This is an umbrella term for a variety of different pieces of code, such as the [network requester](../nodes/network-requester.md) binary. * **Nyx Blockchain Validators** secure the network with proof-of-stake Sybil defenses, determine which nodes are included within the network, and work together to create Coconut threshold credentials which provide anonymous access to data and resources. They also produce blocks and secure the Nyx Blockchain. Initially, this chain was used only to house the CosmWasm smart contracts keeping track of Nym's network topology, token vesting contracts, and the `NYM` token itself. In recent months, we've decided to expand the role of Nyx and instead expand its role by making it an open smart contract platform for anyone to upload CosmWasm smart contracts to. Validators also provide privacy-enhanced credentials based on the testimony of a set of decentralized, blockchain-based issuing authorities. Nym validators use the [Coconut](https://arxiv.org/abs/1802.07344) [signature scheme](https://en.wikipedia.org/wiki/Digital_signature) to issue credentials. This allows privacy apps to generate anonymous resource claims through decentralised authorities, then use them with Service Providers. diff --git a/documentation/docs/src/binaries/building-nym.md b/documentation/docs/src/binaries/building-nym.md index 06edd54a2f..e2c970bd00 100644 --- a/documentation/docs/src/binaries/building-nym.md +++ b/documentation/docs/src/binaries/building-nym.md @@ -8,7 +8,7 @@ Nym has two main codebases: - the [Nym platform](https://github.com/nymtech/nym), written in Rust. This contains all of our code _except_ for the validators. - the [Nym validators](https://github.com/nymtech/nyxd), written in Go. -> This page details how to build the main Nym platform code. **If you want to build and run a validator, [go here](../nodes/validator-setup.md) instead.** +> This page details how to build the main Nym platform code. **If you want to build and run a validator, [go here](../nodes/validator.md) instead.** ## Prerequisites - Debian/Ubuntu: `pkg-config`, `build-essential`, `libssl-dev`, `curl`, `jq`, `git` diff --git a/documentation/docs/src/clients/socks5-client.md b/documentation/docs/src/clients/socks5-client.md index e8bce0e948..e3a5759685 100644 --- a/documentation/docs/src/clients/socks5-client.md +++ b/documentation/docs/src/clients/socks5-client.md @@ -60,7 +60,7 @@ There are 2 pieces of software that work together to send SOCKS traffic through 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-setup.md). Packets are shuffled and mixed as they transit the mixnet. +* 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! @@ -100,9 +100,9 @@ Before you can use the client, you need to initalise a new instance of it, which 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 `--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-setup.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/). +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-setup.md#network-requester-whitelist): Keybase, Telegram, Electrum, Blockstream Green, and Helios. +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. diff --git a/documentation/docs/src/nyx/ledger-live.md b/documentation/docs/src/nyx/ledger-live.md index f7559b6fd2..031834fa24 100644 --- a/documentation/docs/src/nyx/ledger-live.md +++ b/documentation/docs/src/nyx/ledger-live.md @@ -4,7 +4,7 @@ Use the following instructions to interact with the Nyx blockchain - either with ## Prerequisites * Download and install [Ledger Live](https://www.ledger.com/ledger-live). -* Compile the `nyxd` binary as per the instructions [here](../nodes/validator-setup.md#building-the-nym-validator). Stop after you can successfully run `nyxd` and get the helptext in your console output. +* Compile the `nyxd` binary as per the instructions [here](https://nymtech.net/operators/nodes/validator-setup.md#building-the-nym-validator). Stop after you can successfully run `nyxd` and get the helptext in your console output. ## Prepare your Ledger App * Plug in your Ledger device diff --git a/documentation/docs/src/nyx/rpc-node.md b/documentation/docs/src/nyx/rpc-node.md index af76f1f927..dc48d68409 100644 --- a/documentation/docs/src/nyx/rpc-node.md +++ b/documentation/docs/src/nyx/rpc-node.md @@ -4,6 +4,6 @@ RPC Nodes (which might otherwise be referred to as 'Lite Nodes' or just 'Full No You may want to set up an RPC Node for querying the blockchain, or in order to have an endpoint that your app can use to send transactions. -In order to set up an RPC Node, simply follow the instructions to set up a [Validator](../nodes/validator-setup.md), but **exclude the `nyxd tx staking create-validator` command**. +In order to set up an RPC Node, simply follow the instructions to set up a [Validator](https://nymtech.net/operators/nodes/validator-setup.md), but **exclude the `nyxd tx staking create-validator` command**. If you want to fast-sync your node, check out the Polkachu snapshot and their other [resources](https://polkachu.com/seeds/nym). \ No newline at end of file diff --git a/documentation/docs/src/wallet/cli-wallet.md b/documentation/docs/src/wallet/cli-wallet.md index 3f713b1937..36670190a3 100644 --- a/documentation/docs/src/wallet/cli-wallet.md +++ b/documentation/docs/src/wallet/cli-wallet.md @@ -1,8 +1,8 @@ # CLI Wallet -If you have already read our validator setup and maintenance [documentation](../nodes/validator-setup.md) you will have seen that we compile and use the `nyxd` binary primarily for our validators. This binary can however be used for many other tasks, such as creating and using keypairs for wallets, or automated setups that require the signing and broadcasting of transactions. +If you have already read our validator setup and maintenance [documentation](../nodes/validator.md) you will have seen that we compile and use the `nyxd` binary primarily for our validators. This binary can however be used for many other tasks, such as creating and using keypairs for wallets, or automated setups that require the signing and broadcasting of transactions. ### Using `nyxd` binary as a CLI wallet -You can use the `nyxd` as a minimal CLI wallet if you want to set up an account (or multiple accounts). Just compile the binary as per the documentation, **stopping after** the [building your validator](../nodes/validator-setup.md#building-your-validator) step is complete. You can then run `nyxd keys --help` to see how you can set up and store different keypairs with which to interact with the Nyx blockchain. +You can use the `nyxd` as a minimal CLI wallet if you want to set up an account (or multiple accounts). Just compile the binary as per the documentation, **stopping after** the [building your validator](../nodes/validator.md) step is complete. You can then run `nyxd keys --help` to see how you can set up and store different keypairs with which to interact with the Nyx blockchain. For more on interacting with the chain, see the [Interacting with Nyx Chain and Smart Contracts](../nyx/interacting-with-chain.md) page. diff --git a/documentation/operators/book.toml b/documentation/operators/book.toml index 52d1379fa8..be7233c069 100644 --- a/documentation/operators/book.toml +++ b/documentation/operators/book.toml @@ -121,5 +121,5 @@ expand = true # partial words will match longer terms heading-split-level = 3 # link results to heading levels copy-js = true # include Javascript code for search -# [output.linkcheck] -# warning-policy = "warn" +[output.linkcheck] +warning-policy = "warn" diff --git a/documentation/operators/src/nodes/maintenance.md b/documentation/operators/src/nodes/maintenance.md index bb7a0f0ea7..c955975118 100644 --- a/documentation/operators/src/nodes/maintenance.md +++ b/documentation/operators/src/nodes/maintenance.md @@ -46,7 +46,7 @@ You can either do this graphically via the Desktop Wallet, or the CLI. ![Node Settings Page](../images/wallet-screenshots/node_settings.png) ### Updating node information via the CLI -If you want to bond your `` via the CLI, then check out the [relevant section in the Nym CLI](../../documentation/docs/src/tools/nym-cli.md#upgrade-a-mix-node) docs. +If you want to bond your `` via the CLI, then check out the [relevant section in the Nym CLI](https://nymtech.net/docs/tools/nym-cli.md#upgrade-a-mix-node) docs. ### Upgrading Network Requester to >= v1.1.10 from Date: Fri, 11 Aug 2023 12:29:30 +0200 Subject: [PATCH 131/146] rough staging sh script --- documentation/staging.sh | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 documentation/staging.sh diff --git a/documentation/staging.sh b/documentation/staging.sh new file mode 100755 index 0000000000..07ca2de1d2 --- /dev/null +++ b/documentation/staging.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# commands assume you run script from `nym/documentation/` + +# array of project dirs +declare -a projects=("docs" "dev-portal" "operators") + +## now loop through the above array +for i in "${projects[@]}" +do + # cd to project dir + cd "./$i" && + # little sanity checks + echo $(pwd) && echo $(mdbook --version) && + # clean old book + rm -rf ./book/ + # build book + mdbook build + # check for destination, if ! then mkdir & check again else echo thumbs up + if [ ! -d ../../dist/docs/$i ]; then + echo "dest doesn't exist: creating dir" + mkdir -p ../../dist/docs/$i + fi + if [ -d ../../dist/docs/$i ]; then + echo "cp destination exists, all good" + fi + # clean old dist/$i + rm -rf ../../dist/docs/$i + # move newly rendered book/ to dist + cp -r ./book/ ../../dist/docs/$i + # sanity check + ls -a ../../dist/docs/$i/html + # cd back to ../documentation/ + cd ../ +done \ No newline at end of file From 89ea3039d5d93fbf2cc6da61be4f791328ade1ef Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 12:30:41 +0200 Subject: [PATCH 132/146] removed unnecessary linkcheck rendering output from dist/ --- documentation/staging.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/staging.sh b/documentation/staging.sh index 07ca2de1d2..64fec07e47 100755 --- a/documentation/staging.sh +++ b/documentation/staging.sh @@ -27,9 +27,9 @@ do # clean old dist/$i rm -rf ../../dist/docs/$i # move newly rendered book/ to dist - cp -r ./book/ ../../dist/docs/$i + cp -r ./book/html/ ../../dist/docs/$i # sanity check - ls -a ../../dist/docs/$i/html + ls -a ../../dist/docs/$i/ # cd back to ../documentation/ cd ../ done \ No newline at end of file From a1a1970dc1fb37457b0178facc7ddd1957ea8a42 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 11 Aug 2023 13:08:19 +0200 Subject: [PATCH 133/146] updated readme with soon to be operator doc URL --- documentation/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/README.md b/documentation/README.md index 3330b3e969..e074f7cdfe 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -2,5 +2,6 @@ * `docs` contains technical documentation hosted at [https://nymtech.net/docs](https://nymtech.net/docs) * `dev-portal` contains developer documentation hosted at [https://nymtech.net/developers](https://nymtech.net/developers) +* `operators` contains node setup and maintenance guides hosted at [https://nymtech.net/operators](https://nymtech.net/operators) Each directory contains a readme with more information about running and contributing to the projects. Each is built with [`mdbook`](https://rust-lang.github.io/mdBook/index.html) - use `mdbook serve` to build and serve them (defaults to `localhost:3000`). From 0f43521497f076e3427cb7ae6e7ccdde3e415350 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 10:10:36 +0200 Subject: [PATCH 134/146] tweak --- documentation/staging.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/documentation/staging.sh b/documentation/staging.sh index 64fec07e47..87fe4d5b58 100755 --- a/documentation/staging.sh +++ b/documentation/staging.sh @@ -13,6 +13,7 @@ do # little sanity checks echo $(pwd) && echo $(mdbook --version) && # clean old book + echo "cleaning old book" rm -rf ./book/ # build book mdbook build @@ -27,9 +28,9 @@ do # clean old dist/$i rm -rf ../../dist/docs/$i # move newly rendered book/ to dist - cp -r ./book/html/ ../../dist/docs/$i + rsync -r ./book/html/ ../../dist/docs/$i # sanity check - ls -a ../../dist/docs/$i/ + ls -laF ../../dist/docs/ # cd back to ../documentation/ cd ../ -done \ No newline at end of file +done From c8516071fca4755edbf2bbda8d2783f6943142ac Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 14:36:22 +0200 Subject: [PATCH 135/146] removed developer portal specific files --- .github/workflows/cd-dev.yml | 77 ------------------------------------ .github/workflows/ci-dev.yml | 70 -------------------------------- 2 files changed, 147 deletions(-) delete mode 100644 .github/workflows/cd-dev.yml delete mode 100644 .github/workflows/ci-dev.yml diff --git a/.github/workflows/cd-dev.yml b/.github/workflows/cd-dev.yml deleted file mode 100644 index 664f3cd79e..0000000000 --- a/.github/workflows/cd-dev.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: CD dev-portal - -on: - workflow_dispatch: - push: - branches: master - paths: - - 'documentation/dev-portal/**' - -jobs: - build: - runs-on: custom-runner-linux - steps: - - uses: actions/checkout@v3 - - name: Install rsync - run: sudo apt-get install rsync - - uses: rlespinasse/github-slug-action@v3.x - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Install Rust stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - name: Install mdbook - run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook) - - name: Install mdbook plugins - run: | - cargo install --vers "^0.2.0" mdbook-variables && cargo install \ - --vers "^1.8.0" mdbook-admonish && cargo install --vers \ - "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \ - mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck - - name: Clean website - run: cd documentation/dev-portal && mdbook clean - - name: Build website - run: cd documentation/dev-portal && mdbook build - - name: Deploy branch master to dev - continue-on-error: true - uses: easingthemes/ssh-deploy@main - env: - SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }} - ARGS: "-rltgoDzvO --delete" - SOURCE: "documentation/dev-portal/book/html/" - REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }} - REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }} - TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/ - EXCLUDE: "/dist/, /node_modules/" - - name: Deploy branch master to prod - uses: easingthemes/ssh-deploy@main - env: - SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }} - ARGS: "-rltgoDzvO --delete" - SOURCE: "documentation/dev-portal/book/html/" - REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }} - REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }} - TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET_DEVP }}/ - EXCLUDE: "/dist/, /node_modules/" - - name: Matrix - Node Install - run: npm install - working-directory: .github/workflows/support-files - - name: Matrix - Send Notification - env: - NYM_NOTIFICATION_KIND: cd-dev - NYM_PROJECT_NAME: "Dev portal CD" - NYM_CI_WWW_BASE: "${{ secrets.NYM_CD_WWW_BASE }}" - NYM_CI_WWW_LOCATION: "${{ env.GITHUB_REF_SLUG }}" - GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}" - GIT_BRANCH: "${GITHUB_REF##*/}" - MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}" - MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}" - MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}" - MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}" - MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}" - IS_SUCCESS: "${{ job.status == 'success' }}" - uses: docker://keybaseio/client:stable-node - with: - args: .github/workflows/support-files/notifications/entry_point.sh diff --git a/.github/workflows/ci-dev.yml b/.github/workflows/ci-dev.yml deleted file mode 100644 index 90470e8c3e..0000000000 --- a/.github/workflows/ci-dev.yml +++ /dev/null @@ -1,70 +0,0 @@ -name: CI dev-portal - -on: - workflow_dispatch: - push: - branches-ignore: master - paths: - - 'documentation/dev-portal/**' - -jobs: - build: - runs-on: custom-runner-linux - steps: - - uses: actions/checkout@v3 - - name: Install rsync - run: sudo apt-get install rsync - - uses: rlespinasse/github-slug-action@v3.x - - uses: actions/setup-node@v3 - with: - node-version: 18 - - name: Install Rust stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - name: Install mdbook - # to make sure we don't run into toml dependency issue, make sure to pull fixed mdbook that depends on old 0.5 - # and OLD mdbook-variables that uses the same dependency - # (mdbook-variables 0.2.3 updated to 0.7 which was used by mdbook incorrectly and extremely briefly) - run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) - - name: Install mdbook plugins - run: | - cargo install --vers "=0.2.2" mdbook-variables && cargo install \ - --vers "^1.8.0" mdbook-admonish && cargo install --vers \ - "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ - && cargo install --vers "^0.7.7" mdbook-linkcheck - - name: Clean website - run: cd documentation/dev-portal && mdbook clean - - name: Build website - run: cd documentation/dev-portal && mdbook build - - name: Deploy branch to CI www - continue-on-error: true - uses: easingthemes/ssh-deploy@main - env: - SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }} - ARGS: "-rltgoDzvO --delete" - SOURCE: "documentation/dev-portal/book/html/" - REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }} - REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }} - TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/dev-portal-${{ env.GITHUB_REF_SLUG }} - EXCLUDE: "/dist/, /node_modules/" - - name: Matrix - Node Install - run: npm install - working-directory: .github/workflows/support-files - - name: Matrix - Send Notification - env: - NYM_NOTIFICATION_KIND: ci-dev - NYM_PROJECT_NAME: "Dev portal CI" - NYM_CI_WWW_BASE: "${{ secrets.NYM_CI_WWW_BASE }}" - NYM_CI_WWW_LOCATION: "dev-portal-${{ env.GITHUB_REF_SLUG }}" - GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}" - GIT_BRANCH: "${GITHUB_REF##*/}" - MATRIX_SERVER: "${{ secrets.MATRIX_SERVER }}" - MATRIX_ROOM: "${{ secrets.MATRIX_ROOM_DEVP }}" - MATRIX_USER_ID: "${{ secrets.MATRIX_USER_ID }}" - MATRIX_TOKEN: "${{ secrets.MATRIX_TOKEN }}" - MATRIX_DEVICE_ID: "${{ secrets.MATRIX_DEVICE_ID }}" - IS_SUCCESS: "${{ job.status == 'success' }}" - uses: docker://keybaseio/client:stable-node - with: - args: .github/workflows/support-files/notifications/entry_point.sh From ff4350ec9083d89eb9a8e11c41d7c49212797f4f Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 14:36:46 +0200 Subject: [PATCH 136/146] changed name of script for staging to dist/ --- documentation/{staging.sh => build_all_to_dist.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{staging.sh => build_all_to_dist.sh} (100%) diff --git a/documentation/staging.sh b/documentation/build_all_to_dist.sh similarity index 100% rename from documentation/staging.sh rename to documentation/build_all_to_dist.sh From 43dfb31eb22e946cbbbe078fbd78a5a09cccc1a6 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 14:37:14 +0200 Subject: [PATCH 137/146] modified ci script --- .github/workflows/ci-docs.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index 5d7874833b..f7c7af8d07 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -1,6 +1,7 @@ name: CI docs on: + workflow_dispatch: push: branches-ignore: master paths: @@ -34,21 +35,24 @@ jobs: --vers "^1.8.0" mdbook-admonish && cargo install --vers \ "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ && cargo install --vers "^0.7.7" mdbook-linkcheck - - name: Clean website - run: cd documentation/docs && mdbook clean - - name: Build website - run: cd documentation/docs && mdbook build + # - name: Clean website + # run: cd documentation/docs && mdbook clean + # - name: Build website + # run: cd documentation/docs && mdbook build + - name: Build all projects in documentation/ & move to ~/dist/docs/ + run: cd documentation && chmod +x build_all_to_dist.sh && ./build_all_to_dist.sh + continue-on-error: false - name: Deploy branch to CI www continue-on-error: true uses: easingthemes/ssh-deploy@main env: SSH_PRIVATE_KEY: ${{ secrets.CI_WWW_SSH_PRIVATE_KEY }} ARGS: "-rltgoDzvO --delete" - SOURCE: "documentation/docs/book/" + SOURCE: "dist/docs/" REMOTE_HOST: ${{ secrets.CI_WWW_REMOTE_HOST }} REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }} TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/docs-${{ env.GITHUB_REF_SLUG }} - EXCLUDE: "/dist/, /node_modules/" + EXCLUDE: "/node_modules/" - name: Matrix - Node Install run: npm install working-directory: .github/workflows/support-files From 7b3cbdcd447cfe17d8d9f2b10c3f00efbdabea29 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 15:36:11 +0200 Subject: [PATCH 138/146] cont. work on cicd --- .github/workflows/cd-docs.yml | 15 +++++++-------- .github/workflows/ci-docs.yml | 13 +++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/.github/workflows/cd-docs.yml b/.github/workflows/cd-docs.yml index b3f15ab265..25deaa0e82 100644 --- a/.github/workflows/cd-docs.yml +++ b/.github/workflows/cd-docs.yml @@ -36,31 +36,30 @@ jobs: "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \ mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \ cargo install --vers "^0.5.0" mdbook-cmdrun - - name: Clean website - run: cd documentation/docs && mdbook clean - - name: Build website - run: cd documentation/docs && mdbook build + - name: Build all projects in documentation/ & move to ~/dist/docs/ + run: cd documentation && ./build_all_to_dist.sh + continue-on-error: false - name: Deploy branch master to dev continue-on-error: true uses: easingthemes/ssh-deploy@main env: SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }} ARGS: "-rltgoDzvO --delete" - SOURCE: "documentation/docs/book/" + SOURCE: "dist/docs/" REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_DEV }} REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }} TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/ - EXCLUDE: "/dist/, /node_modules/" + EXCLUDE: "/node_modules/" - name: Deploy branch master to prod uses: easingthemes/ssh-deploy@main env: SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }} ARGS: "-rltgoDzvO --delete" - SOURCE: "documentation/docs/book/" + SOURCE: "dist/docs/" REMOTE_HOST: ${{ secrets.CD_WWW_REMOTE_HOST_PROD }} REMOTE_USER: ${{ secrets.CD_WWW_REMOTE_USER }} TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/ - EXCLUDE: "/dist/, /node_modules/" + EXCLUDE: "/node_modules/" - name: Matrix - Node Install run: npm install working-directory: .github/workflows/support-files diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index f7c7af8d07..f69da39928 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -31,16 +31,13 @@ jobs: run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) - name: Install mdbook plugins run: | - cargo install --vers "=0.2.2" mdbook-variables && cargo install \ + cargo install --vers "^0.2.0" mdbook-variables && cargo install \ --vers "^1.8.0" mdbook-admonish && cargo install --vers \ - "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ - && cargo install --vers "^0.7.7" mdbook-linkcheck - # - name: Clean website - # run: cd documentation/docs && mdbook clean - # - name: Build website - # run: cd documentation/docs && mdbook build + "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \ + mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \ + cargo install --vers "^0.5.0" mdbook-cmdrun - name: Build all projects in documentation/ & move to ~/dist/docs/ - run: cd documentation && chmod +x build_all_to_dist.sh && ./build_all_to_dist.sh + run: cd documentation && ./build_all_to_dist.sh continue-on-error: false - name: Deploy branch to CI www continue-on-error: true From c169971287c10d9af144949cd10fb346a0725b84 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 15:45:44 +0200 Subject: [PATCH 139/146] fixed mdbook versions --- .github/workflows/cd-docs.yml | 9 ++++----- .github/workflows/ci-docs.yml | 7 +++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/cd-docs.yml b/.github/workflows/cd-docs.yml index 25deaa0e82..f3e6e34da5 100644 --- a/.github/workflows/cd-docs.yml +++ b/.github/workflows/cd-docs.yml @@ -28,14 +28,13 @@ jobs: command: build args: --workspace --release --all - name: Install mdbook - run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4" mdbook) + run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) - name: Install mdbook plugins run: | - cargo install --vers "^0.2.0" mdbook-variables && cargo install \ + cargo install --vers "=0.2.2" mdbook-variables && cargo install \ --vers "^1.8.0" mdbook-admonish && cargo install --vers \ - "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \ - mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \ - cargo install --vers "^0.5.0" mdbook-cmdrun + "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ + && cargo install --vers "^0.7.7" mdbook-linkcheck - name: Build all projects in documentation/ & move to ~/dist/docs/ run: cd documentation && ./build_all_to_dist.sh continue-on-error: false diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index f69da39928..2ce019272a 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -31,11 +31,10 @@ jobs: run: (test -x $HOME/.cargo/bin/mdbook || cargo install --vers "^0.4.33" mdbook) - name: Install mdbook plugins run: | - cargo install --vers "^0.2.0" mdbook-variables && cargo install \ + cargo install --vers "=0.2.2" mdbook-variables && cargo install \ --vers "^1.8.0" mdbook-admonish && cargo install --vers \ - "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" \ - mdbook-theme && cargo install --vers "^0.7.7" mdbook-linkcheck && \ - cargo install --vers "^0.5.0" mdbook-cmdrun + "^0.1.2" mdbook-last-changed && cargo install --vers "^0.1.2" mdbook-theme \ + && cargo install --vers "^0.7.7" mdbook-linkcheck - name: Build all projects in documentation/ & move to ~/dist/docs/ run: cd documentation && ./build_all_to_dist.sh continue-on-error: false From 6ead19bd97058191f700b33507fb8353ff8de773 Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 15:55:59 +0200 Subject: [PATCH 140/146] added conditional push for master branch --- .github/workflows/cd-docs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cd-docs.yml b/.github/workflows/cd-docs.yml index f3e6e34da5..a1ba0c104a 100644 --- a/.github/workflows/cd-docs.yml +++ b/.github/workflows/cd-docs.yml @@ -50,6 +50,7 @@ jobs: TARGET: ${{ secrets.CD_WWW_REMOTE_TARGET }}/ EXCLUDE: "/node_modules/" - name: Deploy branch master to prod + if: github.ref == 'refs/heads/master' uses: easingthemes/ssh-deploy@main env: SSH_PRIVATE_KEY: ${{ secrets.CD_WWW_SSH_PRIVATE_KEY }} From b5f2ecd79e1e4e63afd4bc4244196c1f327df7e0 Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:24:57 +0100 Subject: [PATCH 141/146] Update build_all_to_dist.sh --- documentation/build_all_to_dist.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/build_all_to_dist.sh b/documentation/build_all_to_dist.sh index 87fe4d5b58..87834f5a3c 100755 --- a/documentation/build_all_to_dist.sh +++ b/documentation/build_all_to_dist.sh @@ -34,3 +34,4 @@ do # cd back to ../documentation/ cd ../ done +mv ../../dist/docs/dev-portal ../../dist/docs/developers From 404d2d9857f6c13fb1d7b993e743f1cf3487663b Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:28:42 +0100 Subject: [PATCH 142/146] Update build_all_to_dist.sh --- documentation/build_all_to_dist.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/build_all_to_dist.sh b/documentation/build_all_to_dist.sh index 87834f5a3c..721ed07e6a 100755 --- a/documentation/build_all_to_dist.sh +++ b/documentation/build_all_to_dist.sh @@ -34,4 +34,4 @@ do # cd back to ../documentation/ cd ../ done -mv ../../dist/docs/dev-portal ../../dist/docs/developers +mv ../dist/docs/dev-portal ../dist/docs/developers From ff4dbd09d0c1ef3513b882180cc71650d82f9ec5 Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:42:18 +0100 Subject: [PATCH 143/146] Update general.css --- documentation/dev-portal/theme/css/general.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/documentation/dev-portal/theme/css/general.css b/documentation/dev-portal/theme/css/general.css index 84dbfa3371..1d77810f5e 100644 --- a/documentation/dev-portal/theme/css/general.css +++ b/documentation/dev-portal/theme/css/general.css @@ -8,7 +8,7 @@ } html { - font-family: "Open Sans", sans-serif; + /* font-family: "Open Sans", sans-serif; */ color: var(--fg); background-color: var(--bg); text-size-adjust: none; @@ -16,13 +16,14 @@ html { } body { + font-family: "Open Sans", sans-serif; margin: 0; font-size: 1.5rem; overflow-x: hidden; } code { - font-family: var(--mono-font) !important; + font-family: var(--mono-font); font-size: 0.9em; } From 5f095d703d9c534e065ab9e2a5e109bff2215f61 Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:44:01 +0100 Subject: [PATCH 144/146] Update custom.css --- documentation/dev-portal/custom.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/documentation/dev-portal/custom.css b/documentation/dev-portal/custom.css index 0174c7796c..855f5eef5f 100644 --- a/documentation/dev-portal/custom.css +++ b/documentation/dev-portal/custom.css @@ -1,6 +1,5 @@ :root { - --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", - monospace, monospace; + --mono-font: Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace; } .coal { --bg: #121726; @@ -35,4 +34,4 @@ footer { text-align: center; border-top: 1px solid black; padding: 5px 0; -} \ No newline at end of file +} From 4ff69b77a91199a9a2a77c379e1d64bd51b86eed Mon Sep 17 00:00:00 2001 From: Mark Sinclair <14054343+mmsinclair@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:44:38 +0100 Subject: [PATCH 145/146] Update general.css --- documentation/dev-portal/theme/css/general.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/dev-portal/theme/css/general.css b/documentation/dev-portal/theme/css/general.css index 1d77810f5e..f8597e5767 100644 --- a/documentation/dev-portal/theme/css/general.css +++ b/documentation/dev-portal/theme/css/general.css @@ -8,7 +8,7 @@ } html { - /* font-family: "Open Sans", sans-serif; */ + font-family: "Open Sans", sans-serif; color: var(--fg); background-color: var(--bg); text-size-adjust: none; @@ -16,7 +16,6 @@ html { } body { - font-family: "Open Sans", sans-serif; margin: 0; font-size: 1.5rem; overflow-x: hidden; From e0b32e1cc9192d6c6a3fbe17e5e8f009ee800a2a Mon Sep 17 00:00:00 2001 From: mfahampshire Date: Fri, 18 Aug 2023 17:47:48 +0200 Subject: [PATCH 146/146] updated css font --- documentation/docs/custom.css | 3 +-- documentation/operators/custom.css | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/documentation/docs/custom.css b/documentation/docs/custom.css index 170e91dd26..855f5eef5f 100644 --- a/documentation/docs/custom.css +++ b/documentation/docs/custom.css @@ -1,6 +1,5 @@ :root { - --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", - monospace, monospace; + --mono-font: Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace; } .coal { --bg: #121726; diff --git a/documentation/operators/custom.css b/documentation/operators/custom.css index 170e91dd26..855f5eef5f 100644 --- a/documentation/operators/custom.css +++ b/documentation/operators/custom.css @@ -1,6 +1,5 @@ :root { - --mono-font: "Open Sans", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", - monospace, monospace; + --mono-font: Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace; } .coal { --bg: #121726;