diff --git a/docs/core-development/code-standards.md b/docs/core-development/code-standards.md new file mode 100644 index 000000000..97b0514e9 --- /dev/null +++ b/docs/core-development/code-standards.md @@ -0,0 +1,47 @@ +title: Code Standards +description: Learn about the code standards expected when contributing to the nano protocol and node implementation + +# Code standards + +## Formatting + +clang-format is used to enforce most of the formatting rules, such as: + +* Tabs for indentation. +* Open braces go on new lines. +* Space before open parenthesis. +* Space after comma. + +Running `ci/clang-format-all.sh` on \*nix systems is required before pushing your code to ensure that the formatting is good. If you want to do formatting from the IDE, chances are there's a plugin available. Visual studio for instance provides a way to automatically format on saving. The definition file `.clang-format` is located in the project root directory. + +Make sure you set up your editor to use tabs. Use tabs for indentation, and spaces for alignment [^1]. That way, you can use any tab size you want in your favorite editor, but the code will still look good for people with different settings. + +## General guidelines + +* Use `auto` type inference for local variables if it's clear from the context what the type will be. Use your best judgement, sometimes adding explicit types can increase readability [^2] +* Handle exceptions, including IO exceptions for file and network operations. +* Be liberal with `debug_assert`. Use asserts to check invariants, not potential runtime errors, which should be handled gracefully. `debug_assert` has an advantage over normal `assert` as it will always print out the stacktrace of the current thread when it hits. Debug asserts are for detecting bugs, not error handling. There is also `release_assert` which is similar to `debug_assert` but also hits in a release build. When there is unexpected behaviour and no suitable way to recover it can be used to halt program execution. +* Be liberal with `logger.always_log` or `logger.try_log` statements, except in performance critical paths. +* Add comments to explain complex and subtle situations, but avoid comments that reiterates what the code already says. +* Use RAII and C++11 smart pointers to manage memory and other resources. + +## Performance and scalabiliy considerations + +* When making changes, think about performance and scalability. Pick good data structures and think about algorithmic complexity. + * For small data sets, `std::vector` should be your to-go container, as a linear scan through contiguous memory is often faster than any alternative due to memory being read in cache lines. + * Nested loops yield quadratic behavior - is there an alternative? A typical example is removing an inner lookup loop with an unordered set/map to improve lookup performance to O(1). +* Make sure your change doesn't conflict with the scalability characteristics described in the white paper. + +## Security + +Your code will be reviewed with security in mind, but please do your part before creating a pull request: + +* Familiarize yourself with best practices for writing secure C++ code. In particular: + * Consult https://wiki.sei.cmu.edu/confluence/display/cplusplus + * Avoid using ANSI C functions. Many of these are prone to buffer overruns. + * Avoid using C strings and direct buffer manipulation. + +* Use static and dynamic analysis tools, such as valgrind, XCode instrumentation, linters and sanitizers. These tools are also great for debugging crashes and performance problems. + +[^1]: https://dmitryfrank.com/articles/indent_with_tabs_align_with_spaces +[^2]: http://www.acodersjourney.com/2016/02/c-11-auto/ \ No newline at end of file diff --git a/docs/core-development/collaboration-process.md b/docs/core-development/collaboration-process.md new file mode 100644 index 000000000..b1820c9ec --- /dev/null +++ b/docs/core-development/collaboration-process.md @@ -0,0 +1,86 @@ +title: Collaboration Process +description: Find out how the open source collaboration process works with the nano protocol and node software + +# Collaboration Process + +## Code Process + +**Fork and do all your work on a branch** + +Nano prefers the standard GitHub workflow. You create a fork of the nanocurrency/nano-node repository (or other repositories as needed), make changes on new branches for features/fixes, and push these up to be added as Pull Requests. + +**Create pull requests** + +Before: + +* Branch out of the **develop** branch. The **master** branch is only updated on new releases. +* Review your code locally. Have you followed the [Code Standards](code-standards.md) closely? +* Run tests: `core_test`,`qt_test`,`rpc_test` (see [running tests](understanding-the-code.md#tests) for more details). Did you consider adding a test case for your feature? +* Run ASAN, TSAN and Valgrind to detect memory, threading or other bugs +* Commit and push your fork branch + +After: + +* Create pull request on the upstream repository: + * Make sure you add a description that clearly describes the purpose of the PR. + * If the PR solves one or more issues, please reference these in the description. +* Check that CI completes successfully - this can take up to a few hours depending on current CI queues. If any failures exist, fix the problem and push an update. +* Respond to comments and reviews in a timely fashion. + +**Resolve conflicts** + +If time passes between your pull request (PR) submission and the team accepting it, merge conflicts may occur due to activity on develop, such as merging other PR's before yours. In order for your PR to be accepted, you must resolve these conflicts. + +The preferred process is to rebase your changes, resolve any conflicts, and push your changes again. [^1][^2] + +* Check out your branch +* `git fetch upstream` +* `git rebase upstream/develop` +* Resolve conflicts in your favorite editor +* `git add {filename}` +* `git rebase --continue` +* Commit and push your branch + +**Consider squashing or amending commits** + +In the review process, you're likely to get feedback. You'll commit and push more changes, get more feedback, etc. + +This can lead to a messy git history, and can make stuff like bisecting harder. + +Once your PR is OK'ed, please squash the commits into a one.[^3] + +Note that you can also update the last commit with `git commit --amend`. Say your last commit had a typo. Instead of committing and having to squash it later, simply commit with amend and push the branch. + +## Finding issues or features to work on + +- Issues are available on GitHub, with the most urgent being in the latest milestone for release +- Start with issues labeled as [`good first issue`](https://github.com/nanocurrency/nano-node/labels/good%20first%20issue) or connect with the NF core developers on [Discord](https://chat.nano.org) or the [forum](https://forum.nano.org) for ideas on how to help +- If you find an issue you'd like to help with, comment and tag a [Nano Foundation team member](https://github.com/orgs/nanocurrency/people) who can evaluate and assign it to you + +## Submitting issues and feature requests + +Standard GitHub templates exist for submitting any found issues or feature requests. If you plan on working on a bug or feature that doesn't already have a GitHub Issue associated with it, please submit it first so the team is aware. See https://github.com/nanocurrency/nano-node/issues/new/choose for templates. + +## Discussion channels + +Various channels exist for discussing code changes with the Nano Foundation and community. + +**GitHub** + +To help persist useful information about a particular issue or feature, it is best to discuss within the related GitHub Issue or Pull Request. Members of the nano community and Nano Foundation actively follow and will engage when available. + +**Discord for chat** + +For live chat, join the server at https://chat.nano.org and check out the `#protocol` and `#development` channels. The various channels under the `TESTING` section can also be helpful to follow. + +**Forum** + +Another area for technical and code related discussions is the [forum](https://forum.nano.org). There are categories for `Protocol Design` and `Development` that are useful in discussing ideas. This can be a great place for getting feedback on ideas and exploring further before finalizing fixes and features in GitHub. + +## Proposals + +There currently is no formal process for proposals on the nano network. This is an area actively being investigated and if requirements for submissions change, this area will be updated. For now, if you wish to propose an new idea, it is recommended to discuss on the [forum](https://forum.nano.org) first to gather feedback and use the [GitHub Issues](https://github.com/nanocurrency/nano-node/issues/new/choose) on the concept is solidifed/validated. + +[^1]: https://help.github.com/articles/resolving-merge-conflicts-after-a-git-rebase/ +[^2]: https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/ +[^3]: https://github.com/todotxt/todo.txt-android/wiki/Squash-All-Commits-Related-to-a-Single-Issue-into-a-Single-Commit \ No newline at end of file diff --git a/docs/core-development/overview.md b/docs/core-development/overview.md new file mode 100644 index 000000000..fb9b0448a --- /dev/null +++ b/docs/core-development/overview.md @@ -0,0 +1,41 @@ +title: Core Development Overview +description: All you need to know to help contribute to the core development of the nano node and protocol + +# Core Development + +Welcome and thanks for your interest in core development of the nano! The following resources contain information and guides for getting involved with the development of the node and protocol. + +## Getting started + +It is recommended to have an understanding of how the nano protocol is designed to work so the code can be more easily read and evaluated. + +- Start by reviewing the [living whitepaper](../living-whitepaper/index.md) +- Read through (or try out) the [running a node guides](../running-a-node/overview.md) +- Understand [the basics](../integration-guides/the-basics.md) and maybe even some [advanced details](../integration-guides/advanced.md) about integrations +- Learn how to [build the node yourself](../integration-guides/build-options.md) +- Participate in the community through [Discord](https://chat.nano.org) and the [Forum](https://forum.nano.org) +- Start perusing the code in the repositories below and don't be afraid to ask questions + + +## Code repositories + +The Nano Foundation manages the [`nanocurrency`](https://github.com/nanocurrency) GitHub Organization account which includes various repositories for nano tools and implementations. Below is a partial list of the most common repositories referenced. + +| Name | Language | Purpose | +|------|----------|---------| +| [nanocurrency/nano-node](https://github.com/nanocurrency/nano-node) | C++| Primary node implementation used on the nano network | +| [nanocurrency/nano-work-server](https://github.com/nanocurrency/nano-work-server) | Rust | Standalone server for generating work values for blocks | +| [nanocurrency/protocol](https://github.com/nanocurrency/protocol) | Kaitai Struct | Specification for nano network message protocol | +| [nanocurrency/nanodb-specification](https://github.com/nanocurrency/nanodb-specification) | Kaitai Struct | Specification for database tables and fields used by the `nano-node` implementation | +| [nanocurrency/nano-docs](https://github.com/nanocurrency/nano-docs) | Markdown | MKDocs based documentation this docs.nano.org site is built from | + +Most of the content in the following documentation is focused around the [nanocurrency/nano-node](https://github.com/nanocurrency/nano-node) repository, as that is where most development activity occurs. But there are tons of related projects creating useful tools, libraries, services and more for the nano ecosystem (see some options in [GitHub](https://github.com/search?q=nanocurrency&type=discussions)). + +## Security vulnerability reporting + +--8<-- "security-vulnerability-reporting.md" + + +## Nano Foundation core developers + +In addition to contributions from the wider nano community, the [Nano Foundation](https://nano.org/foundation) manages a team of core developers who contribute to the protocol and primary node implementation. For a list of code contributors, see the [GitHub Insights page](https://github.com/nanocurrency/nano-node/graphs/contributors). \ No newline at end of file diff --git a/docs/node-implementation/contributing.md b/docs/core-development/understanding-the-code.md similarity index 61% rename from docs/node-implementation/contributing.md rename to docs/core-development/understanding-the-code.md index 31afd2338..2fbed4843 100644 --- a/docs/node-implementation/contributing.md +++ b/docs/core-development/understanding-the-code.md @@ -1,352 +1,276 @@ -title: Contributing to the Nano Node -description: Find out how to contribute code to the Nano node implementation and help improve the protocol and network +title: Understanding the code +description: Learn about the nano code for better development practices -# Contributing code to the Nano node +# Understanding the code -## About the code base +This guide is designed to give an overall structure of the core nano protocol codebase to help new developers get a better understanding of the different areas and how they interoperate. Due to the rapid changing nature of the protocol it’s possible some of the features are moved to different places or have changed entirely. Working on the protocol requires a very multi-disciplined and wide area of knowledge, none of it is particularly mandatory to get started but a good C++ understanding will help prevent being too overwhelmed initially: -Nano is written in C++17 and supports Linux, macOS and Windows. +Items required include: -**Libraries** +- Windows/MacOS/Linux +- C++17 compiler +- Boost +- Git +- CMake -We use Boost to help us write efficient cross platform code, including the async IO library for networking (asio). +Useful experience includes modern C++ knowledge (up to C++17) including multithreading primitives (mutex, condition variables, atomics) & templates, Boost (asio & beast), RocksDB, LMDB, FlatBuffers, JSON-RPC, IPC, networking communication (ip/tcp, message passing, broadcasting algorithms), QT, signal handling, PKI cryptography, git & cross-platform development. -Make sure you have the correct [Boost version](https://github.com/nanocurrency/nano-node/search?utf8=%E2%9C%93&q=find_package+%28Boost&type=) installed. +The main Nano projects are located inside the `/nano` subdirectory. -**Submodules** +## Executable binaries -| **Name** | **Details** | -| | | -| cryptopp | Provides the implementation for random number generator, SipHash, AES and other cryptographic schemes. | -| phc‑winner‑argon2 | When encrypting with AES, the password first goes through key derivation, and argon2 is our hash of choice for doing that. | -| lmdb | The database library used for the ledger and wallet, with local patches for Windows. This is a very fast and portable key/value store with ordered keys. It is extremely resilient to crashes in the program, OS, and power-downs without corruption. | -| rocksdb | This database library can be used for the ledger. Provides better file IO and reduced ledger size. | -| miniupnp | This library is used to do port mapping if the gateway supports it. | -| cpptoml | This library is used for rpc, wallet and node configuration files | -| flatbuffers | A (de)serialization library for sending binary messages over IPC instead of plain-text JSON | -| gtest | A unit testing library, only used in development environments | +All executables have `nano_` prefix and projects have a `main` function inside `entry.cpp` -**Qt Wallet** +**nano_node** – The standard way to start a node. There are 2 source files in here, `entry.cpp` and `daemon.cpp`. `nano_daemon::daemon::run()` is always called so is a good place to put a breakpoint if there are any issues during node operation (especially errors when launching initially). -To build the GUI, set the `NANO_GUI` flag in cmake. The desktop wallet uses Qt5, but without the MOC compiler. Hence, you cannot use the signals and slots mechanism. +**nano_rpc** – This executable does not need to be run explicitly unless out of process RPC is selected. https://docs.nano.org/integration-guides/advanced/?h=+nano_rpc#running-nano-as-a-service Because this project is quite small it is all done inside the `entry.cpp` file and is probably an easier starting point template should anything else need to be moved out of process in the future. -The majority of the Qt wallet code resides in the `qt` subproject, while the QApplication startup code resides in `nano_wallet`. +**nano_wallet** – This essentially does the same as `nano_node` but doesn’t support all CLI commands and has a graphical user interface for the wallet. -**Using CMake** +--- -CMake is used to generate build files and project files for various IDE's. +## Tests -Please familiarize yourself with basic cmake usage, such as how to change cache variables via the command line, ccmake or CMake GUI. This is much more convenient that editing the `CMakeLists.txt` file directly. +The googletest (gtest) framework is used to validate a variety of functionality in the node, we do not currently use gmock in the codebase. -Find out more about building in [Integration Guides Build Options](/integration-guides/build-options). +### Running tests +The dev network is forced for locally run tests, this lowers work and other settings to make it simpler to test. +Build with `cmake -DNANO_TEST=ON ..` +See docs.nano.org for more information. There may be intermittent failures, if so add them here https://github.com/nanocurrency/nano-node/issues/1121 and fix if possible. -## Testing +### Executables -**Add tests** +**core\_test** – This is where the majority of tests should go. If there is any new functionality added or something has changed, it more often than not should have a test here! Any new core areas should have their own separate test file to encapsulate the logic. -If you add new functionality, adding unit tests to avoid regressions in the future is required. +**ipc\_flatbuffers\_test** – This actually doesn’t use the `gtest` library and has its own main file which just contains a simple example of using flatbuffers. -The easiest way to get started writing your first test is to base it off one of the existing tests. You'll find these in the `core_test` & `rpc_test` directories. There is also `slow_test` & `load_test` directories but these are not commonly modified. +**load_test** – This creates a dynamic number of nodes, sends blocks from 1 of the nodes (primary) and waits until all other nodes have the same number of blocks. This does not normally need to be modified but is run as part CI at the end. -Make sure the `NANO_TEST` cache variable in cmake is set. +**rpc_test** – All RPC tests go here. There is some boilerplate to follow which creates an `ipc_server` for the node which mimics out of process rpc commands communicating with it. Care must be taken when creating write transactions as they are not allowed on io-threads (https://github.com/nanocurrency/nano-node/pull/1264). To make sure this is adhered to when calling the RPC commands, there is an RAII object `scoped_io_thread_name_change` which changes the current thread (normally the main one) to be `io`, and restores it when the object goes out of scope. For instance +``` +... +scoped_thread_name_io.reset (); +node.process (state_block); +scoped_thread_name_io.renew (); +``` +**slow_test** – Any core tests which are not suitable for CI because they take a long time (> a few seconds) should go here. There is a desire to make this file run once per night, but until then should be periodically run by developers. -**Run tests before creating a pull request** +### Work/Sig verification modifying for tests -Please run the tests before submitting a PR. Go to the build directory and run the `core_test` binary. +A common mistake is to request work for the hash of the block to be added, but it should happen on the root (previous one). The work difficulty is different for the live/beta/dev networks and are set using the `work_thresholds` class. During any local testing, where a lot of blocks are processed, work generation and signature verification can take the majority of the time. To speed this up it can make sense to manually lower the work difficulty even further and change the sig verification to always return `true`. -## GitHub collaboration +### Helpers -Communication is the key to working together efficiently. A good way to get in touch with the developers is to join the #development channel on [Discord](https://chat.nano.org/). If you have an idea of an improvement or new feature, consider discussing it first with the team, either on Discord, or by adding an issue. Maybe someone is already working on it, or have suggestions on how to improve on the idea. +**test_common** – This is a helper library which contains test specific (not node related) things which can be used by all test projects. This project should not have a `node` dependency. Anything which does should be put into `nano/node/testing.cpp`. -### Security vulnerability disclosure +### Fuzzer -!!! warning "Submit vulnerabilities privately" - **Do NOT discuss potential security vulnerabilities on the issue tracker, public forums or open discussion channels. Submit sensitive issues privately to the Nano Foundation for review.** +The fuzzer uses libfuzzer which inputs arbitrary data continuously trying to find catch edge cases missed in traditional testing on specific examples. This is not currently supported on Windows. The executables are found in fuzzer_test/\*. The node must be built with the CMake option `-DNANO_FUZZER_TEST=ON`, this does not require that `NANO_TEST` be set. Currently there are 3 executables built: fuzz_bignum, fuzz_buffer, fuzz_endpoint_parsing. -If you discover a bug you believe to pose a security risk to the Nano network, please contact security@nano.org with a proof of concept with full details of the bug including: +**Notes:** +There aren’t currently tests for specific CLIs so it’s recommended to abstract the functionality so that it can be tested in `core_test`. -* Repository of the bug -* High-level summary -* Detailed description -* Steps to reproduce -* Supporting material/references -* The potential security impact of the bug +### Testing implementation details +Sometimes it is necessary to be able to change something about a class only for a test. Rather than make this the class interface public just for tests, the specific tests can be added as friends to the class, this is done like so for a test named like so TEST (node, example); +``` +class my_class +{ +private: + int private_member; // the Test (node, example); test can access this member + friend class node_example_Test; +}; +``` +The test itself needs to be wrapped with the nano { } namespace for this to work correctly, if the class itself is in the nano namespace which is normally the case. -It is strongly recommended to encrypt the email using GPG and the pubkeys for this purpose can be found on the [SECURITY file](https://github.com/nanocurrency/nano-node/blob/develop/SECURITY.md) in the node repository. The Nano Foundation will work to determine potential impacts and coordinate resolution in a node release. +### Additional pre-release testing +- Run tests with TSAN/ASAN/Valgrind. All errors should be fixed before launch unless these are determined to be test related or false positives. We currently have some errors with using coroutines. There are blacklist files for the sanitizers which remove some errors caused by lmdb & rocksdb. -### Code Process +--- -#### Fork and do all your work on a branch +## Bootstrapping -Nano prefers the standard GitHub workflow. You create a fork of the Nano repository, make branches for features/issues, and commit and push these. +There are 2 bootstrapping methods, legacy and lazy. See https://medium.com/nanocurrency/nano-explainer-lazy-bootstrapping-6f091e1eae8c for more information. +`node/bootstrap/boostrap_attempt.hpp` contains the base class definition for bootstrap attempts. -#### Create pull requests +### Legacy -Before: +`node/bootstrap/boostrap_legacy.cpp` -* Branch out of the **develop** branch. The **master** branch is only updated on new releases. -* Review your code locally. Have you followed the guidelines in this document? -* Run tests. Did you consider adding a test case for your feature? -* Run ASAN and TSAN to detect memory or threading bugs -* Commit and push your fork -* Create pull request on the upstream repository: - * Make sure you add a description that clearly describes the purpose of the PR. - * If the PR solves one or more issues, please reference these in the description. +Legacy bootstrapping works by requesting frontiers periodically (every 5 minutes) from a random selection of peers, this is done in `nano::node::ongoing_bootstrap ()`. `bootstrap_frontier.cpp` contains the frontier req client and server. A `frontier_req` message is send from `frontier_req_client` to get a list of frontiers from a peer’s `frontier_req_server` starting at `frontier_req.start` which is done as `accounts_begin (transaction, current + 1);`. The accounts are sorted by their hash. -After: +### Lazy -* Check that CI completes successfully. If not, fix the problem and push an update. -* Respond to comments and reviews in a timely fashion. +`node/bootstrap/boostrap_lazy.hpp` -#### Resolve conflicts +TODO -If time passes between your pull request (PR) submission and the team accepting it, merge conflicts may occur due to activity on develop, such as merging other PR's before yours. In order for your PR to be accepted, you must resolve these conflicts. +### Wallet lazy -The preferred process is to rebase your changes, resolve any conflicts, and push your changes again. [^2][^3] +TODO -* Check out your branch -* `git fetch upstream` -* `git rebase upstream/develop` -* Resolve conflicts in your favorite editor -* `git add {filename}` -* `git rebase --continue` -* Commit and push your branch +### How messages are handled -**Consider squashing or amending commits** +`node/bootstrap/bootstrap_server.cpp` -In the review process, you're likely to get feedback. You'll commit and push more changes, get more feedback, etc. +When a message is received through the bootstrap server, its header is first checked inside `nano::bootstrap_server::receive_header_action ()`. The message is deserialized and added in `add_request ()` to the `std::queue> requests` collection which holds a queue of messages. `run_next ()` is then called (and will be called after the request is finished if there are more messages to process), this runs the message through a `request_response_visitor` object which creates a `tcp_message_item` and adds it to the `tcp_message_manager` to be processed. The newest set of messages added were for telemetry. If new messages need adding that can be used as a guide: https://github.com/nanocurrency/nano-node/pull/2446 -This can lead to a messy git history, and can make stuff like bisecting harder. +--- -Once your PR is OK'ed, please squash the commits into a one.[^4] +## Workers (thread pool) -Note that you can also update the last commit with `git commit --amend`. Say your last commit had a typo. Instead of committing and having to squash it later, simply commit with amend and push the branch. +The class definition for `thread_pool` is defined inside `nano/lib/threading.cpp`, which allows tasks to be added to a queue for execution as well as executed at a specific time. Previously there were worker/alarm classes, which were combined in https://github.com/nanocurrency/nano-node/pull/2871. Its primary purpose was to schedule write transactions off the io threads. It is generally recommended to push other tasks onto the io threads though to avoid bottlenecking these threads. -## Code standard +--- -### Formatting +## Database -clang-format is used to enforce most of the formatting rules, such as: +There are 2 logical areas where a persistent file is needed: the ledger and wallets. For this 2 NoSQL databases which store binary data are used, namely LMDB & RocksDB. The ledger database is comprised of a few files: -* Tabs for indentation. -* Open braces go on new lines. -* Space before open parenthesis. -* Space after comma. +- `nano/secure/blockstore.hpp`: interface +- `nano/secure/blockstore_partial.hpp`: partial implementation of the interface, it allows CRTP for derived classes +- `nano/node/lmdb/`: anything specific to LMDB goes here +- `nano/node/rocksdb/`: anything specific to RocksDB goes here -Please run `ci/clang-format-all.sh` on \*nix systems before pushing your code to ensure that the formatting is good. If you want to do formatting from the IDE, chances are there's a plugin available. Visual studio for instance provides a way to automatically format on saving. The definition file `.clang-format` is located in the project root directory. +The wallets database uses the wallets_store which only has an LMDB backend. -Make sure you set up your editor to use tabs. Use tabs for indentation, and spaces for alignment [^5]. That way, you can use any tab size you want in your favorite editor, but the code will still look good for people with different settings. +### Database upgrades -### Coding guidelines +`nano::mdb_store::do_upgrades ()` is where LMDB database upgrades are done. For instance `void nano::mdb_store::upgrade_v18_to_v19 ()` combines all block databases into a single one. Raw mdb functions are normally required as `blockstore::block_get ()` and other functions normally can’t be used because they are updated to the latest db spec. There are currently no rocksdb upgrades but this will follow a similar approach when required. A corresponding test should be added, https://github.com/nanocurrency/nano-node/pull/2429/files is a simple example of adding an upgrade. There are sometimes multiple upgrades during a release if a beta build goes out and a subsequent upgrade is desired. Previously a ledger reset was done and the version was re-used but this was deemed too inconvenient. -* Use `auto` type inference for local variables if it's clear from the context what the type will be. Use your best judgement, sometimes adding explicit types can increase readability [^1] -* Handle exceptions, including IO exceptions for file and network operations. -* Be liberal with `debug_assert`. Use asserts to check invariants, not potential runtime errors, which should be handled gracefully. `debug_assert` has an advantage over normal `assert` as it will always print out the stacktrace of the current thread when it hits. Debug asserts are for detecting bugs, not error handling. There is also `release_assert` which is similar to `debug_assert` but also hits in a release build. When there is unexpected behaviour and no suitable way to recover it can be used to halt program execution. -* Be liberal with `logger.always_log` or `logger.try_log` statements, except in performance critical paths. -* Add comments to explain complex and subtle situations, but avoid comments that reiterates what the code already says. -* Use RAII and C++11 smart pointers to manage memory and other resources. +### write_database_queue +This was introduced to reduce LMDB write lock contention between the block processor and the confirmation height processor. As during bootstrapping or high TPS the block processor can hold onto the lock up to 5s (by default), before the lock is held by the blockprocessor it signals that it is about to get the LMDB lock, the confirmation height processor can make use of this information and continue processing where it would otherwise be stalled. Ongoing pruning also makes use of this. -### Performance and scalabiliy considerations +--- -* When making changes, think about performance and scalability. Pick good data structures and think about algorithmic complexity. - * For small data sets, `std::vector` should be your to-go container, as a linear scan through contiguous memory is often faster than any alternative due to memory being read in cache lines. - * Nested loops yield quadratic behavior - is there an alternative? A typical example is removing an inner lookup loop with an unordered set/map to improve lookup performance to O(1). -* Make sure your change doesn't conflict with the scalability characteristics described in the white paper. - -### Security +## Block processing -Your code will be reviewed with security in mind, but please do your part before creating a pull request: +There are 4 types of legacy blocks: open, receive, send & change. There are the state blocks which encompass traits from the legacy subtypes as well as support epochs. In various places an `epoch_link` is checked, this indicates that the link field is set to one of the epoch accounts (for v1 state blocks), or possibly self for v2 state blocks upgrade blocks. No new legacy blocks can be created (there are about 10million), but they still need to be handled in any algorithm which deals with blocks because users can still be bootstrap from scratch. When a node is first launched without a ledger `block_store_partial::init ()` is called, this creates the genesis block. Blocks are then bootstrapped. -* Familiarize yourself with best practices for writing secure C++ code. In particular: - * Consult https://wiki.sei.cmu.edu/confluence/display/cplusplus - * Avoid using ANSI C functions. Many of these are prone to buffer overruns. - * Avoid using C strings and direct buffer manipulation. +--- -* Use static and dynamic analysis tools, such as valgrind, XCode instrumentation, linters and sanitizers. These tools are also great for debugging crashes and performance problems. +## Ledger -## General tips for contributors +`nano/secure/ledger.cpp` is where blocks are added and deleted to the ledger database. -* Read the [white paper](https://nano.org/en/whitepaper) -* Peruse the code and don't be shy about asking questions if there are parts you don't understand. -* Make sure you understand the GitHub workflow. -* Participate in the community by reading and replying to GitHub issues, Reddit posts and tweets. This gives you a great insight into the pain points that exists with the software. +The ledger cache is used when it may be expensive to try and determine the count of something in the ledger. It was originally used for the cemented count, because this is determined by adding the confirmation height from all accounts. This does mean that any external write operations from LMDB (such as CLI command `--confirmation_height_clear`) will cause this number to get out of sync. This is not possible with RocksDB backend because it does not allow multi-process write transactions. -## [WIP] Developer starter pack +--- -Items include: +## Node initialization -- Windows/MacOS/Linux -- C++17 compiler -- Boost -- Git -- CMake +The biggest bottleneck for node start-up is caused by setting up the ledger cache. This requires scanning all accounts & conf height databases. A multi-threaded process (added in https://github.com/nanocurrency/nano-node/pull/2876) splits the account space into equal partitions (as accounts should be randomly distributed) and does sequential sorted reads in each partition; this is the most efficient way to search through any of the databases. Point/Random reads are very slow in comparison. -This guide is designed to give an overall structure of the core Nano Protocol codebase to help new developers get a better understanding of the different areas and how they interoperate. Due to the rapid changing nature of the protocol it’s possible some of the features are moved to different places or have changed entirely. Working on the protocol requires a very multi-disciplined and wide area of knowledge, none of it is particularly mandatory to get started but a good C++ understanding will help prevent being too overwhelmed initially: +### Keeping build times low -Modern C++ knowledge (up to C++17) including multithreading primitives (mutex, condition variables, atomics) & templates, Boost (asio & beast), RocksDB, LMDB, FlatBuffers, JSON-RPC, IPC, networking communication (ip/tcp, message passing, broadcasting algorithms), QT, signal handling, PKI cryptography, git & cross-platform development. +`nano/node/node.hpp` is the largest build bottleneck, it can increase build times of files by up to 10 seconds on some systems! Some boost files tend to be large too, they offer forward declaration headers such as `` & `` worth checking if they exist for any you are using in header files. -The main Nano projects are located inside the /nano subdirectory. +### node_initialized_latch -### Executable binaries (all have nano\_ prefix) -All executable projects have a `main` function inside `entry.cpp` +Some classes use `node_initialized_latch.wait ();` The latch was added in https://github.com/nanocurrency/nano-node/pull/2042 this is to prevent some of the issues in the node constructor initializer list where the `node` object is passed and a child constructor is wants to use a node member which is not yet initialized. This makes it resume operation once the latch is incremented at the beginning of the `node` constructor. -*nano_node* – The standard way to start a node. There are 2 source files in here, `entry.cpp` and `daemon.cpp`. `nano_daemon::daemon::run()` is always called so is a good place to put a breakpoint if there are any issues during node operation (especially errors when launching initially). -*nano_rpc* – This executable does not need to be run explicitly unless out of process RPC is selected. https://docs.nano.org/integration-guides/advanced/?h=+nano_rpc#running-nano-as-a-service Because this project is quite small it is all done inside the `entry.cpp` file and is probably an easier starting point template should anything else need to be moved out of process in the future. -*nano_wallet* – This essentially does the same as `nano_node` but doesn’t support all CLI commands and has a graphical user interface for the wallet. +### Initial output +When the node is run it prints out some information about the database used, compiler etc. An example of appending to the output is here: https://github.com/nanocurrency/nano-node/pull/2807 -##### Tests -The googletest (gtest) framework is used to validate a variety of functionality in the node, we do not currently use gmock in the codebase. +--- -**Executables** -**core\_test** – This is where the majority of tests should go. If there is any new functionality added or something has changed, it more often than not should have a test here! Any new core areas should have their own separate test file to encapsulate the logic. -**ipc\_flatbuffers\_test** – This actually doesn’t use the `gtest` library and has its own main file which just contains a simple example of using flatbuffers. -**load_test** – This creates a dynamic number of nodes, sends blocks from 1 of the nodes (primary) and waits until all other nodes have the same number of blocks. This does not normally need to be modified but is run as part CI at the end. -**rpc_test** – All RPC tests go here. There is some boilerplate to follow which creates an `ipc_server` for the node which mimics out of process rpc commands communicating with it. Care must be taken when creating write transactions as they are not allowed on io-threads (https://github.com/nanocurrency/nano-node/pull/1264). To make sure this is adhered to when calling the RPC commands, there is an RAII object `scoped_io_thread_name_change` which changes the current thread (normally the main one) to be `io`, and restores it when the object goes out of scope. For instance -``` -... -scoped_thread_name_io.reset (); -node.process (state_block); -scoped_thread_name_io.renew (); -``` -**slow_test** – Any core tests which are not suitable for CI because they take a long time (> a few seconds) should go here. There is a desire to make this file run once per night, but until then should be periodically run by developers. +## CMake -##### Helper -**test_common** – This is a helper library which contains test specific (not node related) things which can be used by all test projects. This project should not have a `node` dependency. Anything which does should be put into `nano/node/testing.cpp`. +CMake is used as the build system, and git submodules for any third party dependencies (except boost which must be installed separately by the developer). In `CMakeLists.txt` header files (.hpp) are above source files (.cpp), no particular reason but consistency is important. -##### Fuzzer -The fuzzer uses libfuzzer which inputs arbitrary data continuously trying to find catch edge cases missed in traditional testing on specific examples. This is not currently supported on Windows. The executables are found in fuzzer_test/\*. The node must be built with the CMake option `-DNANO_FUZZER_TEST=ON`, this does not require that `NANO_TEST` be set. Currently there are 3 executables built: fuzz_bignum, fuzz_buffer, fuzz_endpoint_parsing. +### Developer build options -**Notes:** -There aren’t currently tests for specific CLIs so it’s recommended to abstract the functionality so that it can be tested in `core_test`. +`-DNANO_TIMED_LOCKS=10` -##### Bootstrapping -There are 2 bootstrapping methods, legacy and lazy. See https://medium.com/nanocurrency/nano-explainer-lazy-bootstrapping-6f091e1eae8c for more information. -node/bootstrap/boostrap_attempt.hpp contains the base class definition for bootstrap attempts. +Added: https://github.com/nanocurrency/nano-node/pull/2267. In `nano/lib/locks.hpp(.cpp)`, `std::mutex`, `std::condition_variable`, `std::unique_lock` & `std::lock_guard` are wrapped in custom classes (with the same interface) which adds some extra timing functionality to check if a mutex was help for a time longer than `NANO_TIMED_LOCKS` in milliseconds. This is useful to see if mutex contention is a cause of any performance loss. To pinpoint a specific mutex https://github.com/nanocurrency/nano-node/pull/2765 added `NANO_TIMED_LOCKS_FILTER=confirmation_height_processor`. The full list of mutexes is available in `nano/lib/locks.cpp` - `mutex_identifier()` . -##### Legacy +--- -node/bootstrap/boostrap_legacy.cpp +## APIs -Legacy bootstrapping works by requesting frontiers periodically (every 5 minutes) from a random selection of peers, this is done in `nano::node::ongoing_bootstrap ()`. `bootstrap_frontier.cpp` contains the frontier req client and server. A `frontier_req` message is send from `frontier_req_client` to get a list of frontiers from a peer’s `frontier_req_server` starting at `frontier_req.start` which is done as `accounts_begin (transaction, current + 1);`. The accounts are sorted by their hash. +### CLI -##### Lazy -node/bootstrap/boostrap_lazy.hpp -TODO +There are 2 places that CLI commands can be added for use with `nano_node`, `nano/node/cli.cpp` & `nano/nano_node/entry.cpp`. The `nano/node/cli.cpp` CLI commands are also shared with `nano_wallet` so this is the place to put shared logic which can be used by both. CLI commands prefixed with `debug_*` shouldn’t really be used by end users unless they are diagnosing issues. Sometimes it can be useful to compare the RPC output with CLI, and rpc results such as `block_count` will return cached results. -##### Wallet lazy -TODO +### IPC -##### How messages are handled (bootstrap_server.cpp) -When a message is received through the bootstrap server, its header is first checked inside `nano::bootstrap_server::receive_header_action ()`. The message is deserialized and added in `add_request ()` to the `std::queue> requests` collection which holds a queue of messages. `run_next ()` is then called (and will be called after the request is finished if there are more messages to process), this runs the message through a `request_response_visitor` object which creates a `tcp_message_item` and adds it to the `tcp_message_manager` to be processed. The newest set of messages added were for telemetry. If new messages need adding that can be used as a guide: https://github.com/nanocurrency/nano-node/pull/2446 +When using the `nano_rpc` as a separate process (either child or manually starting it), there needs to be a way of communicating between processes. IPC supports tcp and unix domain sockets, `nano_rpc` only supports tcp as it can be run on a different computer. IPC 2.0 adds flatbuffer support (https://github.com/nanocurrency/nano-node/pull/2487) which can be used for the new RPC 2.0 (TBA). + +### Websockets -##### Websocket Websockets were introduced in https://github.com/nanocurrency/nano-node/pull/1840. Previously a HTTP callback had to be used, but websockets provides a more efficient 2 way communication protocol. Websocket events are available for various topics. For an example of adding a websocket topic look at: https://github.com/nanocurrency/nano-node/pull/2634. `observers.notify (message_a.data, endpoint);` is what ultimately invokes the websocket server to send a message which is deserialized inside `nano::websocket::message_builder`. -##### Workers (thread pool) -The class definition for `thread_pool` is defined inside `nano/lib/threading.cpp`, which allows tasks to be added to a queue for execution as well as executed at a specific time. Previously there were worker/alarm classes, which were combined in https://github.com/nanocurrency/nano-node/pull/2871. Its primary purpose was to schedule write transactions off the io threads. It is generally recommended to push other tasks onto the io threads though to avoid bottlenecking these threads. +--- -##### Database -There are 2 logical areas where a persistent file is needed: the ledger and wallets. For this 2 NoSQL databases which store binary data are used, namely LMDB & RocksDB. The ledger database is comprised of a few files: -**nano/secure/blockstore.hpp** (interface) -**nano/secure/blockstore_partial.hpp** (partial implementation of the interface, it allows CRTP for derived classes) -**nano/node/lmdb/** (anything specific to LMDB goes here) -**nano/node/rocksdb/** (anything specific to RocksDB goes here) -The wallets database uses the wallets_store which only has an LMDB backend. +## Signal handling -##### Database upgrades -`nano::mdb_store::do_upgrades ()` is where LMDB database upgrades are done. For instance `void nano::mdb_store::upgrade_v18_to_v19 ()` combines all block databases into a single one. Raw mdb functions are normally required as `blockstore::block_get ()` and other functions normally can’t be used because they are updated to the latest db spec. There are currently no rocksdb upgrades but this will follow a similar approach when required. A corresponding test should be added, https://github.com/nanocurrency/nano-node/pull/2429/files is a simple example of adding an upgrade. There are sometimes multiple upgrades during a release if a beta build goes out and a subsequent upgrade is desired. Previously a ledger reset was done and the version was re-used but this was deemed too inconvenient. +There are 2 sets of signal handlers registered (both are only set when the `nano_node` is run as a daemon. `SIGSEGV` & `SIGABRT` are set at the beginning which will create dump files if there is a segmentation fault during program execution (added in https://github.com/nanocurrency/nano-node/pull/1921/). `SIGINT` & `SIGTERM` signals catch non-kill intentional closing of the executable, such as pressing ctrl+c (added in https://github.com/nanocurrency/nano-node/pull/2018). This shuts down the node allows any running write transactions to finish. Only async signal safe functions should be used in signal handlers, this limits it to very specific functions. -##### Block processing -There are 4 types of legacy blocks: open, receive, send & change. There are the state blocks which encompass traits from the legacy subtypes as well as support epochs. In various places an `epoch_link` is checked, this indicates that the link field is set to one of the epoch accounts (for v1 state blocks), or possibly self for v2 state blocks upgrade blocks. No new legacy blocks can be created (there are about 10million), but they still need to be handled in any algorithm which deals with blocks because users can still be bootstrap from scratch. When a node is first launched without a ledger `block_store_partial::init ()` is called, this creates the genesis block. Blocks are then bootstrapped. +--- -##### Ledger -nano/secure/ledger.cpp is where blocks are added and deleted to the ledger database. -The ledger cache is used when it may be expensive to try and determine the count of something in the ledger. It was originally used for the cemented count, because this is determined by adding the confirmation height from all accounts. This does mean that any external write operations from LMDB (such as CLI command `--confirmation_height_clear`) will cause this number to get out of sync. This is not possible with RocksDB backend because it does not allow multi-process write transactions. +## Memory allocators -##### Node initialization -The biggest bottleneck for node start-up is caused by setting up the ledger cache. This requires scanning all accounts & conf height databases. A multi-threaded process (added in https://github.com/nanocurrency/nano-node/pull/2876) splits the account space into equal partitions (as accounts should be randomly distributed) and does sequential sorted reads in each partition; this is the most efficient way to search through any of the databases. Point/Random reads are very slow in comparison. +A lot of our heap usage is from deserializing block/votes off the wire and ledger database. To solve this we use a memory pool allocator which reuses memory in a freelist: https://github.com/nanocurrency/nano-node/pull/2047 -##### CMake developer build options --DNANO_TIMED_LOCKS=10 – https://github.com/nanocurrency/nano-node/pull/2267 In nano/lib/locks.hpp(.cpp) `std::mutex`, `std::condition_variable`, `std::unique_lock` & `std::lock_guard` are wrapped in custom classes (with the same interface) which adds some extra timing functionality to check if a mutex was help for a time longer than `NANO_TIMED_LOCKS` in milliseconds. This is useful to see if mutex contention is a cause of any performance loss. To pinpoint a specific mutex https://github.com/nanocurrency/nano-node/pull/2765 added `NANO_TIMED_LOCKS_FILTER=confirmation_height_processor`. The full list of mutexes is available in nano/lib/locks.cpp `mutex_identifier()` . +In `nano/lib/memory.hpp` a `nano::make_shared` function is defined which checks if the global variable `use_memory_pool` is set (initialized during node startup reading the config `node.use_memory_pools`, which defaults to true). The memory is never reclaimed, this is a performance optimization. -##### CLI -There are 2 places that CLI commands can be added for use with `nano_node`, `nano/node/cli.cpp` & `nano/nano_node/entry.cpp`. The `nano/node/cli.cpp` CLI commands are also shared with `nano_wallet` so this is the place to put shared logic which can be used by both. CLI commands prefixed with `debug_*` shouldn’t really be used by end users unless they are diagnosing issues. Sometimes it can be useful to compare the RPC output with CLI, and rpc results such as `block_count` will return cached results. +--- -##### IPC -When using the `nano_rpc` as a separate process (either child or manually starting it), there needs to be a way of communicating between processes. IPC supports tcp and unix domain sockets, `nano_rpc` only supports tcp as it can be run on a different computer. IPC 2.0 adds flatbuffer support (https://github.com/nanocurrency/nano-node/pull/2487) which can be used for the new RPC 2.0 (TBA). +## Libraries and submodules -##### Work/Sig verification modifying for tests -A common mistake is to request work for the hash of the block to be added, but it should happen on the root (previous one). The work difficulty is different for the live/beta/dev networks and are set using the `work_thresholds` class. During any local testing, where a lot of blocks are processed, work generation and signature verification can take the majority of the time. To speed this up it can make sense to manually lower the work difficulty even further and change the sig verification to always return `true`. +### Boost +We use the Boost library where possible, such as coroutine, filesystem, endian converter, lexical_cast, multi_index_container etc.. if there is a static/dynamic Boost library which is not used, there are generally no issues in adding it. Just make sure the build scripts and documentation are updated. -##### Signal handling -There are 2 sets of signal handlers registered (both are only set when the `nano_node` is run as a daemon. `SIGSEGV` & `SIGABRT` are set at the beginning which will create dump files if there is a segmentation fault during program execution (added in https://github.com/nanocurrency/nano-node/pull/1921/). `SIGINT` & `SIGTERM` signals catch non-kill intentional closing of the executable, such as pressing ctrl+c (added in https://github.com/nanocurrency/nano-node/pull/2018). This shuts down the node allows any running write transactions to finish. Only async signal safe functions should be used in signal handlers, this limits it to very specific functions. +**nano/boost** +Use `nano/boost/asio` `nano/boost/beast` for includes, this wraps up various includes and prevents warnings being shown (particularly on Windows builds). -##### Memory allocators -A lot of our heap usage is from deserializing block/votes off the wire and ledger database. To solve this we use a memory pool allocator which reuses memory in a freelist: https://github.com/nanocurrency/nano-node/pull/2047 -In nano/lib/memory.hpp a `nano::make_shared` function is defined which checks if the global variable `use_memory_pool` is set (initialized during node startup reading the config `node.use_memory_pools`, which defaults to true). The memory is never reclaimed, this is a performance optimization. +### `nano/crypto_lib/` -##### nano/crypto_lib/ This is a small library which has no dependency to anything in the nano core, which is needed as it is included by the ed25519 library as well. More info here: https://github.com/nanocurrency/nano-node/pull/1870 -##### test/common/ -Any functionality which is shared between test projects and may also use gtest library. There is also nano/node/testing.cpp which has no gtest dependency because it is also used in CLI commands too. +### `test/common/` -##### debug_assert & release_assert -`debug_assert` is essentially the same as the traditional C++ assert but also outputs a stacktrace. Added in https://github.com/nanocurrency/nano-node/pull/2568. This should be used to check programmer logic. -`release_assert` this is an assert which is triggered in both release/debug build, it also outputs a stacktrace. This was added https://github.com/nanocurrency/nano-node/pull/1114. This should be used if some invariant doesn’t hold and there is no suitable way to recover from this. Such as reading something from the ledger which is meant to exist but doesn’t, can indicate ledger corruption. +Any functionality which is shared between test projects and may also use gtest library. There is also `nano/node/testing.cpp` which has no gtest dependency because it is also used in CLI commands too. -##### Put inside nano/lib or nano/secure? -These libraries . nano/lib was originally intended to be used by other programs wanting some of the nano functionality, but those specific extern C functions were removed and it has now become the place to put all commonly used code. As such anything which doesn’t depend on the node should go here, and the `secure` library is now mostly for ledger specific things. +### `nano/lib` vs. `nano/secure` +The`nano/lib` library was originally intended to be used by other programs wanting some of the nano functionality, but those specific external C functions were removed and it has now become the place to put all commonly used code. As such anything which doesn’t depend on the node should go here, and the `secure` library is now mostly for ledger specific things. -##### git submodules +### git submodules We have a variety of submodules https://docs.nano.org/node-implementation/contributing/?h=+submodule#about-the-code-base third party dependencies are to be kept as minimal as possible in order to keep build times lean, but if there is a suitable one it can be added a submodule. -##### All threads should have a name set -An easy example to follow is https://github.com/nanocurrency/nano-node/pull/2987/files This is so that debuggers/viewers which show threads can pick up the name to make it easier to navigate. It’s been known not to work in the Visual Studio Concurrency visualizer. +--- -##### (de)serializing -Where possible we try and store primitives in big-endian. As most systems are little-endian this means using `boost::endian::native_to_big` on primitives when serializing and `boost::endian::big_to_native` when deserializing. +## Assertions -##### Boost -We use the Boost library where possible, such as coroutine, filesystem, endian converter, lexical_cast, multi_index_container etc.. if there is a static/dynamic Boost library which is not used, there are generally no issues in adding it. Just make sure the build scripts and documentation are updated. - -##### Signature checker -This is used by both blocks/votes and creates (total threads / 2) to perform signature verification of set batches; this is the biggest compute resource. Being able to lower this would be very beneficial, such as out of process sig verification and/or via GPU. +`debug_assert` is essentially the same as the traditional C++ assert but also outputs a stacktrace. Added in https://github.com/nanocurrency/nano-node/pull/2568. This should be used to check programmer logic. -##### Keeping build times low -nano/node/node.hpp is the largest build bottleneck, it can increase build times of files by up to 10 seconds on some systems! Some boost files tend to be large too, they offer forward declaration headers such as `` & `` worth checking if they exist for any you are using in header files. +`debug_assert (!mutex.try_lock ());` When functions require that a mutex is required before being called we often check that the mutex is locked. Although this is technically undefined behaviour to be called by a thread which already owns the mutex we have been using this idiom for years and found no issues with the major compilers. -##### peers -Peers are written to disk periodically. This was added in https://github.com/nanocurrency/nano-node/pull/1608 -If the node has not been run in a long time (1 week), the peers list is cleared and the preconfigured peers list is used, this was added in https://github.com/nanocurrency/nano-node/pull/2506 +`release_assert` this is an assert which is triggered in both release/debug build, it also outputs a stacktrace. This was added https://github.com/nanocurrency/nano-node/pull/1114. This should be used if some invariant doesn’t hold and there is no suitable way to recover from this. Such as reading something from the ledger which is meant to exist but doesn’t, can indicate ledger corruption. -##### write_database_queue -This was introduced to reduce LMDB write lock contention between the block processor and the confirmation height processor. As during bootstrapping or high TPS the block processor can hold onto the lock up to 5s (by default), before the lock is held by the blockprocessor it signals that it is about to get the LMDB lock, the confirmation height processor can make use of this information and continue processing where it would otherwise be stalled. Ongoing pruning also makes use of this. +--- -##### debug_assert (!mutex.try_lock ()); -When functions require that a mutex is required before being called we often check that the mutex is locked. Although this is technically undefined behaviour to be called by a thread which already owns the mutex we have been using this idiom for years and found no issues with the major compilers. +## Voting/Consensus -### Voting/Consensus To confirm a block a sufficient number of votes which are taken from `confirm_ack` messages are tallied up. If the tally is above the delta inside `nano::election::have_quorum ()` it returns true and the block is considered confirmed. `confirm_ack` messages can either contain the whole block or a hash (vote by hash). `confirm_req` message header as well as `confirm_ack` indicate what the type of the contents is in the header, either `not_a_block` which means dealing with block hashes or the block type. `nano/node/common.cpp` contains these messages (among others) and (de)serializing functions. -##### voting +### voting The vote generator `nano::vote_generator::vote_generator` is responsible for collecting hashes that need a vote generated, combining them into a single `vote by hash` message, signing the package with the representative key and publishing the votes to the network. A maximum of `nano::network::confirm_ack_hashes_max` hashes can be combined into a single vote `confirm_ack` message, this provides a decent tradeoff between optimizing vote signatures and reducing bandwidth. While the process is running it waits for `config.vote_generator_delay` time in order to pack more hashes into a single vote message. If there are more than `config.vote_generator_threshold` after waiting then it will wait for one additional `config.vote_generator_delay` before broadcasting the message. This allows for fast vote publishing at lower rates while enabling more hashes to be combined together at higher rates. -##### vote_processor +### vote_processor Votes are signed by the representative and the vote processor schedules checking these votes through the `signature_checker` inside `nano::vote_processor::verify_votes ()`. Once a vote signature has been verified, the hashes within the vote packet are passed to active_elections where they are either added to an active election or added to the inactive votes cache if an election does not exist. -##### active_transactions +### active_transactions The active transactions class handles election management and prioritization. When a block is processed and `nano::active_transactions::insert` called, a new election is started for the block hash if one does not already exist. In addition to starting elections there is a 500ms `request_loop` that handles election management. This process assists with moving elections through the different transition states as well as moving elections to a prioritized status if there is a backlog of elections. During the requst loop the current network difficulty is updated through `update_active_multiplier` which takes the top `prioritized_cutoff` number of active elections that have not been confirmed and samples their difficulty multiplier. Finally, the active transactions class also handles frontiers that have not been confirmed. Most commonly this is from bootstrapping, where the frontier of an account is added to the active elections and vote requests are sent to other nodes to confirm the frontier and thereby the rest of the account and ancestors through confirmation height processing. -##### confirmation_solicitor +### confirmation_solicitor During the `request_loop` of the active transactions process, any election that is in the `active` state for more than 5 seconds will request votes from Principle Representative nodes that it has not seen a vote from yet. These requests are added to the `confirmation_solicitor` which aggregates the hashes up to `nano::network::confirm_req_hashes_max` into a single `confirm_req` message and publishes it to select PR nodes that have not voted. This helps fill any gaps in network communication failures where a vote may have been dropped which helps reach quorum on the highest priority elections. -##### request_aggregator +### request_aggregator The request aggregator is responsible for collecting vote requests `confirm_req` messages from other nodes and finding the optimal responses. A local vote cache is used for recently generated votes, if the block hash in the request exists in the cache then a cached vote is returned, if the hash does not exist then the hash is added to the vote generator and a new vote is generated and published to the requesting node. The request aggregator also handles publishing forks if the request is for a competing fork. If the local node has a different winning hash it will publish a vote for the winning hash instead of the requested hash in addition to sending the requesting node the winning block as well. -##### election +### election An election is created when a new block is processed. The primary purpose of the election class is to tally the vote weight and ensure consensus between any competing forks. In order to efficiently move an election through the process it can have several states. Initially `passive` where it is waiting for votes from other nodes, then after 5 seconds if it has not been confirmed it will transition to `active` where vote requests to other nodes are made. After `active_request_count_min` rounds of requesting votes are complete if the election is still not confirmed it moves to `broadcasting` where it will publish the block to PR nodes that have not voted in an attempt to ensure the block has been propagated throughout the network. Under low load the `active` and `broadcasting` states are rarely used as all elections are complete within the `passive` window. Every vote that is added to the election triggers a check for whether quorum has been reached on the election. Quorum requires that the winning hash has `node.online_reps.delta` more weight than any competing forks. If quorum is reached the election is marked confirmed, transitions to the `confirmed` state and is added to the confirmation height procesor which updates the ledger. @@ -355,134 +279,130 @@ After an election is confirmed it can stay in the active elections container up If an election lasts longer than 5 minutes and has not been confirmed it is transitioned to `expired_unconfirmed` and removed from the queue. This most often happens during high saturation when the active elections container reaches capacity. -##### Confirmation height processor +### Confirmation height processor When a block is confirmed `void nano::node::process_confirmed ()` the block is added to the confirmation height processor. This begins the process of cementing it and all of its dependents, once this occurs these blocks can never be rolled back. There are 2 confirmation height algorithms bounded and unbounded. Originally only the unbounded one existed, this would store the block hash for the original block confirmed, all its previous blocks, and recurse the bottom most receive block to the source and repeat the process. If this hit something like the binance chain or (any long chain) it could use a lot of memory (unbounded amount). So this brought about the bounded confirmation height processor algorithm which starts at the very bottom of the account chains but does the same recursion when a receive block is hit. This limits the amount of block hashes needing to be stored in memory to be able to cement the bottom most blocks. Checkpoints are used if there are a lot of accounts which need to be traversed to reach which exceeds the maximum amount of memory . It does mean in certain cases the same iteration will need to be done more than once but this should be a rare case only during initial cementing. Once the uncemented count (block count – cemented count) is less than 16K the unbounded processor is used. As mentioned above this instead starts from the top (original confirmed block) and works downwards and saves all the blocks hit (not just hash) which means they don’t need to be re-read during writing later. This does use a lot more memory though which is why this is limited to a certain number of blocks, once the unbounded cutoff is exceeded the bounded processor resumes. Both algorithms operate with a read transaction first which reduces write lock held time as it can do a lot of iterating. This does mean that there can be some inconsistency by the time the writing is done, but this shouldn’t be an issue because once a block is confirmed by the network it will stay confirmed by `debug_assert` checks are added to catch any programming mistakes. While it is more effort to maintain 2 algorithms the unbounded one largely existed before so it made sense to re-use it, given the performance improvements in almost cemented ledgers. -##### node_initialized_latch -Some classes use `node_initialized_latch.wait ();` The latch was added in https://github.com/nanocurrency/nano-node/pull/2042 this is to prevent some of the issues in the node constructor initializer list where the `node` object is passed and a child constructor is wants to use a node member which is not yet initialized. This makes it resume operation once the latch is incremented at the beginning of the `node` constructor. - -##### Frontiers confirmation +### Frontiers confirmation `nano/node/frontiers_confirmation.cpp` contains code which starts at the beginning of the accounts database (`nano::blockstore_partial::accounts_begin`) and iterates in ascending order and prioritises accounts based on the number of uncemented blocks (stores up to 100k) and requests confirmation for a limited number of these accounts. When the cemented count is above the hardcoded bootstrap weights this is limited to the number of optimistic elections which is 50 in this case so it is expected to be quite slow in this case. Accounts in wallets are also checked. -##### Telemetry +--- + +## Telemetry nano/node/telemetry.cpp contains the logic for telemetry processing. This sets up an ongoing telemetry request round (every 60 seconds on the live network) where a telemetry_req message is sent to every peer. There is an `alarm` timeout of about 10 seconds in which we require the response (telemetry_ack) to be received otherwise it is rejected. Any calls to get_metrics_* return a cached result. To add a new definition to the telemetry_ack message this can be used as a guide which added the `active_multiplier`: https://github.com/nanocurrency/nano-node/pull/2728 `telemetry_ack` messages are signed and are backwards compatible with older nodes (from v22 onwards). Those nodes will verify the whole message including any extra unknown data which is appended at the end is just ignored. To prevent ddosing by `telemetry_req` messages, nodes ignore messages received within that 60second (on live) boundary. This is done in `void nano::bootstrap_server::receive_header_action ()` -##### Stats (counters) +--- + +## Stats + +### Counters The `stats` object is used to keep a count of events that have happened, this is a useful idiom for checking values in tests and is aggregated in the stats->counts RPC. There are main stat types and then details for that type. A simple example of adding new details and incrementing the stats can be seen here: https://github.com/nanocurrency/nano-node/pull/2515 Adding a type for a stat is a similar procedure just using the `nano::stat::type` enumerator. -##### Stats (objects) +### Objects Most classes which have a member variable of container of multiple items (map, vector, list etc..) should have a function with a prototype of: `std::unique_ptr collect_container_info (my_class & my_class, std::string const & name);` And then call this in an owning object which should itself be called recursively until it reaches the `node` object `collect_container_info`. They are typically not made as part of the class itself because it’s a very specialised function which is only called as part of the stats->object RPC, like so: `{"action":"stats","type":"objects"}` -##### Initial output when running the node -When the node is run it prints out some information about the database used, compiler etc. An example of appending to the output is here: https://github.com/nanocurrency/nano-node/pull/2807 +--- -##### Pruning +## Pruning Pruning occurs periodically inside `nano::node::ongoing_ledger_pruning ()`. Pruning currently requires a full ledger to be bootstrapped and when an account frontier is confirmed it can then be pruned. The hashes of the pruned blocks are put into the pruned database so that we know to ignore any of these old blocks should the node bootstrap them again. Pending blocks cannot be pruned currently. -##### Removing old upgrade version support -Sometimes it is necessary/desired to remove being able to upgrade from specific versions. We dropped support for upgrades from v18 and earlier nodes in v1 using https://github.com/nanocurrency/nano-node/pull/2770 +--- -##### Config files -TOML config files are used, previously we used json files but TOML config files have the benefit of providing comments inside. There are few config files: -There are no versions or upgrades done here, instead any defaults not explicitly overridden in the toml file get updated implicitly. +## Config files +TOML config files are used, previously we used json files but TOML config files have the benefit of providing comments inside. There are no versions or upgrades done here, instead any defaults not explicitly overridden in the toml file get updated implicitly. There are few config files: -##### config-node.toml +### config-node.toml This is actually called `daemonconfig.cpp` in the code base, but it wraps a `node_config` object. -##### config-rpc.toml -##### config-wallet.toml -These contain settings which can be modified by the user to override the defaults. The most common ones are enabling rpc/websocket & rocksdb. +### Other config files +`config-rpc.toml` & `config-wallet.toml` contain settings which can be modified by the user to override the defaults. The most common ones are enabling rpc/websocket & rocksdb. + The `nano/node/node_rpc_config.cpp` are the rpc settings for the node. -##### CMakeLists.txt -CMake is used as the build system, and git submodules for any third party dependencies (except boost which must be installed separately by the developer). In `CMakeLists.txt` header files (.hpp) are above source files (.cpp), no particular reason but consistency is important. +--- -##### nano/boost -Use nano/boost/asio nano/boost/beast for includes, this wraps up various includes and prevents warnings being shown (particularly on Windows builds). +## Key resources -### Running tests -The dev network is forced for locally run tests, this lowers work and other settings to make it simpler to test. -Build with `cmake -DNANO_TEST=ON ..` -See docs.nano.org for more information. There may be intermittent failures, if so add them here https://github.com/nanocurrency/nano-node/issues/1121 and fix if possible. +**nanodb-specification & protocol repositories** -##### Testing implementation details -Sometimes it is necessary to be able to change something about a class only for a test. Rather than make this the class interface public just for tests, the specific tests can be added as friends to the class, this is done like so for a test named like so TEST (node, example); -``` -class my_class -{ -private: - int private_member; // the Test (node, example); test can access this member - friend class node_example_Test; -}; -``` -The test itself needs to be wrapped with the nano { } namespace for this to work correctly, if the class itself is in the nano namespace which is normally the case. - -##### nanodb-specification & protocol repositories There are 2 repositories which use kaitai specifications which should be updated (normally near the end of the release) if there are any changes to the https://github.com/nanocurrency/nanodb-specification or https://github.com/nanocurrency/protocol message -##### nano-docs +**nano-docs** + All RPC/CLI changes should have a documentation update specifying the version that they work. There is a documentation label in the nano-node repository which is useful as a reminder that they should be added, documentation updates are often overlooked. -##### Before a release the following should be done: -- Run tests with TSAN/ASAN/Valgrind. All errors should be fixed before launch unless these are determined to be test related or false positives. We currently have some errors with using coroutines. There are blacklist files for the sanitizers which remove some errors caused by lmdb & rocksdb. +**nano.community** + +A great community built resource for developers is https://nano.community/getting-started-devs/getting-started where broad details of the design are outlined along with code-level insights. + +--- -Tips: +## Other notes + +**All threads should have a name set** + +An easy example to follow is https://github.com/nanocurrency/nano-node/pull/2987/files This is so that debuggers/viewers which show threads can pick up the name to make it easier to navigate. It’s been known not to work in the Visual Studio Concurrency visualizer. + +**(de)serializing** + +Where possible we try and store primitives in big-endian. As most systems are little-endian this means using `boost::endian::native_to_big` on primitives when serializing and `boost::endian::big_to_native` when deserializing. + +**Signature checker** + +This is used by both blocks/votes and creates (total threads / 2) to perform signature verification of set batches; this is the biggest compute resource. Being able to lower this would be very beneficial, such as out of process sig verification and/or via GPU. + +**peers** + +Peers are written to disk periodically. This was added in https://github.com/nanocurrency/nano-node/pull/1608 +If the node has not been run in a long time (1 week), the peers list is cleared and the preconfigured peers list is used, this was added in https://github.com/nanocurrency/nano-node/pull/2506 + - Do not use the `node` object or include `node.hpp` in new core source files unless necessary, instead include the dependencies that it requires. We are still in the process of removing this idiom from other files because it adds circular dependencies, potentially ordering bugs and increases the build time. - Take care not to have nested `tx_begin_write ()`, it is quite easy to forget about this in tests, it will just cause a deadlock. To solve it, limit the scope: -- Pass `std::shared_ptr` parameters by reference where possible, https://github.com/nanocurrency/nano-node/pull/3029 -- Be cautious with random DB reads, they are much slower than sequential reads. This PR sped up the delegators by a factor of 100 RPC by removing the block_get call needed in the loop. https://github.com/nanocurrency/nano-node/pull/2283 -``` -{ // Limit scope -auto transaction = store->tx_begin_write (); -block_put (store.tx_begin_write (), block); -} -… -auto transaction = store->tx_begin_write (); -``` -or if it’s a single write can create a temporary just for that use: -`block_put (store.tx_begin_write (), block);` -Be cautious with callback lifetimes with asynchronous callbacks, such as the worker, alarm and asio. The following issue was because of them: -``` -int x = 4; -worker.push_back ([&x]() { - std::cout << x; // x might not be valid by the time this is called, should have been a copy. -}); -``` + - Pass `std::shared_ptr` parameters by reference where possible, https://github.com/nanocurrency/nano-node/pull/3029 + - Be cautious with random DB reads, they are much slower than sequential reads. This PR sped up the delegators by a factor of 100 RPC by removing the block_get call needed in the loop. https://github.com/nanocurrency/nano-node/pull/2283 + ``` + { // Limit scope + auto transaction = store->tx_begin_write (); + block_put (store.tx_begin_write (), block); + } + … + auto transaction = store->tx_begin_write (); + ``` + or if it’s a single write can create a temporary just for that use: + `block_put (store.tx_begin_write (), block);` + Be cautious with callback lifetimes with asynchronous callbacks, such as the worker, alarm and asio. The following issue was because of them: + ``` + int x = 4; + worker.push_back ([&x]() { + std::cout << x; // x might not be valid by the time this is called, should have been a copy. + }); + ``` - Currently using C++17 with Boost 1.70, at the time of writing C++20 is still not fully implemented by any of the major standards compliant compilers. It may be considered for inclusion no earlier than 2022 at which point Linux LTS versions should support it through the default repositories. -There are known exceptions triggered when `consume_future` is called do not be alarmed when seeing this. -Areas of future improvement: +- There are known exceptions triggered when `consume_future` is called do not be alarmed when seeing this. + +## Areas of future improvement + - A lot of tests still use legacy blocks, any new ones should use state blocks. - Minimise heap allocation. This can lead to fragmentation which affects long running processes. - `slow_test` is not run as part of CI -##### FAQs -Where are blocks added to the ledger? -`nano::ledger::process ()` +## FAQs -Where are rpc calls handled? -**nano/node/json_handler.cpp** +- Where are blocks added to the ledger? `nano::ledger::process ()` -Where is the genesis block created? -`nano::blockstore_partial::init ()` +- Where are rpc calls handled? `nano/node/json_handler.cpp` -How to stop the node effectively? -`rpc->stop ();` +- Where is the genesis block created? `nano::blockstore_partial::init ()` -How to use RocksDB in tests? -Set the environment variable: `TEST_USE_ROCKSDB=1` +- How to stop the node effectively? `rpc->stop ();` -[^1]: http://www.acodersjourney.com/2016/02/c-11-auto/ -[^2]: https://help.github.com/articles/resolving-merge-conflicts-after-a-git-rebase/ -[^3]: https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/ -[^4]: https://github.com/todotxt/todo.txt-android/wiki/Squash-All-Commits-Related-to-a-Single-Issue-into-a-Single-Commit -[^5]: https://dmitryfrank.com/articles/indent_with_tabs_align_with_spaces +- How to use RocksDB in tests? Set the environment variable: `TEST_USE_ROCKSDB=1` \ No newline at end of file diff --git a/docs/what-is-nano/living-whitepaper.md b/docs/living-whitepaper/index.md similarity index 92% rename from docs/what-is-nano/living-whitepaper.md rename to docs/living-whitepaper/index.md index 27363b976..b72b8555e 100644 --- a/docs/what-is-nano/living-whitepaper.md +++ b/docs/living-whitepaper/index.md @@ -1,9 +1,3 @@ ---- -hide: - - navigation - - toc ---- - title: Living Whitepaper description: Overview of the living whitepaper on the Nano protocol and existing node implementation @@ -17,7 +11,7 @@ The original whitepaper for Nano was last updated in November 2017 and since the ## Protocol vs. Node -The two main sections of the Living Whitepaper are the [Protocol Design](../protocol-design/introduction.md) and [Node Implementation](../node-implementation/introduction.md). Although they were structured to split the required elements to conform to the protocol (Protocol Design) away from optional improvements built into the current node (Node Implementation), there is some overlap between them. Where possible these overlaps have been highlighted; however, those interested in [contributing to the development of the protocol](../node-implementation/contributing.md) or building another node implementation should analyze more closely the differences between these to ensure the necessary rules are followed. +The two main sections of the Living Whitepaper are the [Protocol Design](../protocol-design/introduction.md) and [Node Implementation](../node-implementation/introduction.md). Although they were structured to split the required elements to conform to the protocol (Protocol Design) away from optional improvements built into the current node (Node Implementation), there is some overlap between them. Where possible these overlaps have been highlighted; however, those interested in [contributing to the development of the protocol](../core-development/overview.md) or building another node implementation should analyze more closely the differences between these to ensure the necessary rules are followed. ### [Protocol Design](../protocol-design/introduction.md) diff --git a/docs/protocol-design/introduction.md b/docs/protocol-design/introduction.md index 71f16a31d..e2e6bcc51 100644 --- a/docs/protocol-design/introduction.md +++ b/docs/protocol-design/introduction.md @@ -6,13 +6,13 @@ description: As the beginning of the living whitepaper, get details and backgrou --8<-- "wip-living-whitepaper.md" !!! tip "Contributing to the protocol" - If you are interested in helping develop the Nano protocol check out our details on [contributing code to the Nano node](../node-implementation/contributing.md) as a starting point to understanding the current implementation contributions, as these are often tightly coupled with protocol-related changes. + If you are interested in helping develop the Nano protocol check out our details on [contributing code to the Nano node](../core-development/overview.md) as a starting point to understanding the current implementation contributions, as these are often tightly coupled with protocol-related changes. --- ## Living Whitepaper Information -The following sections of the [Living Whitepaper](../what-is-nano/living-whitepaper.md) outline the design of the Nano protocol. The focus here is providing details of the blueprints for the different messages shared between nodes which allow data to be stored and communicated consistently across the network. The following Protocol Design sections are largely required to participate on the network, while the [Node Implementation](../node-implementation/introduction.md) sections primarily cover functionality that improves performance and security through a specific node design. +The following sections of the [Living Whitepaper](../living-whitepaper/index.md) outline the design of the Nano protocol. The focus here is providing details of the blueprints for the different messages shared between nodes which allow data to be stored and communicated consistently across the network. The following Protocol Design sections are largely required to participate on the network, while the [Node Implementation](../node-implementation/introduction.md) sections primarily cover functionality that improves performance and security through a specific node design. ## Abstract diff --git a/docs/snippets/security-vulnerability-reporting.md b/docs/snippets/security-vulnerability-reporting.md new file mode 100644 index 000000000..5f47de837 --- /dev/null +++ b/docs/snippets/security-vulnerability-reporting.md @@ -0,0 +1,13 @@ +!!! warning "Submit vulnerabilities privately" + **Do NOT discuss potential security vulnerabilities on the issue tracker, public forums or open discussion channels. Submit sensitive issues privately to the Nano Foundation for review.** + +If you discover a bug you believe to pose a security risk to the Nano network, please contact security@nano.org with a proof of concept with full details of the bug including: + +* Repository of the bug +* High-level summary +* Detailed description +* Steps to reproduce +* Supporting material/references +* The potential security impact of the bug + +It is strongly recommended to encrypt the email using GPG and the pubkeys for this purpose can be found on the [SECURITY file](https://github.com/nanocurrency/nano-node/blob/develop/SECURITY.md) in the node repository. The Nano Foundation will work to determine potential impacts and coordinate resolution in a node release. \ No newline at end of file diff --git a/docs/what-is-nano/overview.md b/docs/what-is-nano/overview.md index c66cef23e..7e353711e 100644 --- a/docs/what-is-nano/overview.md +++ b/docs/what-is-nano/overview.md @@ -48,7 +48,7 @@ Nano was designed with new data structures, consensus mechanisms and other featu ### Exploring More -* Looking for technical details of the protocol and node design? Click **Next** below to learn about the [Living Whitepaper](/what-is-nano/living-whitepaper/) +* Looking for technical details of the protocol and node design? Check out the [Living Whitepaper](/living-whitepaper/index.md) * Ready to participate on the network? Try [running a node](/running-a-node/overview), [review integration options](/integration-guides/the-basics) or find commands via [RPC](/commands/rpc-protocol) and [CLI](/commands/command-line-interface) * Want to know the future of Nano? See the [upcoming features](/releases/upcoming-features/) for the node or help shape the future by [contributing to the development of the protocol](/node-implementation/contributing) if you can! * Want to explore less technical aspects of Nano or join our community? Head over to [Nano.org](https://nano.org) diff --git a/docs/whitepaper/english.md b/docs/whitepaper/english.md index 2bd25c401..2426e2e2a 100644 --- a/docs/whitepaper/english.md +++ b/docs/whitepaper/english.md @@ -6,7 +6,7 @@ description: An HTML-based version of the original RaiBlocks/Nano whitepaper las _Last updated: November 2017_ !!! info - This original whitepaper contains details about the protocol which are no longer accurate, such as voting only being performed on blocks for which forks were detected, but is being left intact for historical reference purposes. For more accurate details, head over to the [Living Whitepaper](../what-is-nano/living-whitepaper.md) section. + This original whitepaper contains details about the protocol which are no longer accurate, such as voting only being performed on blocks for which forks were detected, but is being left intact for historical reference purposes. For more accurate details, head over to the [Living Whitepaper](../living-whitepaper/index.md) section. ## Introduction diff --git a/mkdocs.yml b/mkdocs.yml index 195ac656f..0e565e4f4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -26,10 +26,11 @@ theme: - search.share - search.suggest - content.tabs.link + - navigation.indexes + - navigation.expand nav: - Home: index.md - What is Nano?: what-is-nano/overview.md - - Living Whitepaper: what-is-nano/living-whitepaper.md - Running a Node: - Overview: running-a-node/overview.md - Security: running-a-node/security.md @@ -53,30 +54,36 @@ nav: - WebSockets: integration-guides/websockets.md - IPC Integration: integration-guides/ipc-integration.md - Advanced: integration-guides/advanced.md + - Living Whitepaper: + - living-whitepaper/index.md + - Protocol Design: + - Introduction: protocol-design/introduction.md + - Ledger: protocol-design/ledger.md + - Blocks: protocol-design/blocks.md + - Work: protocol-design/work.md + - Networking: protocol-design/networking.md + - ORV Consensus: protocol-design/orv-consensus.md + - Attack Vectors: protocol-design/attack-vectors.md + - Resource Usage: protocol-design/resource-usage.md + - Distribution and Units: protocol-design/distribution-and-units.md + - Signing, Hashing and Key Derivation: protocol-design/signing-hashing-and-key-derivation.md + - Original whitepaper: whitepaper/english.md + - Node Implementation: + - Introduction: node-implementation/introduction.md + - Components: node-implementation/components.md + - Database: node-implementation/database.md + - Blocks: node-implementation/blocks.md + - Networking: node-implementation/networking.md + - Voting: node-implementation/voting.md + - Work: node-implementation/work.md + - Core Development: + - Overview: core-development/overview.md + - Collaboration Process: core-development/collaboration-process.md + - Code Standards: core-development/code-standards.md + - Understanding the Code: core-development/understanding-the-code.md - Commands: - RPC Protocol: commands/rpc-protocol.md - Command Line Interface: commands/command-line-interface.md - - Protocol Design: - - Introduction: protocol-design/introduction.md - - Ledger: protocol-design/ledger.md - - Blocks: protocol-design/blocks.md - - Work: protocol-design/work.md - - Networking: protocol-design/networking.md - - ORV Consensus: protocol-design/orv-consensus.md - - Attack Vectors: protocol-design/attack-vectors.md - - Resource Usage: protocol-design/resource-usage.md - - Distribution and Units: protocol-design/distribution-and-units.md - - Signing, Hashing and Key Derivation: protocol-design/signing-hashing-and-key-derivation.md - - Original whitepaper: whitepaper/english.md - - Node Implementation: - - Introduction: node-implementation/introduction.md - - Components: node-implementation/components.md - - Database: node-implementation/database.md - - Blocks: node-implementation/blocks.md - - Networking: node-implementation/networking.md - - Voting: node-implementation/voting.md - - Work: node-implementation/work.md - - Contributing: node-implementation/contributing.md - Releases: - Node Releases: releases/node-releases.md - Release Notes: @@ -165,8 +172,9 @@ plugins: redirect_maps: 'running-a-node/rocksdb-ledger-backend.md': 'running-a-node/ledger-management.md' 'protocol-design/network-attacks.md': 'protocol-design/attack-vectors.md' - 'what-is-nano/contributing.md': 'node-implementation/contributing.md' + 'what-is-nano/contributing.md': 'core-development/overview.md' 'what-is-nano/exploring-more.md': 'what-is-nano/overview.md' 'releases/roadmap.md': 'https://github.com/orgs/nanocurrency/projects/5' 'releases/upcoming-features.md': 'https://github.com/orgs/nanocurrency/projects/5' 'releases/current-release-notes.md': 'releases/release-v22-1.md' + 'node-implementation/contributing.md': 'core-development/overview.md'