diff --git a/.github/scripts/levelization/README.md b/.github/scripts/levelization/README.md
index 93748c43e1..70d19b63ba 100644
--- a/.github/scripts/levelization/README.md
+++ b/.github/scripts/levelization/README.md
@@ -1,34 +1,19 @@
# Levelization
-Levelization is the term used to describe efforts to prevent xrpld from
-having or creating cyclic dependencies.
+Levelization is the term used to describe efforts to prevent xrpld from having or creating cyclic dependencies.
-xrpld code is organized into directories under `src/xrpld`, `src/libxrpl` (and
-`src/test`) representing modules. The modules are intended to be
-organized into "tiers" or "levels" such that a module from one level can
-only include code from lower levels. Additionally, a module
-in one level should never include code in an `impl` or `detail` folder of any level
-other than its own.
+xrpld code is organized into directories under `src/xrpld`, `src/libxrpl` (and `src/test`) representing modules. The modules are intended to be organized into "tiers" or "levels" such that a module from one level can only include code from lower levels. Additionally, a module in one level should never include code in an `impl` or `detail` folder of any level other than its own.
The codebase is split into two main areas:
- **libxrpl** (`src/libxrpl`, `include/xrpl`): Reusable library modules with public interfaces
- **xrpld** (`src/xrpld`): Application-specific implementation code
-Unfortunately, over time, enforcement of levelization has been
-inconsistent, so the current state of the code doesn't necessarily
-reflect these rules. Whenever possible, developers should refactor any
-levelization violations they find (by moving files or individual
-classes). At the very least, don't make things worse.
+Unfortunately, over time, enforcement of levelization has been inconsistent, so the current state of the code doesn't necessarily reflect these rules. Whenever possible, developers should refactor any levelization violations they find (by moving files or individual classes). At the very least, don't make things worse.
-The table below summarizes the _desired_ division of modules, based on the current
-state of the xrpld code. The levels are numbered from
-the bottom up with the lower level, lower numbered, more independent
-modules listed first, and the higher level, higher numbered modules with
-more dependencies listed later.
+The table below summarizes the _desired_ division of modules, based on the current state of the xrpld code. The levels are numbered from the bottom up with the lower level, lower numbered, more independent modules listed first, and the higher level, higher numbered modules with more dependencies listed later.
-**tl;dr:** The modules listed first are more independent than the modules
-listed later.
+**tl;dr:** The modules listed first are more independent than the modules listed later.
## libxrpl Modules (Reusable Libraries)
@@ -55,80 +40,37 @@ listed later.
## Test Modules
-| Level / Tier | Module(s) |
-| ------------ | -------------------------------------------------------------------------------------------------------- |
-| 11 | test/jtx test/beast test/csf |
-| 12 | test/unit_test |
-| 13 | test/crypto test/conditions test/json test/resource test/shamap test/peerfinder test/basics test/overlay |
-| 14 | test |
-| 15 | test/net test/protocol test/ledger test/consensus test/core test/server test/nodestore |
-| 16 | test/rpc test/app |
+| Level / Tier | Module(s) |
+| --- | --- |
+| 11 | test/jtx test/beast test/csf |
+| 12 | test/unit_test |
+| 13 | test/crypto test/conditions test/json test/resource test/shamap test/peerfinder test/basics test/overlay |
+| 14 | test |
+| 15 | test/net test/protocol test/ledger test/consensus test/core test/server test/nodestore |
+| 16 | test/rpc test/app |
-(Note that `test` levelization is _much_ less important and _much_ less
-strictly enforced than `xrpl`/`xrpld` levelization, other than the requirement
-that `test` code should _never_ be included in `xrpl` or `xrpld` code.)
+(Note that `test` levelization is _much_ less important and _much_ less strictly enforced than `xrpl`/`xrpld` levelization, other than the requirement that `test` code should _never_ be included in `xrpl` or `xrpld` code.)
## Validation
-The [levelization](generate.py) script takes no parameters,
-reads no environment variables, and can be run from any directory,
-as long as it is in the expected location in the xrpld repo.
-It can be run at any time from within a checked out repo, and will
-do an analysis of all the `#include`s in
-the xrpld source. The only caveat is that it runs much slower
-under Windows than in Linux. It hasn't yet been tested under MacOS.
-It generates many files of [results](results):
+The [levelization](generate.py) script takes no parameters, reads no environment variables, and can be run from any directory, as long as it is in the expected location in the xrpld repo. It can be run at any time from within a checked out repo, and will do an analysis of all the `#include`s in the xrpld source. The only caveat is that it runs much slower under Windows than in Linux. It hasn't yet been tested under MacOS. It generates many files of [results](results):
- `rawincludes.txt`: The raw dump of the `#includes`
-- `paths.txt`: A second dump grouping the source module
- to the destination module, de-duped, and with frequency counts.
-- `includes/`: A directory where each file represents a module and
- contains a list of modules and counts that the module _includes_.
-- `included_by/`: Similar to `includes/`, but the other way around. Each
- file represents a module and contains a list of modules and counts
- that _include_ the module.
-- [`loops.txt`](results/loops.txt): A list of direct loops detected
- between modules as they actually exist, as opposed to how they are
- desired as described above. In a perfect repo, this file will be
- empty.
- This file is committed to the repo, and is used by the [levelization
- Github workflow](../../workflows/reusable-check-levelization.yml) to validate
- that nothing changed.
-- [`ordering.txt`](results/ordering.txt): A list showing relationships
- between modules where there are no loops as they actually exist, as
- opposed to how they are desired as described above.
- This file is committed to the repo, and is used by the [levelization
- Github workflow](../../workflows/reusable-check-levelization.yml) to validate
- that nothing changed.
-- [`levelization.yml`](../../workflows/reusable-check-levelization.yml)
- Github Actions workflow to test that levelization loops haven't
- changed. Unfortunately, if changes are detected, it can't tell if
- they are improvements or not, so if you have resolved any issues or
- done anything else to improve levelization, run `generate.py`,
- and commit the updated results.
+- `paths.txt`: A second dump grouping the source module to the destination module, de-duped, and with frequency counts.
+- `includes/`: A directory where each file represents a module and contains a list of modules and counts that the module _includes_.
+- `included_by/`: Similar to `includes/`, but the other way around. Each file represents a module and contains a list of modules and counts that _include_ the module.
+- [`loops.txt`](results/loops.txt): A list of direct loops detected between modules as they actually exist, as opposed to how they are desired as described above. In a perfect repo, this file will be empty. This file is committed to the repo, and is used by the [levelization Github workflow](../../workflows/reusable-check-levelization.yml) to validate that nothing changed.
+- [`ordering.txt`](results/ordering.txt): A list showing relationships between modules where there are no loops as they actually exist, as opposed to how they are desired as described above. This file is committed to the repo, and is used by the [levelization Github workflow](../../workflows/reusable-check-levelization.yml) to validate that nothing changed.
+- [`levelization.yml`](../../workflows/reusable-check-levelization.yml) Github Actions workflow to test that levelization loops haven't changed. Unfortunately, if changes are detected, it can't tell if they are improvements or not, so if you have resolved any issues or done anything else to improve levelization, run `generate.py`, and commit the updated results.
-The `loops.txt` and `ordering.txt` files relate the modules
-using comparison signs, which indicate the number of times each
-module is included in the other.
+The `loops.txt` and `ordering.txt` files relate the modules using comparison signs, which indicate the number of times each module is included in the other.
-- `A > B` means that A should probably be at a higher level than B,
- because B is included in A significantly more than A is included in B.
- These results can be included in both `loops.txt` and `ordering.txt`.
- Because `ordering.txt`only includes relationships where B is not
- included in A at all, it will only include these types of results.
-- `A ~= B` means that A and B are included in each other a different
- number of times, but the values are so close that the script can't
- definitively say that one should be above the other. These results
- will only be included in `loops.txt`.
-- `A == B` means that A and B include each other the same number of
- times, so the script has no clue which should be higher. These results
- will only be included in `loops.txt`.
+- `A > B` means that A should probably be at a higher level than B, because B is included in A significantly more than A is included in B. These results can be included in both `loops.txt` and `ordering.txt`. Because `ordering.txt`only includes relationships where B is not included in A at all, it will only include these types of results.
+- `A ~= B` means that A and B are included in each other a different number of times, but the values are so close that the script can't definitively say that one should be above the other. These results will only be included in `loops.txt`.
+- `A == B` means that A and B include each other the same number of times, so the script has no clue which should be higher. These results will only be included in `loops.txt`.
-The committed files hide the detailed values intentionally, to
-prevent false alarms and merging issues, and because it's easy to
-get those details locally.
+The committed files hide the detailed values intentionally, to prevent false alarms and merging issues, and because it's easy to get those details locally.
1. Run `generate.py`
2. Grep the modules in `paths.txt`.
- - For example, if a cycle is found `A ~= B`, simply `grep -w
-A .github/scripts/levelization/results/paths.txt | grep -w B`
+ - For example, if a cycle is found `A ~= B`, simply `grep -w A .github/scripts/levelization/results/paths.txt | grep -w B`
diff --git a/.github/scripts/rename/README.md b/.github/scripts/rename/README.md
index ab685bb0c3..a1ef1dcb00 100644
--- a/.github/scripts/rename/README.md
+++ b/.github/scripts/rename/README.md
@@ -1,41 +1,20 @@
## Renaming ripple(d) to xrpl(d)
-In the initial phases of development of the XRPL, the open source codebase was
-called "rippled" and it remains with that name even today. Today, over 1000
-nodes run the application, and code contributions have been submitted by
-developers located around the world. The XRPL community is larger than ever.
-In light of the decentralized and diversified nature of XRPL, we will rename any
-references to `ripple` and `rippled` to `xrpl` and `xrpld`, when appropriate.
+In the initial phases of development of the XRPL, the open source codebase was called "rippled" and it remains with that name even today. Today, over 1000 nodes run the application, and code contributions have been submitted by developers located around the world. The XRPL community is larger than ever. In light of the decentralized and diversified nature of XRPL, we will rename any references to `ripple` and `rippled` to `xrpl` and `xrpld`, when appropriate.
-See [here](https://xls.xrpl.org/xls/XLS-0095-rename-rippled-to-xrpld.html) for
-more information.
+See [here](https://xls.xrpl.org/xls/XLS-0095-rename-rippled-to-xrpld.html) for more information.
### Scripts
-To facilitate this transition, there will be multiple scripts that developers
-can run on their own PRs and forks to minimize conflicts. Each script should be
-run from the repository root.
+To facilitate this transition, there will be multiple scripts that developers can run on their own PRs and forks to minimize conflicts. Each script should be run from the repository root.
-1. `.github/scripts/rename/definitions.sh`: This script will rename all
- definitions, such as include guards, from `RIPPLE_XXX` and `RIPPLED_XXX` to
- `XRPL_XXX`.
-2. `.github/scripts/rename/copyright.sh`: This script will remove superfluous
- copyright notices.
-3. `.github/scripts/rename/cmake.sh`: This script will rename all CMake files
- from `RippleXXX.cmake` or `RippledXXX.cmake` to `XrplXXX.cmake`, and any
- references to `ripple` and `rippled` (with or without capital letters) to
- `xrpl` and `xrpld`, respectively. The name of the binary will remain as-is,
- and will only be renamed to `xrpld` by a later script.
-4. `.github/scripts/rename/binary.sh`: This script will rename the binary from
- `rippled` to `xrpld`, and reverses the symlink so that `rippled` points to
- the `xrpld` binary.
-5. `.github/scripts/rename/namespace.sh`: This script will rename the C++
- namespaces from `ripple` to `xrpl`.
-6. `.github/scripts/rename/config.sh`: This script will rename the config from
- `rippled.cfg` to `xrpld.cfg`, and updating the code accordingly. The old
- filename will still be accepted.
-7. `.github/scripts/rename/docs.sh`: This script will rename any lingering
- references of `ripple(d)` to `xrpl(d)` in code, comments, and documentation.
+1. `.github/scripts/rename/definitions.sh`: This script will rename all definitions, such as include guards, from `RIPPLE_XXX` and `RIPPLED_XXX` to `XRPL_XXX`.
+2. `.github/scripts/rename/copyright.sh`: This script will remove superfluous copyright notices.
+3. `.github/scripts/rename/cmake.sh`: This script will rename all CMake files from `RippleXXX.cmake` or `RippledXXX.cmake` to `XrplXXX.cmake`, and any references to `ripple` and `rippled` (with or without capital letters) to `xrpl` and `xrpld`, respectively. The name of the binary will remain as-is, and will only be renamed to `xrpld` by a later script.
+4. `.github/scripts/rename/binary.sh`: This script will rename the binary from `rippled` to `xrpld`, and reverses the symlink so that `rippled` points to the `xrpld` binary.
+5. `.github/scripts/rename/namespace.sh`: This script will rename the C++ namespaces from `ripple` to `xrpl`.
+6. `.github/scripts/rename/config.sh`: This script will rename the config from `rippled.cfg` to `xrpld.cfg`, and updating the code accordingly. The old filename will still be accepted.
+7. `.github/scripts/rename/docs.sh`: This script will rename any lingering references of `ripple(d)` to `xrpl(d)` in code, comments, and documentation.
You can run all these scripts from the repository root as follows:
diff --git a/.prettierrc.yaml b/.prettierrc.yaml
new file mode 100644
index 0000000000..e22940a04d
--- /dev/null
+++ b/.prettierrc.yaml
@@ -0,0 +1,7 @@
+# Collapse hard-wrapped Markdown prose to one line per paragraph instead of
+# preserving manual line breaks (the prettier default). Scoped to Markdown
+# only, since proseWrap also reflows YAML block scalars.
+overrides:
+ - files: "*.md"
+ options:
+ proseWrap: never
diff --git a/API-CHANGELOG.md b/API-CHANGELOG.md
index df58282f76..7c19da9ca4 100644
--- a/API-CHANGELOG.md
+++ b/API-CHANGELOG.md
@@ -28,8 +28,7 @@ This section contains changes targeting a future version.
### Additions
-- `account_tx`: Added an optional `delegate` request object to filter delegated transactions. The object requires `delegate_filter`, which must be either `actor` for transactions owned by the requested account but signed by another account, or `authorizer` for transactions signed by the requested account on behalf of another account. The optional `counter_party` account narrows the results to a specific signer/delegate for `actor` or a specific owner/delegator for `authorizer`. Malformed `delegate`, `delegate_filter`, and `counter_party` values return standard invalid field errors, and invalid account IDs return `actMalformed`.
- When paginating delegate-filtered queries, a marker from a delegate-filtered query includes a `delegate` flag and is only valid for follow-up requests that also supply `delegate` (mixing marker conventions returns `invalidParams`). Because filtering is applied after the ledger scan, a page may contain fewer results than `limit` (possibly zero) while still returning a marker, so callers must continue until no marker is present.
+- `account_tx`: Added an optional `delegate` request object to filter delegated transactions. The object requires `delegate_filter`, which must be either `actor` for transactions owned by the requested account but signed by another account, or `authorizer` for transactions signed by the requested account on behalf of another account. The optional `counter_party` account narrows the results to a specific signer/delegate for `actor` or a specific owner/delegator for `authorizer`. Malformed `delegate`, `delegate_filter`, and `counter_party` values return standard invalid field errors, and invalid account IDs return `actMalformed`. When paginating delegate-filtered queries, a marker from a delegate-filtered query includes a `delegate` flag and is only valid for follow-up requests that also supply `delegate` (mixing marker conventions returns `invalidParams`). Because filtering is applied after the ledger scan, a page may contain fewer results than `limit` (possibly zero) while still returning a marker, so callers must continue until no marker is present.
- `ledger_entry`, `account_objects`: The `Delegate` ledger entry now includes an optional `DestinationNode` field, which stores the index into the authorized account's owner directory. This field is present on entries created after bidirectional directory tracking was introduced and may appear in RPC responses for those entries. ([#6681](https://github.com/XRPLF/rippled/pull/6681))
- `server_definitions`: Added the following new sections to the response ([#6321](https://github.com/XRPLF/rippled/pull/6321)):
- `TRANSACTION_FORMATS`: Describes the fields and their optionality for each transaction type, including common fields shared across all transactions.
@@ -208,9 +207,7 @@ This release contains bug fixes only and no API changes.
- Adds `AMMDelete` transaction type to delete `AMM` instance.
- Adds `sfAMMID` to `AccountRoot` to indicate that the account is `AMM`'s account. `AMMID` is used to fetch `ltAMM`.
- Adds `lsfAMMNode` `TrustLine` flag to indicate that one side of the `TrustLine` is `AMM` account.
- - Adds `tfLPToken`, `tfSingleAsset`, `tfTwoAsset`, `tfOneAssetLPToken`, `tfLimitLPToken`, `tfTwoAssetIfEmpty`,
- `tfWithdrawAll`, `tfOneAssetWithdrawAll` which allow a trader to specify different fields combination
- for `AMMDeposit` and `AMMWithdraw` transactions.
+ - Adds `tfLPToken`, `tfSingleAsset`, `tfTwoAsset`, `tfOneAssetLPToken`, `tfLimitLPToken`, `tfTwoAssetIfEmpty`, `tfWithdrawAll`, `tfOneAssetWithdrawAll` which allow a trader to specify different fields combination for `AMMDeposit` and `AMMWithdraw` transactions.
- Adds new transaction result codes:
- tecUNFUNDED_AMM: insufficient balance to fund AMM. The account does not have funds for liquidity provision.
- tecAMM_BALANCE: AMM has invalid balance. Calculated balances greater than the current pool balances.
@@ -253,14 +250,11 @@ This release contains bug fixes only and no API changes.
## XRP Ledger server version 1.10.0
-[Version 1.10.0](https://github.com/XRPLF/rippled/releases/tag/1.10.0)
-was released on Mar 14, 2023.
+[Version 1.10.0](https://github.com/XRPLF/rippled/releases/tag/1.10.0) was released on Mar 14, 2023.
### Breaking changes in 1.10
-- If the `XRPFees` feature is enabled, the `fee_ref` field will be
- removed from the [ledger subscription stream](https://xrpl.org/subscribe.html#ledger-stream), because it will no longer
- have any meaning.
+- If the `XRPFees` feature is enabled, the `fee_ref` field will be removed from the [ledger subscription stream](https://xrpl.org/subscribe.html#ledger-stream), because it will no longer have any meaning.
# Unit tests for API changes
diff --git a/API-VERSION-2.md b/API-VERSION-2.md
index eaf626099c..10ff77dd88 100644
--- a/API-VERSION-2.md
+++ b/API-VERSION-2.md
@@ -13,8 +13,7 @@ In API version 2, the following deprecated methods are no longer available: ([#4
## Modifications to JSON transaction element in API version 2
-In API version 2, JSON elements for transaction output have been changed and made consistent for all methods which output transactions. ([#4775](https://github.com/XRPLF/rippled/pull/4775))
-This helps to unify the JSON serialization format of transactions. ([clio#722](https://github.com/XRPLF/clio/issues/722), [#4727](https://github.com/XRPLF/rippled/issues/4727))
+In API version 2, JSON elements for transaction output have been changed and made consistent for all methods which output transactions. ([#4775](https://github.com/XRPLF/rippled/pull/4775)) This helps to unify the JSON serialization format of transactions. ([clio#722](https://github.com/XRPLF/clio/issues/722), [#4727](https://github.com/XRPLF/rippled/issues/4727))
- JSON transaction element is named `tx_json`
- Binary transaction element is named `tx_blob`
diff --git a/BUILD.md b/BUILD.md
index e98d204d0b..8ef5e07ecc 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -1,91 +1,68 @@
-| :warning: **WARNING** :warning: |
-| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| :warning: **WARNING** :warning: |
+| --- |
| These instructions assume you have a C++ development environment ready with Git, Python, Conan, CMake, and a C++ compiler. For help setting one up on Linux, macOS, or Windows, [see this guide](./docs/build/environment.md).
These instructions also assume a basic familiarity with Conan and CMake. If you are unfamiliar with Conan, you can read our [crash course](./docs/build/conan.md) or the official [Getting Started][conan-getting-started] walkthrough. |
## Minimum Requirements
-For the hardware needed to run a node, see
-[System Requirements](https://xrpl.org/system-requirements.html).
+For the hardware needed to run a node, see [System Requirements](https://xrpl.org/system-requirements.html).
-For the software needed to build xrpld, see the
-[environment setup guide](./docs/build/environment.md).
+For the software needed to build xrpld, see the [environment setup guide](./docs/build/environment.md).
## Operating Systems
### Linux
-The Ubuntu Linux distribution has received the highest level of quality
-assurance, testing, and support. We also support Red Hat and use Debian
-internally.
-Our Linux CI tooling is distro-independent and uses a Nix-based environment, so it should be possible to build on other Linux distributions as well, although we have not tested them.
+The Ubuntu Linux distribution has received the highest level of quality assurance, testing, and support. We also support Red Hat and use Debian internally. Our Linux CI tooling is distro-independent and uses a Nix-based environment, so it should be possible to build on other Linux distributions as well, although we have not tested them.
### macOS
-Many `xrpld` engineers use macOS for development.
-The minimum supported version is macOS 15 (Sequoia).
-CI testing is done in macOS 26 (Tahoe), but the build defaults `CMAKE_OSX_DEPLOYMENT_TARGET` to 15.
+Many `xrpld` engineers use macOS for development. The minimum supported version is macOS 15 (Sequoia). CI testing is done in macOS 26 (Tahoe), but the build defaults `CMAKE_OSX_DEPLOYMENT_TARGET` to 15.
### Windows
-Windows is used by some engineers for development only, and is not recommended
-for production use.
+Windows is used by some engineers for development only, and is not recommended for production use.
## Steps
### Branches
-For the latest set of untested features, or to contribute, choose the `develop`
-branch.
+For the latest set of untested features, or to contribute, choose the `develop` branch.
```bash
git checkout develop
```
-For a release candidate, choose the relevant release branch, e.g.
-`release/3.2.x`.
+For a release candidate, choose the relevant release branch, e.g. `release/3.2.x`.
```bash
git checkout release/3.2.x
```
-For a stable release, choose one of the [tagged
-releases](https://github.com/XRPLF/rippled/releases).
+For a stable release, choose one of the [tagged releases](https://github.com/XRPLF/rippled/releases).
### Set Up Conan
-Once your [development environment](./docs/build/environment.md) is ready, set
-Conan up for this repository:
+Once your [development environment](./docs/build/environment.md) is ready, set Conan up for this repository:
```bash
./conan/init.sh
```
-That installs our [`global.conf`](./conan/global.conf), our Conan
-[profiles](./conan/profiles), and the `xrplf` remote that hosts some of our
-dependencies. It honours `CONAN_HOME` and never deletes an existing Conan home,
-so it is safe to re-run — it only overwrites the files it manages.
+That installs our [`global.conf`](./conan/global.conf), our Conan [profiles](./conan/profiles), and the `xrplf` remote that hosts some of our dependencies. It honours `CONAN_HOME` and never deletes an existing Conan home, so it is safe to re-run — it only overwrites the files it manages.
-> [!TIP]
-> In the [Nix development shell](./docs/build/nix.md#conan-configuration) this is
-> already done for you: the script runs on entry.
+> [!TIP] In the [Nix development shell](./docs/build/nix.md#conan-configuration) this is already done for you: the script runs on entry.
-You can inspect the resulting profile with `conan profile show`. If it is not
-suitable for your environment, create a custom profile and pass it to Conan — see
-[Advanced Conan configuration](./docs/build/advanced_conan.md).
+You can inspect the resulting profile with `conan profile show`. If it is not suitable for your environment, create a custom profile and pass it to Conan — see [Advanced Conan configuration](./docs/build/advanced_conan.md).
### Set Up Ccache
-To speed up repeated compilations, we recommend that you install
-[ccache](https://ccache.dev), a tool that wraps your compiler so that it can
-cache build objects locally.
+To speed up repeated compilations, we recommend that you install [ccache](https://ccache.dev), a tool that wraps your compiler so that it can cache build objects locally.
On Linux and macOS, `ccache` is included in the [Nix development shell](./docs/build/nix.md).
#### Windows
-You can install it using Chocolatey, i.e. `choco install ccache`. If you already
-have Ccache installed, then `choco upgrade ccache` will update it to the latest
-version. However, if you see an error such as:
+You can install it using Chocolatey, i.e. `choco install ccache`. If you already have Ccache installed, then `choco upgrade ccache` will update it to the latest version. However, if you see an error such as:
```
terminate called after throwing an instance of 'std::bad_alloc'
@@ -93,8 +70,7 @@ terminate called after throwing an instance of 'std::bad_alloc'
C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(617,5): error MSB6006: "cl.exe" exited with code 3.
```
-then please install a specific version of Ccache that we know works, via: `choco
-install ccache --version 4.11.3 --allow-downgrade`.
+then please install a specific version of Ccache that we know works, via: `choco install ccache --version 4.11.3 --allow-downgrade`.
### Build and Test
@@ -105,14 +81,9 @@ install ccache --version 4.11.3 --allow-downgrade`.
cd .build
```
- You can use any directory name. Conan treats your working directory as an
- install folder and generates files with implementation details.
- You don't need to worry about these files, but make sure to change
- your working directory to your build directory before calling Conan.
+ You can use any directory name. Conan treats your working directory as an install folder and generates files with implementation details. You don't need to worry about these files, but make sure to change your working directory to your build directory before calling Conan.
- **Note:** You can specify a directory for the installation files by adding
- the `install-folder` or `-if` option to every `conan install` command
- in the next step.
+ **Note:** You can specify a directory for the installation files by adding the `install-folder` or `-if` option to every `conan install` command in the next step.
2. Use conan to generate CMake files for every configuration you want to build:
@@ -123,25 +94,15 @@ install ccache --version 4.11.3 --allow-downgrade`.
To build Debug, in the next step, be sure to set `-DCMAKE_BUILD_TYPE=Debug`
- For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`,
- you only need to run this command once.
- For a multi-configuration generator, e.g. `Visual Studio`, you may want to
- run it more than once.
+ For a single-configuration generator, e.g. `Unix Makefiles` or `Ninja`, you only need to run this command once. For a multi-configuration generator, e.g. `Visual Studio`, you may want to run it more than once.
- Each of these commands should also have a different `build_type` setting.
- A second command with the same `build_type` setting will overwrite the files
- generated by the first. You can pass the build type on the command line with
- `--settings build_type=$BUILD_TYPE` or in the profile itself,
- under the section `[settings]` with the key `build_type`.
+ Each of these commands should also have a different `build_type` setting. A second command with the same `build_type` setting will overwrite the files generated by the first. You can pass the build type on the command line with `--settings build_type=$BUILD_TYPE` or in the profile itself, under the section `[settings]` with the key `build_type`.
-3. Configure CMake and pass the toolchain file generated by Conan, located at
- `$OUTPUT_FOLDER/build/generators/conan_toolchain.cmake`.
+3. Configure CMake and pass the toolchain file generated by Conan, located at `$OUTPUT_FOLDER/build/generators/conan_toolchain.cmake`.
Single-config generators:
- Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type]
- and make sure it matches the one of the `build_type` settings
- you chose in the previous step.
+ Pass the CMake variable [`CMAKE_BUILD_TYPE`][build_type] and make sure it matches the one of the `build_type` settings you chose in the previous step.
For example, to build Debug, in the next command, replace "Release" with "Debug"
@@ -159,9 +120,7 @@ install ccache --version 4.11.3 --allow-downgrade`.
4. Build `xrpld`.
- For a single-configuration generator, it will build whatever configuration
- you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator, you
- must pass the option `--config` to select the build configuration.
+ For a single-configuration generator, it will build whatever configuration you passed for `CMAKE_BUILD_TYPE`. For a multi-configuration generator, you must pass the option `--config` to select the build configuration.
Single-config generators:
@@ -176,8 +135,7 @@ install ccache --version 4.11.3 --allow-downgrade`.
cmake --build . --config Debug --parallel N
```
- Replace the `--parallel` parameter N with the desired number of parallel jobs. A common starting point is half of the number of available CPU
- cores.
+ Replace the `--parallel` parameter N with the desired number of parallel jobs. A common starting point is half of the number of available CPU cores.
5. Test xrpld.
@@ -194,28 +152,20 @@ install ccache --version 4.11.3 --allow-downgrade`.
./Debug/xrpld --unittest --unittest-jobs N
```
- Replace the `--unittest-jobs` parameter N with the desired unit tests
- concurrency. Recommended setting is half of the number of available CPU
- cores.
+ Replace the `--unittest-jobs` parameter N with the desired unit tests concurrency. Recommended setting is half of the number of available CPU cores.
- The location of `xrpld` binary in your build directory depends on your
- CMake generator. Pass `--help` to see the rest of the command line options.
+ The location of `xrpld` binary in your build directory depends on your CMake generator. Pass `--help` to see the rest of the command line options.
## Code generation
-The protocol wrapper classes in `include/xrpl/protocol_autogen/` are generated
-from macro definition files in `include/xrpl/protocol/detail/`. If you modify
-the macro files (e.g. `transactions.macro`, `ledger_entries.macro`) or the
-generation scripts/templates in `cmake/scripts/codegen/`, you need to regenerate the
-files:
+The protocol wrapper classes in `include/xrpl/protocol_autogen/` are generated from macro definition files in `include/xrpl/protocol/detail/`. If you modify the macro files (e.g. `transactions.macro`, `ledger_entries.macro`) or the generation scripts/templates in `cmake/scripts/codegen/`, you need to regenerate the files:
```
cmake --build . --target setup_code_gen # create venv and install dependencies (once)
cmake --build . --target code_gen # regenerate code
```
-The same targets are also available as a standalone project, which does not
-need the dependencies to be configured first:
+The same targets are also available as a standalone project, which does not need the dependencies to be configured first:
```
cmake -S cmake/codegen -B build/codegen
@@ -223,15 +173,11 @@ cmake --build build/codegen --target setup_code_gen
cmake --build build/codegen --target code_gen
```
-The regenerated files should be committed alongside your changes. CI verifies
-that they are up-to-date.
+The regenerated files should be committed alongside your changes. CI verifies that they are up-to-date.
## Coverage report
-The coverage report is intended for developers using compilers GCC
-or Clang (including Apple Clang). It is generated by the build target `coverage`,
-which is only enabled when the `coverage` option is set, e.g. with
-`--options coverage=True` in `conan` or `-Dcoverage=ON` variable in `cmake`
+The coverage report is intended for developers using compilers GCC or Clang (including Apple Clang). It is generated by the build target `coverage`, which is only enabled when the `coverage` option is set, e.g. with `--options coverage=True` in `conan` or `-Dcoverage=ON` variable in `cmake`
Prerequisites for the coverage report:
@@ -239,34 +185,17 @@ Prerequisites for the coverage report:
- `gcov` for GCC or `llvm-cov` for Clang, usually installed with the compiler
- `Debug` build type
-> [!NOTE]
-> Clang coverage is not available in the [Nix development shell](./docs/build/nix.md#building-xrpld-in-the-nix-shell):
-> its `clang` shells do not ship `llvm-cov`. Use a `gcc` shell instead (`.#gcc`,
-> or `.#gcc-plain` on Linux), which provides a `gcov` matching its compiler.
+> [!NOTE] Clang coverage is not available in the [Nix development shell](./docs/build/nix.md#building-xrpld-in-the-nix-shell): its `clang` shells do not ship `llvm-cov`. Use a `gcc` shell instead (`.#gcc`, or `.#gcc-plain` on Linux), which provides a `gcov` matching its compiler.
A coverage report is created when the following steps are completed, in order:
-1. `xrpld` binary built with instrumentation data, enabled by the `coverage`
- option mentioned above
+1. `xrpld` binary built with instrumentation data, enabled by the `coverage` option mentioned above
2. completed one or more run of the unit tests, which populates coverage capture data
-3. completed run of the `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`)
- to assemble both instrumentation data and the coverage capture data into a coverage report
+3. completed run of the `gcovr` tool (which internally invokes either `gcov` or `llvm-cov`) to assemble both instrumentation data and the coverage capture data into a coverage report
-The last step of the above is automated into a single target `coverage`. The instrumented
-`xrpld` binary can also be used for regular development or testing work, at
-the cost of extra disk space utilization and a small performance hit
-(to store coverage capture data). Since `xrpld` binary is simply a dependency of the
-coverage report target, it is possible to re-run the `coverage` target without
-rebuilding the `xrpld` binary. Note, running of the unit tests before the `coverage`
-target is left to the developer. Each such run will append to the coverage data
-collected in the build directory.
+The last step of the above is automated into a single target `coverage`. The instrumented `xrpld` binary can also be used for regular development or testing work, at the cost of extra disk space utilization and a small performance hit (to store coverage capture data). Since `xrpld` binary is simply a dependency of the coverage report target, it is possible to re-run the `coverage` target without rebuilding the `xrpld` binary. Note, running of the unit tests before the `coverage` target is left to the developer. Each such run will append to the coverage data collected in the build directory.
-The default coverage report format is `html-details`, but the user
-can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake`
-by setting the `coverage_format` variable in `cmake`. It is also possible
-to generate more than one format at a time by setting the `coverage_extra_args`
-variable in `cmake`. The specific command line used to run the `gcovr` tool will be
-displayed if the `CODE_COVERAGE_VERBOSE` variable is set.
+The default coverage report format is `html-details`, but the user can override it to any of the formats listed in `Builds/CMake/CodeCoverage.cmake` by setting the `coverage_format` variable in `cmake`. It is also possible to generate more than one format at a time by setting the `coverage_extra_args` variable in `cmake`. The specific command line used to run the `gcovr` tool will be displayed if the `CODE_COVERAGE_VERBOSE` variable is set.
Example use with some cmake variables set:
@@ -277,16 +206,14 @@ cmake -DCMAKE_BUILD_TYPE=Debug -Dcoverage=ON -Dxrpld=ON -Dtests=ON -Dcoverage_te
cmake --build . --target coverage
```
-After the `coverage` target is completed, the generated coverage report will be
-stored inside the build directory, as either of:
+After the `coverage` target is completed, the generated coverage report will be stored inside the build directory, as either of:
- file named `coverage.`_extension_, with a suitable extension for the report format, or
- directory named `coverage`, with the `index.html` and other files inside, for the `html-details` or `html-nested` report formats.
## Sanitizers
-To build dependencies and xrpld with sanitizer instrumentation, set the
-`SANITIZERS` environment variable when running `conan install` and use the `sanitizers` profile:
+To build dependencies and xrpld with sanitizer instrumentation, set the `SANITIZERS` environment variable when running `conan install` and use the `sanitizers` profile:
```bash
export SANITIZERS=address,undefinedbehavior
@@ -300,42 +227,27 @@ See [Sanitizers docs](./docs/build/sanitizers.md) for more details.
## Options
-| Option | Default Value | Description |
-| ---------------- | ------------- | ----------------------------------------------------------------------------- |
-| `assert` | OFF | Force enabling assertions. |
-| `coverage` | OFF | Prepare the coverage report. |
-| `rust` | OFF | Build the Rust crates and the C++ code that depends on them. |
-| `tests` | OFF | Build tests. |
-| `unity` | OFF | Configure a unity build. |
-| `verify_headers` | ON | Make the `verify-headers` target available to compile each header on its own. |
-| `xrpld` | OFF | Build the xrpld application, and not just the libxrpl library. |
-| `werr` | OFF | Treat compilation warnings as errors |
-| `wextra` | OFF | Enable additional compilation warnings |
+| Option | Default Value | Description |
+| --- | --- | --- |
+| `assert` | OFF | Force enabling assertions. |
+| `coverage` | OFF | Prepare the coverage report. |
+| `rust` | OFF | Build the Rust crates and the C++ code that depends on them. |
+| `tests` | OFF | Build tests. |
+| `unity` | OFF | Configure a unity build. |
+| `verify_headers` | ON | Make the `verify-headers` target available to compile each header on its own. |
+| `xrpld` | OFF | Build the xrpld application, and not just the libxrpl library. |
+| `werr` | OFF | Treat compilation warnings as errors |
+| `wextra` | OFF | Enable additional compilation warnings |
-[Unity builds][unity-build] may be faster for the first build (at the cost of much more
-memory) since they concatenate sources into fewer translation units. Non-unity
-builds may be faster for incremental builds, and can be helpful for detecting
-`#include` omissions.
+[Unity builds][unity-build] may be faster for the first build (at the cost of much more memory) since they concatenate sources into fewer translation units. Non-unity builds may be faster for incremental builds, and can be helpful for detecting `#include` omissions.
### Rust crates
-The Rust crates in `crates/` are only part of the build when `rust` is ON. With
-`-Drust=OFF` (the default) the `crates` directory is not added to the build, no
-cxxbridge bindings are generated, and the C++ tests that exercise the Rust
-interop are not compiled — so no Rust toolchain is needed. CI builds always pass
-`-Drust=ON`.
+The Rust crates in `crates/` are only part of the build when `rust` is ON. With `-Drust=OFF` (the default) the `crates` directory is not added to the build, no cxxbridge bindings are generated, and the C++ tests that exercise the Rust interop are not compiled — so no Rust toolchain is needed. CI builds always pass `-Drust=ON`.
-With `-Drust=ON` you need one extra dependency: a Rust toolchain (`cargo`,
-`rustc`) matching the channel pinned in
-[`rust-toolchain.toml`](./rust-toolchain.toml), which compiles the crates and
-generates the cxxbridge bindings. It is provided by the
-[Nix development shell](./docs/build/nix.md), so `-Drust=ON` works there without
-any extra setup; otherwise install it as described in
-[Rust](./docs/build/environment.md#rust).
+With `-Drust=ON` you need one extra dependency: a Rust toolchain (`cargo`, `rustc`) matching the channel pinned in [`rust-toolchain.toml`](./rust-toolchain.toml), which compiles the crates and generates the cxxbridge bindings. It is provided by the [Nix development shell](./docs/build/nix.md), so `-Drust=ON` works there without any extra setup; otherwise install it as described in [Rust](./docs/build/environment.md#rust).
-The crates also have their own Rust unit tests. Those are run with `cargo` and
-need only the Rust toolchain, independently of CMake and of the `rust` option
-(CI runs them with `cargo nextest`):
+The crates also have their own Rust unit tests. Those are run with `cargo` and need only the Rust toolchain, independently of CMake and of the `rust` option (CI runs them with `cargo nextest`):
```bash
cargo test --manifest-path crates/Cargo.toml --workspace
@@ -343,22 +255,13 @@ cargo test --manifest-path crates/Cargo.toml --workspace
### Verifying headers
-The regular build only compiles `.cpp` files, so a header is only ever checked
-through whatever translation unit happens to include it. A header that forgets
-an `#include` is not caught as long as every `.cpp` that uses it includes its
-missing dependency first. The `verify_headers` option (ON by default) adds a
-`verify-headers` target that compiles every header on its own, which fails if a
-header is not self-contained:
+The regular build only compiles `.cpp` files, so a header is only ever checked through whatever translation unit happens to include it. A header that forgets an `#include` is not caught as long as every `.cpp` that uses it includes its missing dependency first. The `verify_headers` option (ON by default) adds a `verify-headers` target that compiles every header on its own, which fails if a header is not self-contained:
```bash
cmake --build . --target verify-headers
```
-The per-header objects are excluded from the `all` target, so a normal build
-never compiles them; they are built only through `verify-headers`. The generated
-translation units do appear in `compile_commands.json`, so clang-tidy (and
-clangd and IDEs) can lint each header on its own. Pass `-Dverify_headers=OFF` to
-omit them entirely.
+The per-header objects are excluded from the `all` target, so a normal build never compiles them; they are built only through `verify-headers`. The generated translation units do appear in `compile_commands.json`, so clang-tidy (and clangd and IDEs) can lint each header on its own. Pass `-Dverify_headers=OFF` to omit them entirely.
## Troubleshooting
@@ -385,20 +288,15 @@ After any updates or changes to dependencies, you may need to do the following:
4. [Regenerate lockfile](./docs/build/advanced_conan.md#conan-lockfile).
5. Re-run [conan install](#build-and-test).
-If you are using the Nix development shell, whether prebuilt Conan binaries apply
-depends on your platform — see
-[Prebuilt packages](./docs/build/nix.md#prebuilt-packages).
+If you are using the Nix development shell, whether prebuilt Conan binaries apply depends on your platform — see [Prebuilt packages](./docs/build/nix.md#prebuilt-packages).
#### ERROR: Package not resolved
-If you're seeing an error like `ERROR: Package 'snappy/1.1.10' not resolved: Unable to find 'snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246' in remotes.`,
-please [set Conan up](#set-up-conan) so the `xrplf` remote is configured, or re-run `conan export` for [patched recipes](./docs/build/advanced_conan.md#patched-recipes).
+If you're seeing an error like `ERROR: Package 'snappy/1.1.10' not resolved: Unable to find 'snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246' in remotes.`, please [set Conan up](#set-up-conan) so the `xrplf` remote is configured, or re-run `conan export` for [patched recipes](./docs/build/advanced_conan.md#patched-recipes).
### `protobuf/port_def.inc` file not found
-If `cmake --build .` results in an error due to a missing a protobuf file, then
-you might have generated CMake files for a different `build_type` than the
-`CMAKE_BUILD_TYPE` you passed to Conan.
+If `cmake --build .` results in an error due to a missing a protobuf file, then you might have generated CMake files for a different `build_type` than the `CMAKE_BUILD_TYPE` you passed to Conan.
```
/xrpld/.build/pb-xrpl.libpb/xrpl/proto/xrpl.pb.h:10:10: fatal error: 'google/protobuf/port_def.inc' file not found
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 35309a9824..5dc1d067ff 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,31 +1,19 @@
-The XRP Ledger has many and diverse stakeholders, and everyone deserves
-a chance to contribute meaningful changes to the code that runs the
-XRPL.
+The XRP Ledger has many and diverse stakeholders, and everyone deserves a chance to contribute meaningful changes to the code that runs the XRPL.
# Contributing
-We assume you are familiar with the general practice of [making
-contributions on GitHub][contrib]. This file includes only special
-instructions specific to this project.
+We assume you are familiar with the general practice of [making contributions on GitHub][contrib]. This file includes only special instructions specific to this project.
## Before you start
The following branches exist in the main project repository:
-- `develop`: The latest set of unreleased features, and the most common
- starting point for contributions.
-- `release/*` (e.g. `release/3.2.x`): Release branches, one per release line,
- holding the latest release candidate, or stable release for that line.
- Stable releases are published as [tagged releases](https://github.com/XRPLF/rippled/releases).
+- `develop`: The latest set of unreleased features, and the most common starting point for contributions.
+- `release/*` (e.g. `release/3.2.x`): Release branches, one per release line, holding the latest release candidate, or stable release for that line. Stable releases are published as [tagged releases](https://github.com/XRPLF/rippled/releases).
-The tip of each branch must be signed. In order for GitHub to sign a
-squashed commit that it builds from your pull request, GitHub must know
-your verifying key. Please set up [signature verification][signing].
+The tip of each branch must be signed. In order for GitHub to sign a squashed commit that it builds from your pull request, GitHub must know your verifying key. Please set up [signature verification][signing].
-In general, external contributions should be developed in your personal
-[fork][forking]. Contributions from developers with write permissions
-should be done in [the main repository][xrpld] in a branch with
-a permitted prefix. Permitted prefixes are:
+In general, external contributions should be developed in your personal [fork][forking]. Contributions from developers with write permissions should be done in [the main repository][xrpld] in a branch with a permitted prefix. Permitted prefixes are:
- XLS-[a-zA-Z0-9]+/.+
- e.g. XLS-0033d/mpt-clarify-STEitherAmount
@@ -34,87 +22,47 @@ a permitted prefix. Permitted prefixes are:
- [Organization name]/.+
- e.g. ripple/antithesis
-Regardless of where the branch is created, please open a _draft_ pull
-request as soon as possible after pushing the branch to Github, to
-increase visibility, and ease feedback during the development process.
+Regardless of where the branch is created, please open a _draft_ pull request as soon as possible after pushing the branch to Github, to increase visibility, and ease feedback during the development process.
## Major contributions
-If your contribution is a major feature or breaking change, then you
-must first write an XRP Ledger Standard (XLS) describing it. Go to
-[XRPL-Standards](https://github.com/XRPLF/XRPL-Standards/discussions),
-choose the next available standard number, and open a discussion with an
-appropriate title to propose your draft standard.
+If your contribution is a major feature or breaking change, then you must first write an XRP Ledger Standard (XLS) describing it. Go to [XRPL-Standards](https://github.com/XRPLF/XRPL-Standards/discussions), choose the next available standard number, and open a discussion with an appropriate title to propose your draft standard.
-When you submit a pull request, please link the corresponding XLS in the
-description. An XLS still in `Draft` status is considered a
-work-in-progress and open for discussion. Please allow time for
-questions, suggestions, and changes to the XLS draft. It is the
-responsibility of the XLS author to update the draft to match the final
-implementation when its corresponding pull request is merged, unless the
-author delegates that responsibility to others.
+When you submit a pull request, please link the corresponding XLS in the description. An XLS still in `Draft` status is considered a work-in-progress and open for discussion. Please allow time for questions, suggestions, and changes to the XLS draft. It is the responsibility of the XLS author to update the draft to match the final implementation when its corresponding pull request is merged, unless the author delegates that responsibility to others.
-Any amendment or major RPC change requires either a new XLS or an update
-to an existing XLS. Neither change will be released (in an amendment's
-case, marked as `Supported::yes`) until the corresponding XLS's status
-is `Final`.
+Any amendment or major RPC change requires either a new XLS or an update to an existing XLS. Neither change will be released (in an amendment's case, marked as `Supported::yes`) until the corresponding XLS's status is `Final`.
## Before making a pull request
(Or marking a draft pull request as ready.)
-Changes that alter transaction processing must be guarded by an
-[Amendment](https://xrpl.org/amendments.html).
-All other changes that maintain the existing behavior do not need an
-Amendment.
+Changes that alter transaction processing must be guarded by an [Amendment](https://xrpl.org/amendments.html). All other changes that maintain the existing behavior do not need an Amendment.
-Ensure that your code compiles according to the build instructions in
-[`BUILD.md`](./BUILD.md).
+Ensure that your code compiles according to the build instructions in [`BUILD.md`](./BUILD.md).
-Please write tests for your code.
-If your test can be run offline, in under 60 seconds, then it can be an
-automatic test run by `xrpld --unittest`.
-Otherwise, it must be a manual test.
+Please write tests for your code. If your test can be run offline, in under 60 seconds, then it can be an automatic test run by `xrpld --unittest`. Otherwise, it must be a manual test.
If you create new source files, they must be organized as follows:
-- If the files are in any of the `libxrpl` modules, the headers (`.h`) must go
- under `include/xrpl`, and source (`.cpp`) files must go under
- `src/libxrpl`.
+- If the files are in any of the `libxrpl` modules, the headers (`.h`) must go under `include/xrpl`, and source (`.cpp`) files must go under `src/libxrpl`.
- All other non-test files must go under `src/xrpld`.
- All test source files must go under `src/test`.
- All benchmark source files must go under `src/benchmarks`.
-The source must be formatted according to the style guide below. The easiest
-way to satisfy this is to install the [`pre-commit`](#pre-commit-hooks) hooks,
-which format and lint your changes automatically on every commit.
+The source must be formatted according to the style guide below. The easiest way to satisfy this is to install the [`pre-commit`](#pre-commit-hooks) hooks, which format and lint your changes automatically on every commit.
Header includes must be [levelized](.github/scripts/levelization).
-Changes should be usually squashed down into a single commit.
-Some larger or more complicated change sets make more sense,
-and are easier to review if organized into multiple logical commits.
-Either way, all commits should fit the following criteria:
+Changes should be usually squashed down into a single commit. Some larger or more complicated change sets make more sense, and are easier to review if organized into multiple logical commits. Either way, all commits should fit the following criteria:
-- Changes should be presented in a single commit or a logical
- sequence of commits.
- Specifically, chronological commits that simply
- reflect the history of how the author implemented
- the change, "warts and all", are not useful to
- reviewers.
-- Every commit should have a [good message](#good-commit-messages).
- to explain a specific aspects of the change.
+- Changes should be presented in a single commit or a logical sequence of commits. Specifically, chronological commits that simply reflect the history of how the author implemented the change, "warts and all", are not useful to reviewers.
+- Every commit should have a [good message](#good-commit-messages). to explain a specific aspects of the change.
- Every commit should be signed.
-- Every commit should be well-formed (builds successfully,
- unit tests passing), as this helps to resolve merge
- conflicts, and makes it easier to use `git bisect`
- to find bugs.
+- Every commit should be well-formed (builds successfully, unit tests passing), as this helps to resolve merge conflicts, and makes it easier to use `git bisect` to find bugs.
### Good commit messages
-Refer to
-["How to Write a Git Commit Message"](https://cbea.ms/git-commit/)
-for general rules on writing a good commit message.
+Refer to ["How to Write a Git Commit Message"](https://cbea.ms/git-commit/) for general rules on writing a good commit message.
tl;dr
@@ -124,9 +72,7 @@ tl;dr
> 3. Capitalize the subject line.
> 4. Do not end the subject line with a period.
> 5. Use the imperative mood in the subject line.
-> - A properly formed Git commit subject line should always be able
-> to complete the following sentence: "If applied, this commit will
-> _your subject line here_".
+> - A properly formed Git commit subject line should always be able to complete the following sentence: "If applied, this commit will _your subject line here_".
> 6. Wrap the body at 72 characters.
> 7. Use the body to explain what and why vs. how.
@@ -134,32 +80,15 @@ tl;dr
In general, pull requests use `develop` as the base branch.
-The exceptions are fixes, improvements, and hotfixes for an existing release,
-which use that release's branch (e.g. `release/3.2.x`) as the base.
+The exceptions are fixes, improvements, and hotfixes for an existing release, which use that release's branch (e.g. `release/3.2.x`) as the base.
-If your changes are not quite ready, but you want to make it easily available
-for preliminary examination or review, you can create a "Draft" pull request.
-While a pull request is marked as a "Draft", you can rebase or reorganize the
-commits in the pull request as desired.
+If your changes are not quite ready, but you want to make it easily available for preliminary examination or review, you can create a "Draft" pull request. While a pull request is marked as a "Draft", you can rebase or reorganize the commits in the pull request as desired.
-Github pull requests are created as "Ready" by default, or you can mark
-a "Draft" pull request as "Ready".
-Once a pull request is marked as "Ready",
-any changes must be added as new commits. Do not
-force-push to a branch in a pull request under review.
-(This includes rebasing your branch onto the updated base branch.
-Use a merge operation, instead or hit the "Update branch" button
-at the bottom of the Github PR page.)
-This preserves the ability for reviewers to filter changes since their last
-review.
+Github pull requests are created as "Ready" by default, or you can mark a "Draft" pull request as "Ready". Once a pull request is marked as "Ready", any changes must be added as new commits. Do not force-push to a branch in a pull request under review. (This includes rebasing your branch onto the updated base branch. Use a merge operation, instead or hit the "Update branch" button at the bottom of the Github PR page.) This preserves the ability for reviewers to filter changes since their last review.
-A pull request must obtain **approvals from at least two reviewers**
-before it can be considered for merge by a Maintainer.
-Maintainers retain discretion to require more approvals if they feel the
-credibility of the existing approvals is insufficient.
+A pull request must obtain **approvals from at least two reviewers** before it can be considered for merge by a Maintainer. Maintainers retain discretion to require more approvals if they feel the credibility of the existing approvals is insufficient.
-Pull requests must be merged by [squash-and-merge][squash]
-to preserve a linear history for the `develop` branch.
+Pull requests must be merged by [squash-and-merge][squash] to preserve a linear history for the `develop` branch.
### Type of Change
@@ -180,54 +109,26 @@ First letter after the type prefix should be capitalized, and the type prefix sh
### "Ready to merge"
-A pull request should only have the "Ready to merge" label added when it
-meets a few criteria:
+A pull request should only have the "Ready to merge" label added when it meets a few criteria:
-1. It must have two approving reviews [as described
- above](#pull-requests). (Exception: PRs that are deemed "trivial"
- only need one approval.)
-2. All CI checks must be complete and passed. (One-off failures may
- be acceptable if they are related to a known issue.)
+1. It must have two approving reviews [as described above](#pull-requests). (Exception: PRs that are deemed "trivial" only need one approval.)
+2. All CI checks must be complete and passed. (One-off failures may be acceptable if they are related to a known issue.)
3. The PR must have a [good commit message](#good-commit-messages).
- - If the PR started with a good commit message, and it doesn't
- need to be updated, the author can indicate that in a comment.
- - Any contributor, preferably the author, can leave a comment
- suggesting a commit message.
- - If the author squashes and rebases the code in preparation for
- merge, they should also ensure the commit message(s) are updated
- as well.
-4. The PR branch must be up to date with the base branch (usually
- `develop`). This is usually accomplished by merging the base branch
- into the feature branch, but if the other criteria are met, the
- changes can be squashed and rebased on top of the base branch.
-5. Finally, and most importantly, the author of the PR must
- positively indicate that the PR is ready to merge. That can be
- accomplished by adding the "Ready to merge" label if their role
- allows, or by leaving a comment to the effect that the PR is ready to
- merge.
+ - If the PR started with a good commit message, and it doesn't need to be updated, the author can indicate that in a comment.
+ - Any contributor, preferably the author, can leave a comment suggesting a commit message.
+ - If the author squashes and rebases the code in preparation for merge, they should also ensure the commit message(s) are updated as well.
+4. The PR branch must be up to date with the base branch (usually `develop`). This is usually accomplished by merging the base branch into the feature branch, but if the other criteria are met, the changes can be squashed and rebased on top of the base branch.
+5. Finally, and most importantly, the author of the PR must positively indicate that the PR is ready to merge. That can be accomplished by adding the "Ready to merge" label if their role allows, or by leaving a comment to the effect that the PR is ready to merge.
-Once the "Ready to merge" label is added, a maintainer may merge the PR
-at any time, so don't use it lightly.
+Once the "Ready to merge" label is added, a maintainer may merge the PR at any time, so don't use it lightly.
# Style guide
-This is a non-exhaustive list of recommended style guidelines. These are
-not always strictly enforced and serve as a way to keep the codebase
-coherent rather than a set of _thou shalt not_ commandments.
+This is a non-exhaustive list of recommended style guidelines. These are not always strictly enforced and serve as a way to keep the codebase coherent rather than a set of _thou shalt not_ commandments.
## Pre-commit hooks
-We use the [`pre-commit`](https://pre-commit.com/) framework to run the
-formatting and linting tools that keep the codebase consistent. `pre-commit`
-runs each tool configured in
-[`.pre-commit-config.yaml`](./.pre-commit-config.yaml) in its own isolated
-environment, so you don't need to install most of the individual tools
-yourself. The version of each hook sourced from an external repository
-(`clang-format`, `gersemi`, etc.) is pinned in that file, so running the hooks
-locally uses exactly the same versions as CI. A few `local` hooks — most notably
-`clang-tidy` and `cargo fmt` — run tools from your own environment; see
-[Installing clang-tidy](#installing-clang-tidy) and
-[Rust](./docs/build/environment.md#rust) for how to get those.
+We use the [`pre-commit`](https://pre-commit.com/) framework to run the formatting and linting tools that keep the codebase consistent. `pre-commit` runs each tool configured in [`.pre-commit-config.yaml`](./.pre-commit-config.yaml) in its own isolated environment, so you don't need to install most of the individual tools yourself. The version of each hook sourced from an external repository (`clang-format`, `gersemi`, etc.) is pinned in that file, so running the hooks locally uses exactly the same versions as CI. A few `local` hooks — most notably `clang-tidy` and `cargo fmt` — run tools from your own environment; see [Installing clang-tidy](#installing-clang-tidy) and [Rust](./docs/build/environment.md#rust) for how to get those.
To get started, install `pre-commit` and enable the git hook scripts:
@@ -236,8 +137,7 @@ pip install pre-commit
pre-commit install
```
-Once installed, the hooks run automatically on your staged files every time you
-`git commit`. You can also run them on demand:
+Once installed, the hooks run automatically on your staged files every time you `git commit`. You can also run them on demand:
```bash
# Run all hooks against only the staged files
@@ -260,18 +160,11 @@ The hooks configured in this repository include, among others:
- `prettier`, `black`, `shfmt` — formatting for JavaScript/JSON/Markdown, Python, and shell
- `cspell` — spell checking
-The same hooks run in CI on every pull request, so running them locally before
-you push helps you avoid CI failures.
+The same hooks run in CI on every pull request, so running them locally before you push helps you avoid CI failures.
## Formatting
-All code must conform to `clang-format`, according to the settings in
-[`.clang-format`](./.clang-format), unless the result would be unreasonably
-difficult to read or maintain. The `clang-format` version is pinned in
-[`.pre-commit-config.yaml`](./.pre-commit-config.yaml), so the
-[`pre-commit`](#pre-commit-hooks) hook always formats with the same version as
-CI. To demarcate lines that should be left as-is, surround them with comments
-like this:
+All code must conform to `clang-format`, according to the settings in [`.clang-format`](./.clang-format), unless the result would be unreasonably difficult to read or maintain. The `clang-format` version is pinned in [`.pre-commit-config.yaml`](./.pre-commit-config.yaml), so the [`pre-commit`](#pre-commit-hooks) hook always formats with the same version as CI. To demarcate lines that should be left as-is, surround them with comments like this:
```
// clang-format off
@@ -279,20 +172,15 @@ like this:
// clang-format on
```
-The easiest way to format your changes is to let the `pre-commit` hook run
-automatically on commit, or to run it manually:
+The easiest way to format your changes is to let the `pre-commit` hook run automatically on commit, or to run it manually:
```bash
pre-commit run clang-format --all-files
```
-You can also format individual files in place by running `clang-format -i ...`
-from any directory within this project.
+You can also format individual files in place by running `clang-format -i ...` from any directory within this project.
-> [!NOTE]
-> This uses whatever `clang-format` version is installed locally, which may
-> differ from the pinned version used by `pre-commit` and CI, so the results
-> can vary.
+> [!NOTE] This uses whatever `clang-format` version is installed locally, which may differ from the pinned version used by `pre-commit` and CI, so the results can vary.
There is a Continuous Integration job that runs clang-format on pull requests. If the code doesn't comply, a patch file that corrects auto-fixable formatting issues is generated.
@@ -353,8 +241,7 @@ Then run clang-tidy on your local changes:
run-clang-tidy -p build -allow-no-checks src tests
```
-This will check all source files in the `src`, `include` and `tests` directories using the compile commands from your `build` directory.
-If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix -format` to the above command:
+This will check all source files in the `src`, `include` and `tests` directories using the compile commands from your `build` directory. If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix -format` to the above command:
```
run-clang-tidy -p build -quiet -fix -format -allow-no-checks src tests
@@ -364,27 +251,11 @@ run-clang-tidy -p build -quiet -fix -format -allow-no-checks src tests
## Contracts and instrumentation
-We are using [Antithesis](https://antithesis.com/) for continuous fuzzing,
-and keep a copy of [Antithesis C++ SDK](https://github.com/antithesishq/antithesis-sdk-cpp/)
-in `external/antithesis-sdk`. One of the aims of fuzzing is to identify bugs
-by finding external conditions which cause contracts violations inside `xrpld`.
-The contracts are expressed as `XRPL_ASSERT` or `UNREACHABLE` (defined in
-`include/xrpl/beast/utility/instrumentation.h`), which are effectively (outside
-of Antithesis) wrappers for `assert(...)` with added name. The purpose of name
-is to provide contracts with stable identity which does not rely on line numbers.
+We are using [Antithesis](https://antithesis.com/) for continuous fuzzing, and keep a copy of [Antithesis C++ SDK](https://github.com/antithesishq/antithesis-sdk-cpp/) in `external/antithesis-sdk`. One of the aims of fuzzing is to identify bugs by finding external conditions which cause contracts violations inside `xrpld`. The contracts are expressed as `XRPL_ASSERT` or `UNREACHABLE` (defined in `include/xrpl/beast/utility/instrumentation.h`), which are effectively (outside of Antithesis) wrappers for `assert(...)` with added name. The purpose of name is to provide contracts with stable identity which does not rely on line numbers.
-When `xrpld` is built with the Antithesis instrumentation enabled
-(using `voidstar` CMake option) and ran on the Antithesis platform, the
-contracts become
-[test properties](https://antithesis.com/docs/using_antithesis/properties.html);
-otherwise they are just like a regular `assert`.
-To learn more about Antithesis, see
-[How Antithesis Works](https://antithesis.com/docs/introduction/how_antithesis_works.html)
-and [C++ SDK](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html#)
+When `xrpld` is built with the Antithesis instrumentation enabled (using `voidstar` CMake option) and ran on the Antithesis platform, the contracts become [test properties](https://antithesis.com/docs/using_antithesis/properties.html); otherwise they are just like a regular `assert`. To learn more about Antithesis, see [How Antithesis Works](https://antithesis.com/docs/introduction/how_antithesis_works.html) and [C++ SDK](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html#)
-We continue to use the old style `assert` or `assert(false)` in certain
-locations, where the reporting of contract violations on the Antithesis
-platform is either not possible or not useful.
+We continue to use the old style `assert` or `assert(false)` in certain locations, where the reporting of contract violations on the Antithesis platform is either not possible or not useful.
For this reason:
@@ -392,38 +263,17 @@ For this reason:
- `constexpr` functions
- unit tests i.e. files under `src/test`
- unit tests-related modules (files under `beast/test` and `beast/unit_test`)
-- Outside of the listed locations, do not use `assert`; use `XRPL_ASSERT` instead,
- giving it unique name, with the short description of the contract.
-- Outside of the listed locations, do not use `assert(false)`; use
- `UNREACHABLE` instead, giving it unique name, with the description of the
- condition being violated
-- The contract name should start with a full name (including scope) of the
- function, optionally a named lambda, followed by a colon `:` and a brief
- (typically at most five words) description. `UNREACHABLE` contracts
- can use slightly longer descriptions. If there are multiple overloads of the
- function, use common sense to balance both brevity and unambiguity of the
- function name. NOTE: the purpose of name is to provide stable means of
- unique identification of every contract; for this reason try to avoid elements
- which can change in some obvious refactors or when reinforcing the condition.
-- Contract description typically (except for `UNREACHABLE`) should describe the
- _expected_ condition, as in "I assert that _expected_ is true".
-- Contract description for `UNREACHABLE` should describe the _unexpected_
- situation which caused the line to have been reached.
-- Example good name for an
- `UNREACHABLE` macro `"json::operator==(Value, Value) : invalid type"`; example
- good name for an `XRPL_ASSERT` macro `"json::Value::asCString : valid type"`.
-- Example **bad** name
- `"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"`
- (missing namespace, unnecessary full function signature, description too verbose).
- Good name: `"xrpl::RFC1751::insert : minimum length"`.
-- In **few** well-justified cases a non-standard name can be used, in which case a
- comment should be placed to explain the rationale (example in `contract.cpp`)
-- Do **not** rename a contract without a good reason (e.g. the name no longer
- reflects the location or the condition being checked)
+- Outside of the listed locations, do not use `assert`; use `XRPL_ASSERT` instead, giving it unique name, with the short description of the contract.
+- Outside of the listed locations, do not use `assert(false)`; use `UNREACHABLE` instead, giving it unique name, with the description of the condition being violated
+- The contract name should start with a full name (including scope) of the function, optionally a named lambda, followed by a colon `:` and a brief (typically at most five words) description. `UNREACHABLE` contracts can use slightly longer descriptions. If there are multiple overloads of the function, use common sense to balance both brevity and unambiguity of the function name. NOTE: the purpose of name is to provide stable means of unique identification of every contract; for this reason try to avoid elements which can change in some obvious refactors or when reinforcing the condition.
+- Contract description typically (except for `UNREACHABLE`) should describe the _expected_ condition, as in "I assert that _expected_ is true".
+- Contract description for `UNREACHABLE` should describe the _unexpected_ situation which caused the line to have been reached.
+- Example good name for an `UNREACHABLE` macro `"json::operator==(Value, Value) : invalid type"`; example good name for an `XRPL_ASSERT` macro `"json::Value::asCString : valid type"`.
+- Example **bad** name `"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"` (missing namespace, unnecessary full function signature, description too verbose). Good name: `"xrpl::RFC1751::insert : minimum length"`.
+- In **few** well-justified cases a non-standard name can be used, in which case a comment should be placed to explain the rationale (example in `contract.cpp`)
+- Do **not** rename a contract without a good reason (e.g. the name no longer reflects the location or the condition being checked)
- Do not use `std::unreachable`
-- Do not put contracts where they can be violated by an external condition
- (e.g. timing, data payload before mandatory validation etc.) as this creates
- bogus bug reports (and causes crashes of Debug builds)
+- Do not put contracts where they can be violated by an external condition (e.g. timing, data payload before mandatory validation etc.) as this creates bogus bug reports (and causes crashes of Debug builds)
## Unit Tests
@@ -431,8 +281,7 @@ To execute all unit tests:
`xrpld --unittest --unittest-jobs=`
-(Note: Using multiple cores on a Mac M1 can cause spurious test failures. The
-cause is still under investigation. If you observe this problem, try specifying fewer jobs.)
+(Note: Using multiple cores on a Mac M1 can cause spurious test failures. The cause is still under investigation. If you observe this problem, try specifying fewer jobs.)
To run a specific set of test suites:
@@ -440,11 +289,7 @@ To run a specific set of test suites:
xrpld --unittest TestSuiteName
```
-Note: In this example, all tests with prefix `TestSuiteName` will be run, so if
-`TestSuiteName1` and `TestSuiteName2` both exist, then both tests will run.
-Alternatively, if the unit test name finds an exact match, it will stop
-doing partial matches, i.e. if a unit test with a title of `TestSuiteName`
-exists, then no other unit test will be executed, apart from `TestSuiteName`.
+Note: In this example, all tests with prefix `TestSuiteName` will be run, so if `TestSuiteName1` and `TestSuiteName2` both exist, then both tests will run. Alternatively, if the unit test name finds an exact match, it will stop doing partial matches, i.e. if a unit test with a title of `TestSuiteName` exists, then no other unit test will be executed, apart from `TestSuiteName`.
## Avoid
@@ -454,44 +299,27 @@ exists, then no other unit test will be executed, apart from `TestSuiteName`.
4. Unmanaged memory allocation and raw pointers.
5. Macros and non-trivial templates (unless they add significant value).
6. Lambda patterns (unless these add significant value).
-7. CPU or architecture-specific code unless there is a good reason to
- include it, and where it is used, guard it with macros and provide
- explanatory comments.
+7. CPU or architecture-specific code unless there is a good reason to include it, and where it is used, guard it with macros and provide explanatory comments.
8. Importing new libraries unless there is a very good reason to do so.
## Seek to
9. Extend functionality of existing code rather than creating new code.
-10. Prefer readability over terseness where important logic is
- concerned.
-11. Inline functions that are not used or are not likely to be used
- elsewhere in the codebase.
-12. Use clear and self-explanatory names for functions, variables,
- structs and classes.
-13. Use TitleCase for classes, structs and filenames, camelCase for
- function and variable names, lower case for namespaces and folders.
-14. Provide as many comments as you feel that a competent programmer
- would need to understand what your code does.
+10. Prefer readability over terseness where important logic is concerned.
+11. Inline functions that are not used or are not likely to be used elsewhere in the codebase.
+12. Use clear and self-explanatory names for functions, variables, structs and classes.
+13. Use TitleCase for classes, structs and filenames, camelCase for function and variable names, lower case for namespaces and folders.
+14. Provide as many comments as you feel that a competent programmer would need to understand what your code does.
# Maintainers
-Maintainers are ecosystem participants with elevated access to the repository.
-They are able to push new code, make decisions on when a release should be
-made, etc.
+Maintainers are ecosystem participants with elevated access to the repository. They are able to push new code, make decisions on when a release should be made, etc.
## Adding and removing
-New maintainers can be proposed by two existing maintainers, subject to a vote
-by a quorum of the existing maintainers.
-A minimum of 50% support and a 50% participation is required.
-In the event of a tie vote, the addition of the new maintainer will be
-rejected.
+New maintainers can be proposed by two existing maintainers, subject to a vote by a quorum of the existing maintainers. A minimum of 50% support and a 50% participation is required. In the event of a tie vote, the addition of the new maintainer will be rejected.
-Existing maintainers can resign, or be subject to a vote for removal at the
-behest of two existing maintainers.
-A minimum of 60% agreement and 50% participation are required.
-The XRP Ledger Foundation will have the ability, for cause, to remove an
-existing maintainer without a vote.
+Existing maintainers can resign, or be subject to a vote for removal at the behest of two existing maintainers. A minimum of 60% agreement and 50% participation are required. The XRP Ledger Foundation will have the ability, for cause, to remove an existing maintainer without a vote.
## Current Maintainers
@@ -507,8 +335,7 @@ Maintainers are users with maintain or admin access to the repo.
## Current Code Reviewers
-Code Reviewers are developers who have the ability to review, approve, and
-in some cases merge source code changes.
+Code Reviewers are developers who have the ability to review, approve, and in some cases merge source code changes.
- [a1q123456](https://github.com/a1q123456) (Ripple)
- [Bronek](https://github.com/Bronek) (Ripple)
@@ -529,14 +356,11 @@ in some cases merge source code changes.
- [Tapanito](https://github.com/Tapanito) (Ripple)
- [ximinez](https://github.com/ximinez) (Ripple)
-Developers not on this list are able and encouraged to submit feedback
-on pending code changes (open pull requests).
+Developers not on this list are able and encouraged to submit feedback on pending code changes (open pull requests).
## Instructions for maintainers
-These instructions assume you have your git upstream remotes configured
-to avoid accidental pushes to the main repo, and a remote group
-specifying both of them. e.g.
+These instructions assume you have your git upstream remotes configured to avoid accidental pushes to the main repo, and a remote group specifying both of them. e.g.
```
$ git remote -v | grep upstream
@@ -561,104 +385,58 @@ $ git config user.signingkey
### When and how to merge pull requests
-The maintainer should double-check that the PR has met all the
-necessary criteria, and can request additional information from the
-owner, or additional reviews, and can always feel free to remove the
-"Ready to merge" label if appropriate. The maintainer has final say on
-whether a PR gets merged, and are encouraged to communicate and issues
-or concerns to other maintainers.
+The maintainer should double-check that the PR has met all the necessary criteria, and can request additional information from the owner, or additional reviews, and can always feel free to remove the "Ready to merge" label if appropriate. The maintainer has final say on whether a PR gets merged, and are encouraged to communicate and issues or concerns to other maintainers.
#### Most pull requests: "Squash and merge"
-Most pull requests don't need special handling, and can simply be
-merged using the "Squash and merge" button on the Github UI. Update
-the suggested commit message, or modify it as needed.
+Most pull requests don't need special handling, and can simply be merged using the "Squash and merge" button on the Github UI. Update the suggested commit message, or modify it as needed.
#### Slightly more complicated pull requests
-Some pull requests need to be pushed to `develop` as more than one
-commit. A PR author may _request_ to merge as separate commits. They
-must _justify_ why separate commits are needed, and _specify_ how they
-would like the commits to be merged. If you disagree with the author,
-discuss it with them directly.
+Some pull requests need to be pushed to `develop` as more than one commit. A PR author may _request_ to merge as separate commits. They must _justify_ why separate commits are needed, and _specify_ how they would like the commits to be merged. If you disagree with the author, discuss it with them directly.
-If the process is reasonable, follow it. The simplest option is to do a
-fast forward only merge (`--ff-only`) on the command line and push to
-`develop`.
+If the process is reasonable, follow it. The simplest option is to do a fast forward only merge (`--ff-only`) on the command line and push to `develop`.
Some examples of when separate commits are worthwhile are:
1. PRs where source files are reorganized in multiple steps.
-2. PRs where the commits are mostly independent and _could_ be separate
- PRs, but are pulled together into one PR under a commit theme or
- issue.
-3. PRs that are complicated enough that `git bisect` would not be much
- help if it determined this PR introduced a problem.
+2. PRs where the commits are mostly independent and _could_ be separate PRs, but are pulled together into one PR under a commit theme or issue.
+3. PRs that are complicated enough that `git bisect` would not be much help if it determined this PR introduced a problem.
Either way, check that:
- The commits are based on the current tip of `develop`.
-- The commits are clean: No merge commits (except when reverse
- merging), no "[FOLD]" or "fixup!" messages.
-- All commits are signed. If the commits are not signed by the author, use
- `git commit --amend -S` to sign them yourself.
-- At least one (but preferably all) of the commits has the PR number
- in the commit message.
+- The commits are clean: No merge commits (except when reverse merging), no "[FOLD]" or "fixup!" messages.
+- All commits are signed. If the commits are not signed by the author, use `git commit --amend -S` to sign them yourself.
+- At least one (but preferably all) of the commits has the PR number in the commit message.
-The "Create a merge commit" and "Rebase and merge" options should be
-disabled in the Github UI, but if you ever find them available **Do not
-use them!**
+The "Create a merge commit" and "Rebase and merge" options should be disabled in the Github UI, but if you ever find them available **Do not use them!**
### Releases
-All releases, including release candidates and betas, are handled
-differently from typical PRs. Most importantly, never use
-the Github UI to merge a release.
+All releases, including release candidates and betas, are handled differently from typical PRs. Most importantly, never use the Github UI to merge a release.
Xrpld uses a linear workflow model that can be summarized as:
1. In between releases, developers work against the `develop` branch.
-2. Periodically, a maintainer will build and tag a beta version from
- `develop`, which is pushed to `release`.
- - Betas are usually released every two to three weeks, though that
- schedule can vary depending on progress, availability, and other
- factors.
-3. When the changes in `develop` are considered stable and mature enough
- to be ready to release, a release candidate (RC) is built and tagged
- from `develop`, and merged to `release`.
- - Further development for that release (primarily fixes) then
- continues against `release`, while other development continues on
- `develop`. Effectively, `release` is forked from `develop`. Changes
- to `release` must be reverse merged to `develop`.
-4. When the candidate has passed testing and is ready for release, the
- final release is merged to `master`.
-5. If any issues are found post-release, a hotfix / point release may be
- created, which is merged to `master`, and then reverse merged to
- `develop`.
+2. Periodically, a maintainer will build and tag a beta version from `develop`, which is pushed to `release`.
+ - Betas are usually released every two to three weeks, though that schedule can vary depending on progress, availability, and other factors.
+3. When the changes in `develop` are considered stable and mature enough to be ready to release, a release candidate (RC) is built and tagged from `develop`, and merged to `release`.
+ - Further development for that release (primarily fixes) then continues against `release`, while other development continues on `develop`. Effectively, `release` is forked from `develop`. Changes to `release` must be reverse merged to `develop`.
+4. When the candidate has passed testing and is ready for release, the final release is merged to `master`.
+5. If any issues are found post-release, a hotfix / point release may be created, which is merged to `master`, and then reverse merged to `develop`.
#### Betas, and the first release candidate
##### Preparing the `develop` branch
-1. Optimally, the `develop` branch will be ready to go, with all
- relevant PRs already merged.
+1. Optimally, the `develop` branch will be ready to go, with all relevant PRs already merged.
2. If there are any PRs pending, merge them **BEFORE** preparing the beta.
- 1. If only one or two PRs need to be merged, merge those PRs [as
- normal](#when-and-how-to-merge-pull-requests), updating the second
- one, and waiting for CI to finish in between.
- 2. If there are several pending PRs, do not use the Github UI,
- because the delays waiting for CI in between each merge will be
- unnecessarily onerous. (Incidentally, this process can also be
- used to merge if the Github UI has issues.) Merge each PR branch
- directly to a `release-next` on your local machine and create a single
- PR, then push your branch to `develop`.
- 1. Squash the changes from each PR, one commit each (unless more
- are needed), being sure to sign each commit and update the
- commit message to include the PR number. You may be able to use
- a fast-forward merge for the first PR.
+ 1. If only one or two PRs need to be merged, merge those PRs [as normal](#when-and-how-to-merge-pull-requests), updating the second one, and waiting for CI to finish in between.
+ 2. If there are several pending PRs, do not use the Github UI, because the delays waiting for CI in between each merge will be unnecessarily onerous. (Incidentally, this process can also be used to merge if the Github UI has issues.) Merge each PR branch directly to a `release-next` on your local machine and create a single PR, then push your branch to `develop`.
+ 1. Squash the changes from each PR, one commit each (unless more are needed), being sure to sign each commit and update the commit message to include the PR number. You may be able to use a fast-forward merge for the first PR.
2. Push your branch.
- 3. Continue to [Making the release](#making-the-release) to update
- the version number, etc.
+ 3. Continue to [Making the release](#making-the-release) to update the version number, etc.
The workflow may look something like:
@@ -691,17 +469,13 @@ git push --set-upstream origin
You can also use the [squash-branches] script.
-You may also need to manually close the open PRs after the changes are
-merged to `develop`. Be sure to include the commit ID.
+You may also need to manually close the open PRs after the changes are merged to `develop`. Be sure to include the commit ID.
##### Making the release
This includes, betas, and the first release candidate (RC).
-1. If you didn't create one [preparing the `develop`
- branch](#preparing-the-develop-branch), Ensure there is no old
- `release-next` branch hanging around. Then make a `release-next`
- branch that only changes the version number. e.g.
+1. If you didn't create one [preparing the `develop` branch](#preparing-the-develop-branch), Ensure there is no old `release-next` branch hanging around. Then make a `release-next` branch that only changes the version number. e.g.
```
git fetch upstreams
@@ -724,8 +498,7 @@ git fetch upstreams
git branch --set-upstream-to=upstream/release-next
```
-You can also use the [update-version] script. 2. Create a Pull Request for `release-next` with **`develop`** as
-the base branch.
+You can also use the [update-version] script. 2. Create a Pull Request for `release-next` with **`develop`** as the base branch.
1. Use the title "[TRIVIAL] Set version to X.X.X-bX".
2. Instead of the default description template, use the following:
@@ -737,27 +510,17 @@ This PR only changes the version number. It will be merged as
soon as Github CI actions successfully complete.
```
-3. Wait for CI to successfully complete, and get someone to approve
- the PR. (It is safe to ignore known CI issues.)
-4. Push the updated `develop` branch using your `release-next`
- branch. **Do not use the Github UI. It's important to preserve
- commit IDs.**
+3. Wait for CI to successfully complete, and get someone to approve the PR. (It is safe to ignore known CI issues.)
+4. Push the updated `develop` branch using your `release-next` branch. **Do not use the Github UI. It's important to preserve commit IDs.**
```
git push upstream-push release-next:develop
```
-5. In the unlikely event that the push fails because someone has merged
- something else in the meantime, rebase your branch onto the updated
- `develop` branch, push again, and go back to step 3.
-6. Ensure that your PR against `develop` is closed. Github should do it
- automatically.
-7. Once this is done, forward progress on `develop` can continue
- (other PRs may be merged).
-8. Now create a Pull Request for `release-next` with **`release`** as
- the base branch. Instead of the default template, reuse and update
- the message from the previous release. Include the following verbiage
- somewhere in the description:
+5. In the unlikely event that the push fails because someone has merged something else in the meantime, rebase your branch onto the updated `develop` branch, push again, and go back to step 3.
+6. Ensure that your PR against `develop` is closed. Github should do it automatically.
+7. Once this is done, forward progress on `develop` can continue (other PRs may be merged).
+8. Now create a Pull Request for `release-next` with **`release`** as the base branch. Instead of the default template, reuse and update the message from the previous release. Include the following verbiage somewhere in the description:
```
The base branch is `release`. [All releases (including
@@ -766,12 +529,8 @@ go in `release`. This PR branch will be pushed directly to `release` (not
squashed or rebased, and not using the GitHub UI).
```
-7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur
- offline, but at least one approval will be needed on the PR.
- - If issues are discovered during testing, simply abandon the
- release. It's easy to start a new release, it should be easy to
- abandon one. **DO NOT REUSE THE VERSION NUMBER.** e.g. If you
- abandon 2.4.0-b1, the next attempt will be 2.4.0-b2.
+7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur offline, but at least one approval will be needed on the PR.
+ - If issues are discovered during testing, simply abandon the release. It's easy to start a new release, it should be easy to abandon one. **DO NOT REUSE THE VERSION NUMBER.** e.g. If you abandon 2.4.0-b1, the next attempt will be 2.4.0-b2.
8. Once everything is ready to go, push to `release`.
```
@@ -808,44 +567,25 @@ git push upstream-push
git push --delete upstream-push release-next
```
-11. Finally [create a new release on
- Github](https://github.com/XRPLF/rippled/releases).
+11. Finally [create a new release on Github](https://github.com/XRPLF/rippled/releases).
#### Release candidates after the first
-Once the first release candidate is [merged into
-release](#making-the-release), then `release` and `develop` _are allowed
-to diverge_.
+Once the first release candidate is [merged into release](#making-the-release), then `release` and `develop` _are allowed to diverge_.
-If a bug or issue is discovered in a version that has a release
-candidate being tested, any fix and new version will need to be applied
-against `release`, then reverse-merged to `develop`. This helps keep git
-history as linear as possible.
+If a bug or issue is discovered in a version that has a release candidate being tested, any fix and new version will need to be applied against `release`, then reverse-merged to `develop`. This helps keep git history as linear as possible.
-A `release-next` branch will be created from `release`, and any further
-work for that release must be based on `release-next`. Specifically,
-PRs must use `release-next` as the base, and those PRs will be merged
-directly to `release-next` when approved. Changes should be restricted
-to bug fixes, but other changes may be necessary from time to time.
+A `release-next` branch will be created from `release`, and any further work for that release must be based on `release-next`. Specifically, PRs must use `release-next` as the base, and those PRs will be merged directly to `release-next` when approved. Changes should be restricted to bug fixes, but other changes may be necessary from time to time.
-1. Open any PRs for the pending release using `release-next` as the base,
- so they can be merged directly in to it. Unlike `develop`, though,
- `release-next` can be thrown away and recreated if necessary.
-2. Once a new release candidate is ready, create a version commit as in
- step 1 [above](#making-the-release) on `release-next`. You can use
- the [update-version] script for this, too.
-3. Jump to step 8 ("Now create a Pull Request for `release-next` with
- **`release`** as the base") from the process
- [above](#making-the-release) to merge `release-next` into `release`.
+1. Open any PRs for the pending release using `release-next` as the base, so they can be merged directly in to it. Unlike `develop`, though, `release-next` can be thrown away and recreated if necessary.
+2. Once a new release candidate is ready, create a version commit as in step 1 [above](#making-the-release) on `release-next`. You can use the [update-version] script for this, too.
+3. Jump to step 8 ("Now create a Pull Request for `release-next` with **`release`** as the base") from the process [above](#making-the-release) to merge `release-next` into `release`.
##### Follow up: reverse merge
-Once the RC is merged and tagged, it needs to be reverse merged into
-`develop` as soon as possible.
+Once the RC is merged and tagged, it needs to be reverse merged into `develop` as soon as possible.
-1. Create a branch, based on `upstream/develop`.
- The branch name is not important, but could include "mergeNNNrcN".
- E.g. For release A.B.C-rcD, use `mergeABCrcD`.
+1. Create a branch, based on `upstream/develop`. The branch name is not important, but could include "mergeNNNrcN". E.g. For release A.B.C-rcD, use `mergeABCrcD`.
```
git fetch upstreams
@@ -861,24 +601,15 @@ git checkout --no-track -b mergeABCrcD upstream/develop
git merge upstream/release
```
-3. `BuildInfo.cpp` will have a conflict with the version number.
- Resolve it with the version from `develop` - the higher version.
-4. Push your branch to your repo (or `upstream` if you have permission),
- and open a normal PR against `develop`. The "High level overview" can
- simply indicate that this is a merge of the RC. The "Context" should
- summarize the changes from the RC. Include the following text
- prominently:
+3. `BuildInfo.cpp` will have a conflict with the version number. Resolve it with the version from `develop` - the higher version.
+4. Push your branch to your repo (or `upstream` if you have permission), and open a normal PR against `develop`. The "High level overview" can simply indicate that this is a merge of the RC. The "Context" should summarize the changes from the RC. Include the following text prominently:
```
This PR must be merged manually using a push. Do not use the Github UI.
```
-5. Depending on the complexity of the changes, and/or merge conflicts,
- the PR may need a thorough review, or just a sign-off that the
- merge was done correctly.
-6. If `develop` is updated before this PR is merged, do not merge
- `develop` back into your branch. Instead rebase preserving merges,
- or do the merge again. (See also the `rerere` git config setting.)
+5. Depending on the complexity of the changes, and/or merge conflicts, the PR may need a thorough review, or just a sign-off that the merge was done correctly.
+6. If `develop` is updated before this PR is merged, do not merge `develop` back into your branch. Instead rebase preserving merges, or do the merge again. (See also the `rerere` git config setting.)
```
git rebase --rebase-merges upstream/develop
@@ -906,30 +637,14 @@ Development on `develop` can proceed as normal.
A final release is any release that is not a beta or RC, such as 2.2.0.
-Only code that has already been tested and vetted across all three
-platforms should be included in a final release. Most of the time, that
-means that the commit immediately preceding the commit setting the
-version number will be an RC. Occasionally, there may be last-minute bug
-fixes included as well. If so, those bug fixes must have been tested
-internally as if they were RCs (at minimum, ensuring unit tests pass,
-and the app starts, syncs, and stops cleanly across all three
-platforms.)
+Only code that has already been tested and vetted across all three platforms should be included in a final release. Most of the time, that means that the commit immediately preceding the commit setting the version number will be an RC. Occasionally, there may be last-minute bug fixes included as well. If so, those bug fixes must have been tested internally as if they were RCs (at minimum, ensuring unit tests pass, and the app starts, syncs, and stops cleanly across all three platforms.)
_If in doubt, make an RC first._
-The process for building a final release is very similar to [the process
-for building a beta](#making-the-release), except the code will be
-moving from `release` to `master` instead of from `develop` to
-`release`, and both branches will be pushed at the same time.
+The process for building a final release is very similar to [the process for building a beta](#making-the-release), except the code will be moving from `release` to `master` instead of from `develop` to `release`, and both branches will be pushed at the same time.
-1. Ensure there is no old `master-next` branch hanging around.
- Then make a `master-next` branch that only changes the version
- number. As above, or using the
- [update-version] script.
-2. Create a Pull Request for `master-next` with **`master`** as
- the base branch. Instead of the default template, reuse and update
- the message from the previous final release. Include the following verbiage
- somewhere in the description:
+1. Ensure there is no old `master-next` branch hanging around. Then make a `master-next` branch that only changes the version number. As above, or using the [update-version] script.
+2. Create a Pull Request for `master-next` with **`master`** as the base branch. Instead of the default template, reuse and update the message from the previous final release. Include the following verbiage somewhere in the description:
```
The base branch is `master`. This PR branch will be pushed directly to
@@ -937,11 +652,8 @@ The base branch is `master`. This PR branch will be pushed directly to
GitHub UI).
```
-7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur
- offline, but at least one approval will be needed on the PR.
- - If issues are discovered during testing, close the PR, delete
- `master-next`, and move development back to `release`, [issuing
- more RCs as necessary](#release-candidates-after-the-first)
+7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur offline, but at least one approval will be needed on the PR.
+ - If issues are discovered during testing, close the PR, delete `master-next`, and move development back to `release`, [issuing more RCs as necessary](#release-candidates-after-the-first)
8. Once everything is ready to go, push to `release` and `master`.
```
@@ -980,31 +692,19 @@ git push upstream-push
git push --delete upstream-push master-next
```
-11. [Create a new release on
- Github](https://github.com/XRPLF/rippled/releases). Be sure that
- "Set as the latest release" is checked.
+11. [Create a new release on Github](https://github.com/XRPLF/rippled/releases). Be sure that "Set as the latest release" is checked.
12. Open a PR to update the [API-CHANGELOG](API-CHANGELOG.md) and `API-VERSION-[n].md` with the changes for this release (if any are missing).
13. Finally, [reverse merge the release into `develop`](#follow-up-reverse-merge).
#### Special cases: point releases, hotfixes, etc.
-On occasion, a bug or issue is discovered in a version that already
-had a final release. Most of the time, development will have started
-on the next version, and will usually have changes in `develop`
-and often in `release`.
+On occasion, a bug or issue is discovered in a version that already had a final release. Most of the time, development will have started on the next version, and will usually have changes in `develop` and often in `release`.
-Because git history is kept as linear as possible, any fix and new
-version will need to be applied against `master`.
+Because git history is kept as linear as possible, any fix and new version will need to be applied against `master`.
-The process for building a hotfix release is very similar to [the
-process for building release candidates after the
-first](#release-candidates-after-the-first) and [for building a final
-release](#final-releases), except the changes will be done against
-`master` instead of `release`.
+The process for building a hotfix release is very similar to [the process for building release candidates after the first](#release-candidates-after-the-first) and [for building a final release](#final-releases), except the changes will be done against `master` instead of `release`.
-If there is only a single issue for the hotfix, the work can be done in
-any branch. When it's ready to merge, jump to step 3 using your branch
-instead of `master-next`.
+If there is only a single issue for the hotfix, the work can be done in any branch. When it's ready to merge, jump to step 3 using your branch instead of `master-next`.
1. Create a `master-next` branch from `master`.
@@ -1014,27 +714,17 @@ git push upstream-push
git fetch upstreams
```
-2. Open any PRs for the pending hotfix using `master-next` as the base,
- so they can be merged directly in to it. Unlike `develop`, though,
- `master-next` can be thrown away and recreated if necessary.
-3. Once the hotfix is ready, create a version commit using the same
- steps as above, or use the
- [update-version] script.
-4. Create a Pull Request for `master-next` with **`master`** as
- the base branch. Instead of the default template, reuse and update
- the message from the previous final release. Include the following verbiage
- somewhere in the description:
+2. Open any PRs for the pending hotfix using `master-next` as the base, so they can be merged directly in to it. Unlike `develop`, though, `master-next` can be thrown away and recreated if necessary.
+3. Once the hotfix is ready, create a version commit using the same steps as above, or use the [update-version] script.
+4. Create a Pull Request for `master-next` with **`master`** as the base branch. Instead of the default template, reuse and update the message from the previous final release. Include the following verbiage somewhere in the description:
```
The base branch is `master`. This PR branch will be pushed directly to
`master` (not squashed or rebased, and not using the GitHub UI).
```
-7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur
- offline, but at least one approval will be needed on the PR.
- - If issues are discovered during testing, update `master-next` as
- needed, but ensure that the changes are properly squashed, and the
- version setting commit remains last
+7. Sign-offs for the three platforms (Linux, Mac, Windows) usually occur offline, but at least one approval will be needed on the PR.
+ - If issues are discovered during testing, update `master-next` as needed, but ensure that the changes are properly squashed, and the version setting commit remains last
8. Once everything is ready to go, push to `master` **only**.
```
@@ -1071,17 +761,11 @@ git push upstream-push
git push --delete upstream-push master-next
```
-10. [Create a new release on
- Github](https://github.com/XRPLF/rippled/releases). Be sure that
- "Set as the latest release" is checked.
+10. [Create a new release on Github](https://github.com/XRPLF/rippled/releases). Be sure that "Set as the latest release" is checked.
-Once the hotfix is released, it needs to be reverse merged into
-`develop` as soon as possible. It may also need to be merged into
-`release` if a release candidate is under development.
+Once the hotfix is released, it needs to be reverse merged into `develop` as soon as possible. It may also need to be merged into `release` if a release candidate is under development.
-1. Create a branch in your own repo, based on `upstream/develop`.
- The branch name is not important, but could include "mergeNNN".
- E.g. For release 2.2.3, use `merge223`.
+1. Create a branch in your own repo, based on `upstream/develop`. The branch name is not important, but could include "mergeNNN". E.g. For release 2.2.3, use `merge223`.
```
git fetch upstreams
@@ -1097,24 +781,15 @@ git checkout --no-track -b merge223 upstream/develop
git merge upstream/master
```
-3. `BuildInfo.cpp` will have a conflict with the version number.
- Resolve it with the version from `develop` - the higher version.
-4. Push your branch to your repo, and open a normal PR against
- `develop`. The "High level overview" can simply indicate that this
- is a merge of the hotfix version. The "Context" should summarize
- the changes from the hotfix. Include the following text
- prominently:
+3. `BuildInfo.cpp` will have a conflict with the version number. Resolve it with the version from `develop` - the higher version.
+4. Push your branch to your repo, and open a normal PR against `develop`. The "High level overview" can simply indicate that this is a merge of the hotfix version. The "Context" should summarize the changes from the hotfix. Include the following text prominently:
```
This PR must be merged manually using a --ff-only merge. Do not use the Github UI.
```
-5. Depending on the complexity of the hotfix, and/or merge conflicts,
- the PR may need a thorough review, or just a sign-off that the
- merge was done correctly.
-6. If `develop` is updated before this PR is merged, do not merge
- `develop` back into your branch. Instead rebase preserving merges,
- or do the merge again. (See also the `rerere` git config setting.)
+5. Depending on the complexity of the hotfix, and/or merge conflicts, the PR may need a thorough review, or just a sign-off that the merge was done correctly.
+6. If `develop` is updated before this PR is merged, do not merge `develop` back into your branch. Instead rebase preserving merges, or do the merge again. (See also the `rerere` git config setting.)
```
git rebase --rebase-merges upstream/develop
@@ -1134,22 +809,13 @@ git log --show-signature "upstream/develop..HEAD"
git push upstream-push HEAD:develop
```
-Development on `develop` can proceed as normal. It is recommended to
-create a beta (or RC) immediately to ensure that everything worked as
-expected.
+Development on `develop` can proceed as normal. It is recommended to create a beta (or RC) immediately to ensure that everything worked as expected.
##### An even rarer scenario: A hotfix on an old release
-Historically, once a final release is tagged and packages are released,
-versions older than the latest final release are no longer supported.
-However, there is a possibility that a very high severity bug may occur
-in a non-amendment blocked version that is still being run by
-a significant fraction of users, which would necessitate a hotfix / point
-release to that version as well as any later versions.
+Historically, once a final release is tagged and packages are released, versions older than the latest final release are no longer supported. However, there is a possibility that a very high severity bug may occur in a non-amendment blocked version that is still being run by a significant fraction of users, which would necessitate a hotfix / point release to that version as well as any later versions.
-This scenario would follow the same basic procedure as above,
-except that _none_ of `develop`, `release`, or `master`
-would be touched during the release process.
+This scenario would follow the same basic procedure as above, except that _none_ of `develop`, `release`, or `master` would be touched during the release process.
In this example, consider if version 2.1.1 needed to be patched.
@@ -1169,20 +835,9 @@ git push upstream-push
git fetch upstreams
```
-2. Work continues as above, except using `master-2.1.2`as
- the base branch for any merging, packaging, etc.
-3. After the release is tagged and packages are built, you could
- potentially delete both branches, e.g. `master-2.1.2` and
- `master212-next`. However, it may be useful to keep `master-2.1.2`
- around indefinitely for reference.
-4. Assuming that a hotfix is also released for the latest
- version in parallel with this one, or if the issue is
- already fixed in the latest version, do no do any
- reverse merges. However, if it is not, it probably makes
- sense to reverse merge `master-2.1.2` into `master`,
- release a hotfix for _that_ version, then reverse merge
- from `master` to `develop`. (Please don't do this unless absolutely
- necessary.)
+2. Work continues as above, except using `master-2.1.2`as the base branch for any merging, packaging, etc.
+3. After the release is tagged and packages are built, you could potentially delete both branches, e.g. `master-2.1.2` and `master212-next`. However, it may be useful to keep `master-2.1.2` around indefinitely for reference.
+4. Assuming that a hotfix is also released for the latest version in parallel with this one, or if the issue is already fixed in the latest version, do no do any reverse merges. However, if it is not, it probably makes sense to reverse merge `master-2.1.2` into `master`, release a hotfix for _that_ version, then reverse merge from `master` to `develop`. (Please don't do this unless absolutely necessary.)
[contrib]: https://docs.github.com/en/get-started/quickstart/contributing-to-projects
[squash]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-commits
diff --git a/LICENSE.md b/LICENSE.md
index 7e6e62994c..b3bfcce368 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,16 +1,7 @@
ISC License
-Copyright (c) 2011, Arthur Britto, David Schwartz, Jed McCaleb, Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant.
-Copyright (c) 2012-present, the XRP Ledger developers.
+Copyright (c) 2011, Arthur Britto, David Schwartz, Jed McCaleb, Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant. Copyright (c) 2012-present, the XRP Ledger developers.
-Permission to use, copy, modify, and distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
+Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/README.md b/README.md
index a0d30ef68b..fdbc5b7a9a 100644
--- a/README.md
+++ b/README.md
@@ -56,8 +56,7 @@ Here are some good places to start learning the source code:
| `./src` | Source code. |
| `./crates` | Rust source code. |
-Some of the directories under `src` are external repositories included using
-git-subtree. See those directories' README files for more details.
+Some of the directories under `src` are external repositories included using git-subtree. See those directories' README files for more details.
## Additional Documentation
diff --git a/conan/lockfile/README.md b/conan/lockfile/README.md
index 5e70de102d..cf84915b60 100644
--- a/conan/lockfile/README.md
+++ b/conan/lockfile/README.md
@@ -2,11 +2,8 @@
To achieve reproducible dependencies, we use a [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html).
-The `conan.lock` file in the repository contains a "snapshot" of the current
-dependencies. It is implicitly used when running `conan` commands, so you don't
-need to specify it.
+The `conan.lock` file in the repository contains a "snapshot" of the current dependencies. It is implicitly used when running `conan` commands, so you don't need to specify it.
-You have to update this file every time you add a new dependency or change a
-revision or version of an existing dependency.
+You have to update this file every time you add a new dependency or change a revision or version of an existing dependency.
To update a lockfile, run from the repository root: `./conan/lockfile/regenerate.sh`
diff --git a/docs/0001-negative-unl/README.md b/docs/0001-negative-unl/README.md
index 0bc65cd860..a2a21613f2 100644
--- a/docs/0001-negative-unl/README.md
+++ b/docs/0001-negative-unl/README.md
@@ -2,61 +2,21 @@
## The Problem Statement
-The moment-to-moment health of the XRP Ledger network depends on the health and
-connectivity of a small number of computers (nodes). The most important nodes
-are validators, specifically ones listed on the unique node list
-([UNL](#Question-What-are-UNLs)). Ripple publishes a recommended UNL that most
-network nodes use to determine which peers in the network are trusted. Although
-most validators use the same list, they are not required to. The XRP Ledger
-network progresses to the next ledger when enough validators reach agreement
-(above the minimum quorum of 80%) about what transactions to include in the next
-ledger.
+The moment-to-moment health of the XRP Ledger network depends on the health and connectivity of a small number of computers (nodes). The most important nodes are validators, specifically ones listed on the unique node list ([UNL](#Question-What-are-UNLs)). Ripple publishes a recommended UNL that most network nodes use to determine which peers in the network are trusted. Although most validators use the same list, they are not required to. The XRP Ledger network progresses to the next ledger when enough validators reach agreement (above the minimum quorum of 80%) about what transactions to include in the next ledger.
-As an example, if there are 10 validators on the UNL, at least 8 validators have
-to agree with the latest ledger for it to become validated. But what if enough
-of those validators are offline to drop the network below the 80% quorum? The
-XRP Ledger network favors safety/correctness over advancing the ledger. Which
-means if enough validators are offline, the network will not be able to validate
-ledgers.
+As an example, if there are 10 validators on the UNL, at least 8 validators have to agree with the latest ledger for it to become validated. But what if enough of those validators are offline to drop the network below the 80% quorum? The XRP Ledger network favors safety/correctness over advancing the ledger. Which means if enough validators are offline, the network will not be able to validate ledgers.
-Unfortunately validators can go offline at any time for many different reasons.
-Power outages, network connectivity issues, and hardware failures are just a few
-scenarios where a validator would appear "offline". Given that most of these
-events are temporary, it would make sense to temporarily remove that validator
-from the UNL. But the UNL is updated infrequently and not every node uses the
-same UNL. So instead of removing the unreliable validator from the Ripple
-recommended UNL, we can create a second negative UNL which is stored directly on
-the ledger (so the entire network has the same view). This will help the network
-see which validators are **currently** unreliable, and adjust their quorum
-calculation accordingly.
+Unfortunately validators can go offline at any time for many different reasons. Power outages, network connectivity issues, and hardware failures are just a few scenarios where a validator would appear "offline". Given that most of these events are temporary, it would make sense to temporarily remove that validator from the UNL. But the UNL is updated infrequently and not every node uses the same UNL. So instead of removing the unreliable validator from the Ripple recommended UNL, we can create a second negative UNL which is stored directly on the ledger (so the entire network has the same view). This will help the network see which validators are **currently** unreliable, and adjust their quorum calculation accordingly.
_Improving the liveness of the network is the main motivation for the negative UNL._
### Targeted Faults
-In order to determine which validators are unreliable, we need clearly define
-what kind of faults to measure and analyze. We want to deal with the faults we
-frequently observe in the production network. Hence we will only monitor for
-validators that do not reliably respond to network messages or send out
-validations disagreeing with the locally generated validations. We will not
-target other byzantine faults.
+In order to determine which validators are unreliable, we need clearly define what kind of faults to measure and analyze. We want to deal with the faults we frequently observe in the production network. Hence we will only monitor for validators that do not reliably respond to network messages or send out validations disagreeing with the locally generated validations. We will not target other byzantine faults.
-To track whether or not a validator is responding to the network, we could
-monitor them with a “heartbeat” protocol. Instead of creating a new heartbeat
-protocol, we can leverage some existing protocol messages to mimic the
-heartbeat. We picked validation messages because validators should send one and
-only one validation message per ledger. In addition, we only count the
-validation messages that agree with the local node's validations.
+To track whether or not a validator is responding to the network, we could monitor them with a “heartbeat” protocol. Instead of creating a new heartbeat protocol, we can leverage some existing protocol messages to mimic the heartbeat. We picked validation messages because validators should send one and only one validation message per ledger. In addition, we only count the validation messages that agree with the local node's validations.
-With the negative UNL, the network could keep making forward progress safely
-even if the number of remaining validators gets to 60%. Say we have a network
-with 10 validators on the UNL and everything is operating correctly. The quorum
-required for this network would be 8 (80% of 10). When validators fail, the
-quorum required would be as low as 6 (60% of 10), which is the absolute
-**_minimum quorum_**. We need the absolute minimum quorum to be strictly greater
-than 50% of the original UNL so that there cannot be two partitions of
-well-behaved nodes headed in different directions. We arbitrarily choose 60% as
-the minimum quorum to give a margin of safety.
+With the negative UNL, the network could keep making forward progress safely even if the number of remaining validators gets to 60%. Say we have a network with 10 validators on the UNL and everything is operating correctly. The quorum required for this network would be 8 (80% of 10). When validators fail, the quorum required would be as low as 6 (60% of 10), which is the absolute **_minimum quorum_**. We need the absolute minimum quorum to be strictly greater than 50% of the original UNL so that there cannot be two partitions of well-behaved nodes headed in different directions. We arbitrarily choose 60% as the minimum quorum to give a margin of safety.
Consider these events in the absence of negative UNL:
@@ -65,10 +25,7 @@ Consider these events in the absence of negative UNL:
1. 5:00pm - validator3 fails, votes vs. quorum: 7 < 8, we don’t have quorum
- **network cannot validate new ledgers with 3 failed validators**
-We're below 80% agreement, so new ledgers cannot be validated. This is how the
-XRP Ledger operates today, but if the negative UNL was enabled, the events would
-happen as follows. (Please note that the events below are from a simplified
-version of our protocol.)
+We're below 80% agreement, so new ledgers cannot be validated. This is how the XRP Ledger operates today, but if the negative UNL was enabled, the events would happen as follows. (Please note that the events below are from a simplified version of our protocol.)
1. 1:00pm - validator1 fails, votes vs. quorum: 9 >= 8, we have quorum
1. 1:40pm - network adds validator1 to negative UNL, quorum changes to ceil(9 \* 0.8), or 8
@@ -88,8 +45,7 @@ This proposal will:
1. add a new pseudo-transaction type
1. add the negative UNL to the ledger data structure.
-Any tools or systems that rely on the format of this data will have to be
-updated.
+Any tools or systems that rely on the format of this data will have to be updated.
### Amendment
@@ -105,122 +61,70 @@ This section discusses the following topics about the Negative UNL design:
- [Negative UNL maintenance](#Negative-UNL-Maintenance)
- [Quorum size calculation](#Quorum-Size-Calculation)
- [Filter validation messages](#Filter-Validation-Messages)
-- [High level sequence diagram of code
- changes](#High-Level-Sequence-Diagram-of-Code-Changes)
+- [High level sequence diagram of code changes](#High-Level-Sequence-Diagram-of-Code-Changes)
### Negative UNL Protocol Overview
-Every ledger stores a list of zero or more unreliable validators. Updates to the
-list must be approved by the validators using the consensus mechanism that
-validators use to agree on the set of transactions. The list is used only when
-checking if a ledger is fully validated. If a validator V is in the list, nodes
-with V in their UNL adjust the quorum and V’s validation message is not counted
-when verifying if a ledger is fully validated. V’s flow of messages and network
-interactions, however, will remain the same.
+Every ledger stores a list of zero or more unreliable validators. Updates to the list must be approved by the validators using the consensus mechanism that validators use to agree on the set of transactions. The list is used only when checking if a ledger is fully validated. If a validator V is in the list, nodes with V in their UNL adjust the quorum and V’s validation message is not counted when verifying if a ledger is fully validated. V’s flow of messages and network interactions, however, will remain the same.
-We define the **\*effective UNL** = original UNL - negative UNL\*, and the
-**_effective quorum_** as the quorum of the _effective UNL_. And we set
-_effective quorum = Ceiling(80% _ effective UNL)\*.
+We define the **\*effective UNL** = original UNL - negative UNL\*, and the **_effective quorum_** as the quorum of the _effective UNL_. And we set _effective quorum = Ceiling(80% _ effective UNL)\*.
### Validator Reliability Measurement
-A node only measures the reliability of validators on its own UNL, and only
-proposes based on local observations. There are many metrics that a node can
-measure about its validators, but we have chosen ledger validation messages.
-This is because every validator shall send one and only one signed validation
-message per ledger. This keeps the measurement simple and removes
-timing/clock-sync issues. A node will measure the percentage of agreeing
-validation messages (_PAV_) received from each validator on the node's UNL. Note
-that the node will only count the validation messages that agree with its own
-validations.
+A node only measures the reliability of validators on its own UNL, and only proposes based on local observations. There are many metrics that a node can measure about its validators, but we have chosen ledger validation messages. This is because every validator shall send one and only one signed validation message per ledger. This keeps the measurement simple and removes timing/clock-sync issues. A node will measure the percentage of agreeing validation messages (_PAV_) received from each validator on the node's UNL. Note that the node will only count the validation messages that agree with its own validations.
-We define the **PAV** as the Percentage of Agreed Validation
-messages received for the last N ledgers, where N = 256 by default.
+We define the **PAV** as the Percentage of Agreed Validation messages received for the last N ledgers, where N = 256 by default.
-When the PAV drops below the **_low-water mark_**, the validator is considered
-unreliable, and is a candidate to be disabled by being added to the negative
-UNL. A validator must have a PAV higher than the **_high-water mark_** to be
-re-enabled. The validator is re-enabled by removing it from the negative UNL. In
-the implementation, we plan to set the low-water mark as 50% and the high-water
-mark as 80%.
+When the PAV drops below the **_low-water mark_**, the validator is considered unreliable, and is a candidate to be disabled by being added to the negative UNL. A validator must have a PAV higher than the **_high-water mark_** to be re-enabled. The validator is re-enabled by removing it from the negative UNL. In the implementation, we plan to set the low-water mark as 50% and the high-water mark as 80%.
### Format Changes
The negative UNL component in a ledger contains three fields.
- **_NegativeUNL_**: The current negative UNL, a list of unreliable validators.
-- **_ToDisable_**: The validator to be added to the negative UNL on the next
- flag ledger.
-- **_ToReEnable_**: The validator to be removed from the negative UNL on the
- next flag ledger.
+- **_ToDisable_**: The validator to be added to the negative UNL on the next flag ledger.
+- **_ToReEnable_**: The validator to be removed from the negative UNL on the next flag ledger.
-All three fields are optional. When the _ToReEnable_ field exists, the
-_NegativeUNL_ field cannot be empty.
+All three fields are optional. When the _ToReEnable_ field exists, the _NegativeUNL_ field cannot be empty.
A new pseudo-transaction, **_UNLModify_**, is added. It has three fields
-- **_Disabling_**: A flag indicating whether the modification is to disable or
- to re-enable a validator.
+- **_Disabling_**: A flag indicating whether the modification is to disable or to re-enable a validator.
- **_Seq_**: The ledger sequence number.
- **_Validator_**: The validator to be disabled or re-enabled.
-There would be at most one _disable_ `UNLModify` and one _re-enable_ `UNLModify`
-transaction per flag ledger. The full machinery is described further on.
+There would be at most one _disable_ `UNLModify` and one _re-enable_ `UNLModify` transaction per flag ledger. The full machinery is described further on.
### Negative UNL Maintenance
-The negative UNL can only be modified on the flag ledgers. If a validator's
-reliability status changes, it takes two flag ledgers to modify the negative
-UNL. Let's see an example of the algorithm:
+The negative UNL can only be modified on the flag ledgers. If a validator's reliability status changes, it takes two flag ledgers to modify the negative UNL. Let's see an example of the algorithm:
- Ledger seq = 100: A validator V goes offline.
-- Ledger seq = 256: This is a flag ledger, and V's reliability measurement _PAV_
- is lower than the low-water mark. Other validators add `UNLModify`
- pseudo-transactions `{true, 256, V}` to the transaction set which goes through
- the consensus. Then the pseudo-transaction is applied to the negative UNL
- ledger component by setting `ToDisable = V`.
-- Ledger seq = 257 ~ 511: The negative UNL ledger component is copied from the
- parent ledger.
-- Ledger seq=512: This is a flag ledger, and the negative UNL is updated
- `NegativeUNL = NegativeUNL + ToDisable`.
+- Ledger seq = 256: This is a flag ledger, and V's reliability measurement _PAV_ is lower than the low-water mark. Other validators add `UNLModify` pseudo-transactions `{true, 256, V}` to the transaction set which goes through the consensus. Then the pseudo-transaction is applied to the negative UNL ledger component by setting `ToDisable = V`.
+- Ledger seq = 257 ~ 511: The negative UNL ledger component is copied from the parent ledger.
+- Ledger seq=512: This is a flag ledger, and the negative UNL is updated `NegativeUNL = NegativeUNL + ToDisable`.
-The negative UNL may have up to `MaxNegativeListed = floor(original UNL * 25%)`
-validators. The 25% is because of 75% \* 80% = 60%, where 75% = 100% - 25%, 80%
-is the quorum of the effective UNL, and 60% is the absolute minimum quorum of
-the original UNL. Adding more than 25% validators to the negative UNL does not
-improve the liveness of the network, because adding more validators to the
-negative UNL cannot lower the effective quorum.
+The negative UNL may have up to `MaxNegativeListed = floor(original UNL * 25%)` validators. The 25% is because of 75% \* 80% = 60%, where 75% = 100% - 25%, 80% is the quorum of the effective UNL, and 60% is the absolute minimum quorum of the original UNL. Adding more than 25% validators to the negative UNL does not improve the liveness of the network, because adding more validators to the negative UNL cannot lower the effective quorum.
The following is the detailed algorithm:
- **If** the ledger seq = x is a flag ledger
- 1. Compute `NegativeUNL = NegativeUNL + ToDisable - ToReEnable` if they
- exist in the parent ledger
+ 1. Compute `NegativeUNL = NegativeUNL + ToDisable - ToReEnable` if they exist in the parent ledger
1. Try to find a candidate to disable if `sizeof NegativeUNL < MaxNegativeListed`
- 1. Find a validator V that has a _PAV_ lower than the low-water
- mark, but is not in `NegativeUNL`.
+ 1. Find a validator V that has a _PAV_ lower than the low-water mark, but is not in `NegativeUNL`.
- 1. If two or more are found, their public keys are XORed with the hash
- of the parent ledger and the one with the lowest XOR result is chosen.
- 1. If V is found, create a `UNLModify` pseudo-transaction
- `TxDisableValidator = {true, x, V}`
+ 1. If two or more are found, their public keys are XORed with the hash of the parent ledger and the one with the lowest XOR result is chosen.
+ 1. If V is found, create a `UNLModify` pseudo-transaction `TxDisableValidator = {true, x, V}`
1. Try to find a candidate to re-enable if `sizeof NegativeUNL > 0`:
- 1. Find a validator U that is in `NegativeUNL` and has a _PAV_ higher
- than the high-water mark.
- 1. If U is not found, try to find one in `NegativeUNL` but not in the
- local _UNL_.
- 1. If two or more are found, their public keys are XORed with the hash
- of the parent ledger and the one with the lowest XOR result is chosen.
- 1. If U is found, create a `UNLModify` pseudo-transaction
- `TxReEnableValidator = {false, x, U}`
+ 1. Find a validator U that is in `NegativeUNL` and has a _PAV_ higher than the high-water mark.
+ 1. If U is not found, try to find one in `NegativeUNL` but not in the local _UNL_.
+ 1. If two or more are found, their public keys are XORed with the hash of the parent ledger and the one with the lowest XOR result is chosen.
+ 1. If U is found, create a `UNLModify` pseudo-transaction `TxReEnableValidator = {false, x, U}`
- 1. If any `UNLModify` pseudo-transactions are created, add them to the
- transaction set. The transaction set goes through the consensus algorithm.
- 1. If have enough support, the `UNLModify` pseudo-transactions remain in the
- transaction set agreed by the validators. Then the pseudo-transactions are
- applied to the ledger:
+ 1. If any `UNLModify` pseudo-transactions are created, add them to the transaction set. The transaction set goes through the consensus algorithm.
+ 1. If have enough support, the `UNLModify` pseudo-transactions remain in the transaction set agreed by the validators. Then the pseudo-transactions are applied to the ledger:
1. If have `TxDisableValidator`, set `ToDisable=TxDisableValidator.V`.
Else clear `ToDisable`.
@@ -231,61 +135,33 @@ The following is the detailed algorithm:
- **Else** (not a flag ledger)
1. Copy the negative UNL ledger component from the parent ledger
-The negative UNL is stored on each ledger because we don't know when a validator
-may reconnect to the network. If the negative UNL was stored only on every flag
-ledger, then a new validator would have to wait until it acquires the latest
-flag ledger to know the negative UNL. So any new ledgers created that are not
-flag ledgers copy the negative UNL from the parent ledger.
+The negative UNL is stored on each ledger because we don't know when a validator may reconnect to the network. If the negative UNL was stored only on every flag ledger, then a new validator would have to wait until it acquires the latest flag ledger to know the negative UNL. So any new ledgers created that are not flag ledgers copy the negative UNL from the parent ledger.
-Note that when we have a validator to disable and a validator to re-enable at
-the same flag ledger, we create two separate `UNLModify` pseudo-transactions. We
-want either one or the other or both to make it into the ledger on their own
-merits.
+Note that when we have a validator to disable and a validator to re-enable at the same flag ledger, we create two separate `UNLModify` pseudo-transactions. We want either one or the other or both to make it into the ledger on their own merits.
-Readers may have noticed that we defined several rules of creating the
-`UNLModify` pseudo-transactions but did not describe how to enforce the rules.
-The rules are actually enforced by the existing consensus algorithm. Unless
-enough validators propose the same pseudo-transaction it will not be included in
-the transaction set of the ledger.
+Readers may have noticed that we defined several rules of creating the `UNLModify` pseudo-transactions but did not describe how to enforce the rules. The rules are actually enforced by the existing consensus algorithm. Unless enough validators propose the same pseudo-transaction it will not be included in the transaction set of the ledger.
### Quorum Size Calculation
-The effective quorum is 80% of the effective UNL. Note that because at most 25%
-of the original UNL can be on the negative UNL, the quorum should not be lower
-than the absolute minimum quorum (i.e. 60%) of the original UNL. However,
-considering that different nodes may have different UNLs, to be safe we compute
-`quorum = Ceiling(max(60% * original UNL, 80% * effective UNL))`.
+The effective quorum is 80% of the effective UNL. Note that because at most 25% of the original UNL can be on the negative UNL, the quorum should not be lower than the absolute minimum quorum (i.e. 60%) of the original UNL. However, considering that different nodes may have different UNLs, to be safe we compute `quorum = Ceiling(max(60% * original UNL, 80% * effective UNL))`.
### Filter Validation Messages
-If a validator V is in the negative UNL, it still participates in consensus
-sessions in the same way, i.e. V still follows the protocol and publishes
-proposal and validation messages. The messages from V are still stored the same
-way by everyone, used to calculate the new PAV for V, and could be used in
-future consensus sessions if needed. However V's ledger validation message is
-not counted when checking if the ledger is fully validated.
+If a validator V is in the negative UNL, it still participates in consensus sessions in the same way, i.e. V still follows the protocol and publishes proposal and validation messages. The messages from V are still stored the same way by everyone, used to calculate the new PAV for V, and could be used in future consensus sessions if needed. However V's ledger validation message is not counted when checking if the ledger is fully validated.
### High Level Sequence Diagram of Code Changes
-The diagram below is the sequence of one round of consensus. Classes and
-components with non-trivial changes are colored green.
+The diagram below is the sequence of one round of consensus. Classes and components with non-trivial changes are colored green.
-- The `ValidatorList` class is modified to compute the quorum of the effective
- UNL.
+- The `ValidatorList` class is modified to compute the quorum of the effective UNL.
-- The `Validations` class provides an interface for querying the validation
- messages from trusted validators.
+- The `Validations` class provides an interface for querying the validation messages from trusted validators.
- The `ConsensusAdaptor` component:
- - The `RCLConsensus::Adaptor` class is modified for creating `UNLModify`
- Pseudo-Transactions.
- - The `Change` class is modified for applying `UNLModify`
- Pseudo-Transactions.
- - The `Ledger` class is modified for creating and adjusting the negative UNL
- ledger component.
- - The `LedgerMaster` class is modified for filtering out validation messages
- from negative UNL validators when verifying if a ledger is fully
- validated.
+ - The `RCLConsensus::Adaptor` class is modified for creating `UNLModify` Pseudo-Transactions.
+ - The `Change` class is modified for applying `UNLModify` Pseudo-Transactions.
+ - The `Ledger` class is modified for creating and adjusting the negative UNL ledger component.
+ - The `LedgerMaster` class is modified for filtering out validation messages from negative UNL validators when verifying if a ledger is fully validated.

@@ -294,63 +170,29 @@ Changes")
### Use a Mechanism Like Fee Voting to Process UNLModify Pseudo-Transactions
-The previous version of the negative UNL specification used the same mechanism
-as the [fee voting](https://xrpl.org/fee-voting.html#voting-process.) for
-creating the negative UNL, and used the negative UNL as soon as the ledger was
-fully validated. However the timing of fully validation can differ among nodes,
-so different negative UNLs could be used, resulting in different effective UNLs
-and different quorums for the same ledger. As a result, the network's safety is
-impacted.
+The previous version of the negative UNL specification used the same mechanism as the [fee voting](https://xrpl.org/fee-voting.html#voting-process.) for creating the negative UNL, and used the negative UNL as soon as the ledger was fully validated. However the timing of fully validation can differ among nodes, so different negative UNLs could be used, resulting in different effective UNLs and different quorums for the same ledger. As a result, the network's safety is impacted.
-This updated version does not impact safety though operates a bit more slowly.
-The negative UNL modifications in the _UNLModify_ pseudo-transaction approved by
-the consensus will take effect at the next flag ledger. The extra time of the
-256 ledgers should be enough for nodes to be in sync of the negative UNL
-modifications.
+This updated version does not impact safety though operates a bit more slowly. The negative UNL modifications in the _UNLModify_ pseudo-transaction approved by the consensus will take effect at the next flag ledger. The extra time of the 256 ledgers should be enough for nodes to be in sync of the negative UNL modifications.
### Use an Expiration Approach to Re-enable Validators
-After a validator disabled by the negative UNL becomes reliable, other
-validators explicitly vote for re-enabling it. An alternative approach to
-re-enable a validator is the expiration approach, which was considered in the
-previous version of the specification. In the expiration approach, every entry
-in the negative UNL has a fixed expiration time. One flag ledger interval was
-chosen as the expiration interval. Once expired, the other validators must
-continue voting to keep the unreliable validator on the negative UNL. The
-advantage of this approach is its simplicity. But it has a requirement. The
-negative UNL protocol must be able to vote multiple unreliable validators to be
-disabled at the same flag ledger. In this version of the specification, however,
-only one unreliable validator can be disabled at a flag ledger. So the
-expiration approach cannot be simply applied.
+After a validator disabled by the negative UNL becomes reliable, other validators explicitly vote for re-enabling it. An alternative approach to re-enable a validator is the expiration approach, which was considered in the previous version of the specification. In the expiration approach, every entry in the negative UNL has a fixed expiration time. One flag ledger interval was chosen as the expiration interval. Once expired, the other validators must continue voting to keep the unreliable validator on the negative UNL. The advantage of this approach is its simplicity. But it has a requirement. The negative UNL protocol must be able to vote multiple unreliable validators to be disabled at the same flag ledger. In this version of the specification, however, only one unreliable validator can be disabled at a flag ledger. So the expiration approach cannot be simply applied.
### Validator Reliability Measurement and Flag Ledger Frequency
-If the ledger time is about 4.5 seconds and the low-water mark is 50%, then in
-the worst case, it takes 48 minutes _((0.5 _ 256 + 256 + 256) _ 4.5 / 60 = 48)_
-to put an offline validator on the negative UNL. We considered lowering the flag
-ledger frequency so that the negative UNL can be more responsive. We also
-considered decoupling the reliability measurement and flag ledger frequency to
-be more flexible. In practice, however, their benefits are not clear.
+If the ledger time is about 4.5 seconds and the low-water mark is 50%, then in the worst case, it takes 48 minutes _((0.5 _ 256 + 256 + 256) _ 4.5 / 60 = 48)_ to put an offline validator on the negative UNL. We considered lowering the flag ledger frequency so that the negative UNL can be more responsive. We also considered decoupling the reliability measurement and flag ledger frequency to be more flexible. In practice, however, their benefits are not clear.
## New Attack Vectors
-A group of malicious validators may try to frame a reliable validator and put it
-on the negative UNL. But they cannot succeed. Because:
+A group of malicious validators may try to frame a reliable validator and put it on the negative UNL. But they cannot succeed. Because:
-1. A reliable validator sends a signed validation message every ledger. A
- sufficient peer-to-peer network will propagate the validation messages to other
- validators. The validators will decide if another validator is reliable or not
- only by its local observation of the validation messages received. So an honest
- validator’s vote on another validator’s reliability is accurate.
+1. A reliable validator sends a signed validation message every ledger. A sufficient peer-to-peer network will propagate the validation messages to other validators. The validators will decide if another validator is reliable or not only by its local observation of the validation messages received. So an honest validator’s vote on another validator’s reliability is accurate.
-1. Given the votes are accurate, and one vote per validator, an honest validator
- will not create a UNLModify transaction of a reliable validator.
+1. Given the votes are accurate, and one vote per validator, an honest validator will not create a UNLModify transaction of a reliable validator.
-1. A validator can be added to a negative UNL only through a UNLModify
- transaction.
+1. A validator can be added to a negative UNL only through a UNLModify transaction.
-Assuming the group of malicious validators is less than the quorum, they cannot
-frame a reliable validator.
+Assuming the group of malicious validators is less than the quorum, they cannot frame a reliable validator.
## Summary
@@ -358,16 +200,13 @@ The bullet points below briefly summarize the current proposal:
- The motivation of the negative UNL is to improve the liveness of the network.
-- The targeted faults are the ones frequently observed in the production
- network.
+- The targeted faults are the ones frequently observed in the production network.
- Validators propose negative UNL candidates based on their local measurements.
- The absolute minimum quorum is 60% of the original UNL.
-- The format of the ledger is changed, and a new _UNLModify_ pseudo-transaction
- is added. Any tools or systems that rely on the format of these data will have
- to be updated.
+- The format of the ledger is changed, and a new _UNLModify_ pseudo-transaction is added. Any tools or systems that rely on the format of these data will have to be updated.
- The negative UNL can only be modified on the flag ledgers.
@@ -375,59 +214,39 @@ The bullet points below briefly summarize the current proposal:
- At most one validator can be removed from the negative UNL at a flag ledger.
-- If a validator's reliability status changes, it takes two flag ledgers to
- modify the negative UNL.
+- If a validator's reliability status changes, it takes two flag ledgers to modify the negative UNL.
-- The quorum is the larger of 80% of the effective UNL and 60% of the original
- UNL.
+- The quorum is the larger of 80% of the effective UNL and 60% of the original UNL.
-- If a validator is on the negative UNL, its validation messages are ignored
- when the local node verifies if a ledger is fully validated.
+- If a validator is on the negative UNL, its validation messages are ignored when the local node verifies if a ledger is fully validated.
## FAQ
### Question: What are UNLs?
-Quote from the [Technical FAQ](https://xrpl.org/technical-faq.html): "They are
-the lists of transaction validators a given participant believes will not
-conspire to defraud them."
+Quote from the [Technical FAQ](https://xrpl.org/technical-faq.html): "They are the lists of transaction validators a given participant believes will not conspire to defraud them."
### Question: How does the negative UNL proposal affect network liveness?
-The network can make forward progress when more than a quorum of the trusted
-validators agree with the progress. The lower the quorum size is, the easier for
-the network to progress. If the quorum is too low, however, the network is not
-safe because nodes may have different results. So the quorum size used in the
-consensus protocol is a balance between the safety and the liveness of the
-network. The negative UNL reduces the size of the effective UNL, resulting in a
-lower quorum size while keeping the network safe.
+The network can make forward progress when more than a quorum of the trusted validators agree with the progress. The lower the quorum size is, the easier for the network to progress. If the quorum is too low, however, the network is not safe because nodes may have different results. So the quorum size used in the consensus protocol is a balance between the safety and the liveness of the network. The negative UNL reduces the size of the effective UNL, resulting in a lower quorum size while keeping the network safe.
Question: How does a validator get into the negative UNL? How is a
validator removed from the negative UNL?
-A validator’s reliability is measured by other validators. If a validator
-becomes unreliable, at a flag ledger, other validators propose _UNLModify_
-pseudo-transactions which vote the validator to add to the negative UNL during
-the consensus session. If agreed, the validator is added to the negative UNL at
-the next flag ledger. The mechanism of removing a validator from the negative
-UNL is the same.
+A validator’s reliability is measured by other validators. If a validator becomes unreliable, at a flag ledger, other validators propose _UNLModify_ pseudo-transactions which vote the validator to add to the negative UNL during the consensus session. If agreed, the validator is added to the negative UNL at the next flag ledger. The mechanism of removing a validator from the negative UNL is the same.
### Question: Given a negative UNL, what happens if the UNL changes?
Answer: Let’s consider the cases:
-1. A validator is added to the UNL, and it is already in the negative UNL. This
- case could happen when not all the nodes have the same UNL. Note that the
- negative UNL on the ledger lists unreliable nodes that are not necessarily the
- validators for everyone.
+1. A validator is added to the UNL, and it is already in the negative UNL. This case could happen when not all the nodes have the same UNL. Note that the negative UNL on the ledger lists unreliable nodes that are not necessarily the validators for everyone.
In this case, the liveness is affected negatively. Because the minimum
quorum could be larger but the usable validators are not increased.
1. A validator is removed from the UNL, and it is in the negative UNL.
- In this case, the liveness is affected positively. Because the quorum could
- be smaller but the usable validators are not reduced.
+ In this case, the liveness is affected positively. Because the quorum could be smaller but the usable validators are not reduced.
1. A validator is added to the UNL, and it is not in the negative UNL.
1. A validator is removed from the UNL, and it is not in the negative UNL.
@@ -438,59 +257,23 @@ Answer: Let’s consider the cases:
Answer: No, because the negative UNL approach is safer.
-First let’s compare the two approaches intuitively, (1) the _negative UNL_
-approach, and (2) _lower quorum_: simply lowering the quorum from 80% to 60%
-without the negative UNL. The negative UNL approach uses consensus to come up
-with a list of unreliable validators, which are then removed from the effective
-UNL temporarily. With this approach, the list of unreliable validators is agreed
-to by a quorum of validators and will be used by every node in the network to
-adjust its UNL. The quorum is always 80% of the effective UNL. The lower quorum
-approach is a tradeoff between safety and liveness and against our principle of
-preferring safety over liveness. Note that different validators don't have to
-agree on which validation sources they are ignoring.
+First let’s compare the two approaches intuitively, (1) the _negative UNL_ approach, and (2) _lower quorum_: simply lowering the quorum from 80% to 60% without the negative UNL. The negative UNL approach uses consensus to come up with a list of unreliable validators, which are then removed from the effective UNL temporarily. With this approach, the list of unreliable validators is agreed to by a quorum of validators and will be used by every node in the network to adjust its UNL. The quorum is always 80% of the effective UNL. The lower quorum approach is a tradeoff between safety and liveness and against our principle of preferring safety over liveness. Note that different validators don't have to agree on which validation sources they are ignoring.
-Next we compare the two approaches quantitatively with examples, and apply
-Theorem 8 of [Analysis of the XRP Ledger Consensus
-Protocol](https://arxiv.org/abs/1802.07242) paper:
+Next we compare the two approaches quantitatively with examples, and apply Theorem 8 of [Analysis of the XRP Ledger Consensus Protocol](https://arxiv.org/abs/1802.07242) paper:
-_XRP LCP guarantees fork safety if **Oi,j > nj / 2 +
-ni − qi + ti,j** for every pair of nodes
-Pi, Pj,_
+_XRP LCP guarantees fork safety if **Oi,j > nj / 2 + ni − qi + ti,j** for every pair of nodes Pi, Pj,_
-where _Oi,j_ is the overlapping requirement, nj and
-ni are UNL sizes, qi is the quorum size of Pi,
-_ti,j = min(ti, tj, Oi,j)_, and
-ti and tj are the number of faults can be tolerated by
-Pi and Pj.
+where _Oi,j_ is the overlapping requirement, nj and ni are UNL sizes, qi is the quorum size of Pi, _ti,j = min(ti, tj, Oi,j)_, and ti and tj are the number of faults can be tolerated by Pi and Pj.
-We denote _UNLi_ as _Pi's UNL_, and _|UNLi|_ as
-the size of _Pi's UNL_.
+We denote _UNLi_ as _Pi's UNL_, and _|UNLi|_ as the size of _Pi's UNL_.
-Assuming _|UNLi| = |UNLj|_, let's consider the following
-three cases:
+Assuming _|UNLi| = |UNLj|_, let's consider the following three cases:
-1. With 80% quorum and 20% faults, _Oi,j > 100% / 2 + 100% - 80% +
- 20% = 90%_. I.e. fork safety requires > 90% UNL overlaps. This is one of the
- results in the analysis paper.
+1. With 80% quorum and 20% faults, _Oi,j > 100% / 2 + 100% - 80% + 20% = 90%_. I.e. fork safety requires > 90% UNL overlaps. This is one of the results in the analysis paper.
-1. If the quorum is 60%, the relationship between the overlapping requirement
- and the faults that can be tolerated is _Oi,j > 90% +
- ti,j_. Under the same overlapping condition (i.e. 90%), to guarantee
- the fork safety, the network cannot tolerate any faults. So under the same
- overlapping condition, if the quorum is simply lowered, the network can tolerate
- fewer faults.
+1. If the quorum is 60%, the relationship between the overlapping requirement and the faults that can be tolerated is _Oi,j > 90% + ti,j_. Under the same overlapping condition (i.e. 90%), to guarantee the fork safety, the network cannot tolerate any faults. So under the same overlapping condition, if the quorum is simply lowered, the network can tolerate fewer faults.
-1. With the negative UNL approach, we want to argue that the inequation
- _Oi,j > nj / 2 + ni − qi +
- ti,j_ is always true to guarantee fork safety, while the negative UNL
- protocol runs, i.e. the effective quorum is lowered without weakening the
- network's fault tolerance. To make the discussion easier, we rewrite the
- inequation as _Oi,j > nj / 2 + (ni −
- qi) + min(ti, tj)_, where Oi,j is
- dropped from the definition of ti,j because _Oi,j >
- min(ti, tj)_ always holds under the parameters we will
- use. Assuming a validator V is added to the negative UNL, now let's consider the
- 4 cases:
+1. With the negative UNL approach, we want to argue that the inequation _Oi,j > nj / 2 + ni − qi + ti,j_ is always true to guarantee fork safety, while the negative UNL protocol runs, i.e. the effective quorum is lowered without weakening the network's fault tolerance. To make the discussion easier, we rewrite the inequation as _Oi,j > nj / 2 + (ni − qi) + min(ti, tj)_, where Oi,j is dropped from the definition of ti,j because _Oi,j > min(ti, tj)_ always holds under the parameters we will use. Assuming a validator V is added to the negative UNL, now let's consider the 4 cases:
1. V is not on UNLi nor UNLj
@@ -526,64 +309,35 @@ three cases:
Question: We have observed that occasionally a validator wanders off on its
own chain. How is this case handled by the negative UNL algorithm?
-Answer: The case that a validator wanders off on its own chain can be measured
-with the validations agreement. Because the validations by this validator must
-be different from other validators' validations of the same sequence numbers.
-When there are enough disagreed validations, other validators will vote this
-validator onto the negative UNL.
+Answer: The case that a validator wanders off on its own chain can be measured with the validations agreement. Because the validations by this validator must be different from other validators' validations of the same sequence numbers. When there are enough disagreed validations, other validators will vote this validator onto the negative UNL.
-In general by measuring the agreement of validations, we also measured the
-"sanity". If two validators have too many disagreements, one of them could be
-insane. When enough validators think a validator is insane, that validator is
-put on the negative UNL.
+In general by measuring the agreement of validations, we also measured the "sanity". If two validators have too many disagreements, one of them could be insane. When enough validators think a validator is insane, that validator is put on the negative UNL.
Question: Why would there be at most one disable UNLModify and one
re-enable UNLModify transaction per flag ledger?
-Answer: It is a design choice so that the effective UNL does not change too
-quickly. A typical targeted scenario is several validators go offline slowly
-during a long weekend. The current design can handle this kind of cases well
-without changing the effective UNL too quickly.
+Answer: It is a design choice so that the effective UNL does not change too quickly. A typical targeted scenario is several validators go offline slowly during a long weekend. The current design can handle this kind of cases well without changing the effective UNL too quickly.
## Appendix
### Confidence Test
-We will use two test networks, a single machine test network with multiple IP
-addresses and the QE test network with multiple machines. The single machine
-network will be used to test all the test cases and to debug. The QE network
-will be used after that. We want to see the test cases still pass with real
-network delay. A test case specifies:
+We will use two test networks, a single machine test network with multiple IP addresses and the QE test network with multiple machines. The single machine network will be used to test all the test cases and to debug. The QE network will be used after that. We want to see the test cases still pass with real network delay. A test case specifies:
1. a UNL with different number of validators for different test cases,
1. a network with zero or more non-validator nodes,
-1. a sequence of validator reliability change events (by killing/restarting
- nodes, or by running modified xrpld that does not send all validation
- messages),
+1. a sequence of validator reliability change events (by killing/restarting nodes, or by running modified xrpld that does not send all validation messages),
1. the correct outcomes.
-For all the test cases, the correct outcomes are verified by examining logs. We
-will grep the log to see if the correct negative UNLs are generated, and whether
-or not the network is making progress when it should be. The ripdtop tool will
-be helpful for monitoring validators' states and ledger progress. Some of the
-timing parameters of xrpld will be changed to have faster ledger time. Most if
-not all test cases do not need client transactions.
+For all the test cases, the correct outcomes are verified by examining logs. We will grep the log to see if the correct negative UNLs are generated, and whether or not the network is making progress when it should be. The ripdtop tool will be helpful for monitoring validators' states and ledger progress. Some of the timing parameters of xrpld will be changed to have faster ledger time. Most if not all test cases do not need client transactions.
For example, the test cases for the prototype:
1. A 10-validator UNL.
1. The network does not have other nodes.
-1. The validators will be started from the genesis. Once they start to produce
- ledgers, we kill five validators, one every flag ledger interval. Then we
- will restart them one by one.
-1. A sequence of events (or the lack of events) such as a killed validator is
- added to the negative UNL.
+1. The validators will be started from the genesis. Once they start to produce ledgers, we kill five validators, one every flag ledger interval. Then we will restart them one by one.
+1. A sequence of events (or the lack of events) such as a killed validator is added to the negative UNL.
#### Roads Not Taken: Test with Extended CSF
-We considered testing with the current unit test framework, specifically the
-[Consensus Simulation
-Framework](https://github.com/XRPLF/rippled/blob/develop/src/test/csf/README.md)
-(CSF). However, the CSF currently can only test the generic consensus algorithm
-as in the paper: [Analysis of the XRP Ledger Consensus
-Protocol](https://arxiv.org/abs/1802.07242).
+We considered testing with the current unit test framework, specifically the [Consensus Simulation Framework](https://github.com/XRPLF/rippled/blob/develop/src/test/csf/README.md) (CSF). However, the CSF currently can only test the generic consensus algorithm as in the paper: [Analysis of the XRP Ledger Consensus Protocol](https://arxiv.org/abs/1802.07242).
diff --git a/docs/0010-ledger-replay/README.md b/docs/0010-ledger-replay/README.md
index c82d9b1906..f8baf4b076 100644
--- a/docs/0010-ledger-replay/README.md
+++ b/docs/0010-ledger-replay/README.md
@@ -1,63 +1,20 @@
# Ledger Replay
-`LedgerReplayer` is a new `Stoppable` for replaying ledgers.
-Patterned after two other `Stoppable`s under `JobQueue`---`InboundLedgers`
-and `InboundTransactions`---it acts like a factory for creating
-state-machine workers, and a network message demultiplexer for those workers.
-Think of these workers like asynchronous functions.
-Like functions, they each take a set of parameters.
-The `Stoppable` memoizes these functions. It maintains a table for each
-worker type, mapping sets of arguments to the worker currently working
-on that argument set.
-Whenever the `Stoppable` is asked to construct a worker, it first searches its
-table to see if there is an existing worker with the same or overlapping
-argument set.
-If one exists, then it is used. If not, then a new one is created,
-initialized, and added to the table.
+`LedgerReplayer` is a new `Stoppable` for replaying ledgers. Patterned after two other `Stoppable`s under `JobQueue`---`InboundLedgers` and `InboundTransactions`---it acts like a factory for creating state-machine workers, and a network message demultiplexer for those workers. Think of these workers like asynchronous functions. Like functions, they each take a set of parameters. The `Stoppable` memoizes these functions. It maintains a table for each worker type, mapping sets of arguments to the worker currently working on that argument set. Whenever the `Stoppable` is asked to construct a worker, it first searches its table to see if there is an existing worker with the same or overlapping argument set. If one exists, then it is used. If not, then a new one is created, initialized, and added to the table.
-For `LedgerReplayer`, there are three worker types: `LedgerReplayTask`,
-`SkipListAcquire`, and `LedgerDeltaAcquire`.
-Each is derived from `TimeoutCounter` to give it a timeout.
-For `LedgerReplayTask`, the parameter set
-is {reason, finish ledger ID, number of ledgers}. For `SkipListAcquire` and
-`LedgerDeltaAcquire`, there is just one parameter: a ledger ID.
+For `LedgerReplayer`, there are three worker types: `LedgerReplayTask`, `SkipListAcquire`, and `LedgerDeltaAcquire`. Each is derived from `TimeoutCounter` to give it a timeout. For `LedgerReplayTask`, the parameter set is {reason, finish ledger ID, number of ledgers}. For `SkipListAcquire` and `LedgerDeltaAcquire`, there is just one parameter: a ledger ID.
-Each `Stoppable` has an entry point. For `LedgerReplayer`, it is `replay`.
-`replay` creates two workers: a `LedgerReplayTask` and a `SkipListAcquire`.
-`LedgerDeltaAcquire`s are created in the callback for when the skip list
-returns.
+Each `Stoppable` has an entry point. For `LedgerReplayer`, it is `replay`. `replay` creates two workers: a `LedgerReplayTask` and a `SkipListAcquire`. `LedgerDeltaAcquire`s are created in the callback for when the skip list returns.
-For `SkipListAcquire` and `LedgerDeltaAcquire`, initialization fires off the
-underlying asynchronous network request and starts the timeout. The argument
-set identifying the worker is included in the network request, and copied to
-the network response. `SkipListAcquire` sends a request for a proof path for
-the skip list of the desired ledger. `LedgerDeltaAcquire` sends a request for
-the transaction set of the desired ledger.
+For `SkipListAcquire` and `LedgerDeltaAcquire`, initialization fires off the underlying asynchronous network request and starts the timeout. The argument set identifying the worker is included in the network request, and copied to the network response. `SkipListAcquire` sends a request for a proof path for the skip list of the desired ledger. `LedgerDeltaAcquire` sends a request for the transaction set of the desired ledger.
-`LedgerReplayer` is also a network message demultiplexer.
-When a response arrives for a request that was sent by a `SkipListAcquire` or
-`LedgerDeltaAcquire` worker, the `Peer` object knows to send it to the
-`LedgerReplayer`, which looks up the worker waiting for that response based on
-the identifying argument set included in the response.
+`LedgerReplayer` is also a network message demultiplexer. When a response arrives for a request that was sent by a `SkipListAcquire` or `LedgerDeltaAcquire` worker, the `Peer` object knows to send it to the `LedgerReplayer`, which looks up the worker waiting for that response based on the identifying argument set included in the response.
-`LedgerReplayTask` may ask `InboundLedgers` to send requests to acquire
-the start ledger, but there is no way to attach a callback or be notified when
-the `InboundLedger` worker completes. All the responses for its messages will
-be directed to `InboundLedgers`, not `LedgerReplayer`. Instead,
-`LedgerReplayTask` checks whether the start ledger has arrived every time its
-timeout expires.
+`LedgerReplayTask` may ask `InboundLedgers` to send requests to acquire the start ledger, but there is no way to attach a callback or be notified when the `InboundLedger` worker completes. All the responses for its messages will be directed to `InboundLedgers`, not `LedgerReplayer`. Instead, `LedgerReplayTask` checks whether the start ledger has arrived every time its timeout expires.
-Like a promise, each worker keeps track of whether it is pending (`!isDone()`)
-or whether it has resolved successfully (`complete_ == true`) or unsuccessfully
-(`failed_ == true`). It will never exist in both resolved states at once, nor
-will it return to a pending state after reaching a resolved state.
+Like a promise, each worker keeps track of whether it is pending (`!isDone()`) or whether it has resolved successfully (`complete_ == true`) or unsuccessfully (`failed_ == true`). It will never exist in both resolved states at once, nor will it return to a pending state after reaching a resolved state.
-Like promises, some workers can accept continuations to be called when they
-reach a resolved state, or immediately if they are already resolved.
-`SkipListAcquire` and `LedgerDeltaAcquire` both accept continuations of a type
-specific to their payload, both via a method named `addDataCallback()`. Continuations
-cannot be removed explicitly, but they are held by `std::weak_ptr` so they can
-be removed implicitly.
+Like promises, some workers can accept continuations to be called when they reach a resolved state, or immediately if they are already resolved. `SkipListAcquire` and `LedgerDeltaAcquire` both accept continuations of a type specific to their payload, both via a method named `addDataCallback()`. Continuations cannot be removed explicitly, but they are held by `std::weak_ptr` so they can be removed implicitly.
`LedgerReplayTask` is simultaneously:
@@ -73,13 +30,7 @@ Each of these roles corresponds to different entry points:
1. the callback added to `LedgerDeltaAcquire`, which calls `deltaReady(...)` or `cancel()`
1. `onTimer()`
-Each of these entry points does something unique to that entry point. They
-either (a) transition `LedgerReplayTask` to a terminal failed resolved state
-(`cancel()` and `onTimer()`) or (b) try to make progress toward the successful
-resolved state. `init()` and `updateSkipList(...)` call `trigger()` while
-`deltaReady(...)` calls `tryAdvance()`. There's a similarity between this
-pattern and the way coroutines are implemented, where every yield saves the spot
-in the code where it left off and every resume jumps back to that spot.
+Each of these entry points does something unique to that entry point. They either (a) transition `LedgerReplayTask` to a terminal failed resolved state (`cancel()` and `onTimer()`) or (b) try to make progress toward the successful resolved state. `init()` and `updateSkipList(...)` call `trigger()` while `deltaReady(...)` calls `tryAdvance()`. There's a similarity between this pattern and the way coroutines are implemented, where every yield saves the spot in the code where it left off and every resume jumps back to that spot.
### Sequence Diagram
diff --git a/docs/CodingStyle.md b/docs/CodingStyle.md
index 2788f7b210..5f5ce63635 100644
--- a/docs/CodingStyle.md
+++ b/docs/CodingStyle.md
@@ -1,13 +1,10 @@
# Coding Standards
-Coding standards used here gradually evolve and propagate through
-code reviews. Some aspects are enforced more strictly than others.
+Coding standards used here gradually evolve and propagate through code reviews. Some aspects are enforced more strictly than others.
## Rules
-These rules only apply to our own code. We can't enforce any sort of
-style on the external repositories and libraries we include. The best
-guideline is to maintain the standards that are used in those libraries.
+These rules only apply to our own code. We can't enforce any sort of style on the external repositories and libraries we include. The best guideline is to maintain the standards that are used in those libraries.
- Tab inserts 4 spaces. No tab characters.
- Braces are indented in the [Allman style][1].
@@ -16,67 +13,37 @@ guideline is to maintain the standards that are used in those libraries.
## Guidelines
-If you want to do something contrary to these guidelines, understand
-why you're doing it. Think, use common sense, and consider that these
-changes will probably need to be maintained long after you've
-moved on to other projects.
+If you want to do something contrary to these guidelines, understand why you're doing it. Think, use common sense, and consider that these changes will probably need to be maintained long after you've moved on to other projects.
- Use white space and blank lines to guide the eye and keep your intent clear.
-- Put private data members at the top of a class, and the 6 public special
- members immediately after, in the following order:
+- Put private data members at the top of a class, and the 6 public special members immediately after, in the following order:
- Destructor
- Default constructor
- Copy constructor
- Copy assignment
- Move constructor
- Move assignment
-- Don't over-inline by defining large functions within the class
- declaration, not even for template classes.
+- Don't over-inline by defining large functions within the class declaration, not even for template classes.
## Formatting
-The goal of source code formatting should always be to make things as easy to
-read as possible. White space is used to guide the eye so that details are not
-overlooked. Blank lines are used to separate code into "paragraphs."
+The goal of source code formatting should always be to make things as easy to read as possible. White space is used to guide the eye so that details are not overlooked. Blank lines are used to separate code into "paragraphs."
-- Always place a space before and after all binary operators,
- especially assignments (`operator=`).
+- Always place a space before and after all binary operators, especially assignments (`operator=`).
- The `!` operator should be preceded by a space, but not followed by one.
- The `~` operator should be preceded by a space, but not followed by one.
-- The `++` and `--` operators should have no spaces between the operator and
- the operand.
+- The `++` and `--` operators should have no spaces between the operator and the operand.
- A space never appears before a comma, and always appears after a comma.
-- Don't put spaces after a parenthesis. A typical member function call might
- look like this: `foobar (1, 2, 3);`
+- Don't put spaces after a parenthesis. A typical member function call might look like this: `foobar (1, 2, 3);`
- In general, leave a blank line before an `if` statement.
- In general, leave a blank line after a closing brace `}`.
-- Do not place code on the same line as any opening or
- closing brace.
-- Do not write `if` statements all-on-one-line. The exception to this is when
- you've got a sequence of similar `if` statements, and are aligning them all
- vertically to highlight their similarities.
-- In an `if-else` statement, if you surround one half of the statement with
- braces, you also need to put braces around the other half, to match.
-- When writing a pointer type, use this spacing: `SomeObject* myObject`.
- Technically, a more correct spacing would be `SomeObject *myObject`, but
- it makes more sense for the asterisk to be grouped with the type name,
- since being a pointer is part of the type, not the variable name. The only
- time that this can lead to any problems is when you're declaring multiple
- pointers of the same type in the same statement - which leads on to the next
- rule:
-- When declaring multiple pointers, never do so in a single statement, e.g.
- `SomeObject* p1, *p2;` - instead, always split them out onto separate lines
- and write the type name again, to make it quite clear what's going on, and
- avoid the danger of missing out any vital asterisks.
-- The previous point also applies to references, so always put the `&` next to
- the type rather than the variable, e.g. `void foo (Thing const& thing)`. And
- don't put a space on both sides of the `*` or `&` - always put a space after
- it, but never before it.
-- The word `const` should be placed to the right of the thing that it modifies,
- for consistency. For example `int const` refers to an int which is const.
- `int const*` is a pointer to an int which is const. `int *const` is a const
- pointer to an int.
-- Always place a space in between the template angle brackets and the type
- name. Template code is already hard enough to read!
+- Do not place code on the same line as any opening or closing brace.
+- Do not write `if` statements all-on-one-line. The exception to this is when you've got a sequence of similar `if` statements, and are aligning them all vertically to highlight their similarities.
+- In an `if-else` statement, if you surround one half of the statement with braces, you also need to put braces around the other half, to match.
+- When writing a pointer type, use this spacing: `SomeObject* myObject`. Technically, a more correct spacing would be `SomeObject *myObject`, but it makes more sense for the asterisk to be grouped with the type name, since being a pointer is part of the type, not the variable name. The only time that this can lead to any problems is when you're declaring multiple pointers of the same type in the same statement - which leads on to the next rule:
+- When declaring multiple pointers, never do so in a single statement, e.g. `SomeObject* p1, *p2;` - instead, always split them out onto separate lines and write the type name again, to make it quite clear what's going on, and avoid the danger of missing out any vital asterisks.
+- The previous point also applies to references, so always put the `&` next to the type rather than the variable, e.g. `void foo (Thing const& thing)`. And don't put a space on both sides of the `*` or `&` - always put a space after it, but never before it.
+- The word `const` should be placed to the right of the thing that it modifies, for consistency. For example `int const` refers to an int which is const. `int const*` is a pointer to an int which is const. `int *const` is a const pointer to an int.
+- Always place a space in between the template angle brackets and the type name. Template code is already hard enough to read!
[1]: http://en.wikipedia.org/wiki/Indent_style#Allman_style
diff --git a/docs/HeapProfiling.md b/docs/HeapProfiling.md
index 6fcc9f9a67..6275c825dc 100644
--- a/docs/HeapProfiling.md
+++ b/docs/HeapProfiling.md
@@ -1,33 +1,18 @@
## Heap profiling of xrpld with jemalloc
-The jemalloc library provides a good API for doing heap analysis,
-including a mechanism to dump a description of the heap from within the
-running application via a function call. Details on how to perform this
-activity in general, as well as how to acquire the software, are available on
-the jemalloc site:
-[https://github.com/jemalloc/jemalloc/wiki/Use-Case:-Heap-Profiling](https://github.com/jemalloc/jemalloc/wiki/Use-Case:-Heap-Profiling)
+The jemalloc library provides a good API for doing heap analysis, including a mechanism to dump a description of the heap from within the running application via a function call. Details on how to perform this activity in general, as well as how to acquire the software, are available on the jemalloc site: [https://github.com/jemalloc/jemalloc/wiki/Use-Case:-Heap-Profiling](https://github.com/jemalloc/jemalloc/wiki/Use-Case:-Heap-Profiling)
-jemalloc is acquired separately from xrpld, and is not affiliated
-with Ripple Labs. If you compile and install jemalloc from the
-source release with default options, it will install the library and header
-under `/usr/local/lib` and `/usr/local/include`, respectively. Heap
-profiling has been tested with xrpld on a Linux platform. It should
-work on platforms on which both xrpld and jemalloc are available.
+jemalloc is acquired separately from xrpld, and is not affiliated with Ripple Labs. If you compile and install jemalloc from the source release with default options, it will install the library and header under `/usr/local/lib` and `/usr/local/include`, respectively. Heap profiling has been tested with xrpld on a Linux platform. It should work on platforms on which both xrpld and jemalloc are available.
-To link xrpld with jemalloc, the argument
-`profile-jemalloc=` is provided after the optional target.
-The `` argument should be the same as that of the
-`--prefix` parameter passed to the jemalloc configure script when building.
+To link xrpld with jemalloc, the argument `profile-jemalloc=` is provided after the optional target. The `` argument should be the same as that of the `--prefix` parameter passed to the jemalloc configure script when building.
## Examples:
-Build xrpld with jemalloc library under /usr/local/lib and
-header under /usr/local/include:
+Build xrpld with jemalloc library under /usr/local/lib and header under /usr/local/include:
$ scons profile-jemalloc=/usr/local
-Build xrpld using clang with the jemalloc library under /opt/local/lib
-and header under /opt/local/include:
+Build xrpld using clang with the jemalloc library under /opt/local/lib and header under /opt/local/include:
$ scons clang profile-jemalloc=/opt/local
@@ -35,10 +20,7 @@ and header under /opt/local/include:
## Using the jemalloc library from within the code
-The `profile-jemalloc` parameter enables a macro definition called
-`PROFILE_JEMALLOC`. Include the jemalloc header file as
-well as the api call(s) that you wish to make within preprocessor
-conditional groups, such as:
+The `profile-jemalloc` parameter enables a macro definition called `PROFILE_JEMALLOC`. Include the jemalloc header file as well as the api call(s) that you wish to make within preprocessor conditional groups, such as:
In global scope:
@@ -52,11 +34,6 @@ And later, within a function scope:
mallctl("prof.dump", NULL, NULL, NULL, 0);
#endif
-Fuller descriptions of how to acquire and use jemalloc's api to do memory
-analysis are available at the [jemalloc
-site.](http://www.canonware.com/jemalloc/)
+Fuller descriptions of how to acquire and use jemalloc's api to do memory analysis are available at the [jemalloc site.](http://www.canonware.com/jemalloc/)
-Linking against the jemalloc library will override
-the system's default `malloc()` and related functions with jemalloc's
-implementation. This is the case even if the code is not instrumented
-to use jemalloc's specific API.
+Linking against the jemalloc library will override the system's default `malloc()` and related functions with jemalloc's implementation. This is the case even if the code is not instrumented to use jemalloc's specific API.
diff --git a/docs/build/advanced_conan.md b/docs/build/advanced_conan.md
index 26b88ef186..6cafc7d2aa 100644
--- a/docs/build/advanced_conan.md
+++ b/docs/build/advanced_conan.md
@@ -4,34 +4,25 @@ This document provides advanced instructions for setting up and configuring Cona
## Custom profile
-If the default profile does not work for you and you do not yet have a Conan
-profile, you can create one by running:
+If the default profile does not work for you and you do not yet have a Conan profile, you can create one by running:
```bash
conan profile detect
```
-You may need to make changes to the profile to suit your environment. You can
-refer to the provided `conan/profiles/default` profile for inspiration, and you
-may also need to apply the required [tweaks](#conan-profile-tweaks) to this
-default profile.
+You may need to make changes to the profile to suit your environment. You can refer to the provided `conan/profiles/default` profile for inspiration, and you may also need to apply the required [tweaks](#conan-profile-tweaks) to this default profile.
## Conan lockfile
-To achieve reproducible dependencies, we use a [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html),
-which has to be updated every time dependencies change.
+To achieve reproducible dependencies, we use a [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html), which has to be updated every time dependencies change.
Please see the [instructions on how to regenerate the lockfile](../../conan/lockfile/README.md).
## Patched recipes
-Occasionally, we need patched recipes or recipes not present in Conan Center.
-We maintain a fork of the Conan Center Index
-[here](https://github.com/XRPLF/conan-center-index/) containing the modified and newly added recipes.
+Occasionally, we need patched recipes or recipes not present in Conan Center. We maintain a fork of the Conan Center Index [here](https://github.com/XRPLF/conan-center-index/) containing the modified and newly added recipes.
-To ensure our patched recipes are used, you must add our Conan remote at a
-higher index than the default Conan Center remote, so it is consulted first. You
-can do this by running:
+To ensure our patched recipes are used, you must add our Conan remote at a higher index than the default Conan Center remote, so it is consulted first. You can do this by running:
```bash
conan remote add --index 0 --force xrplf https://conan.xrplf.org/repository/conan/
@@ -61,16 +52,9 @@ git checkout master
cd ../../
```
-In the case we switch to a newer version of a dependency that still requires a
-patch or add a new dependency, it will be necessary for you to pull in the changes and re-export the
-updated dependencies with the newer version. However, if we switch to a newer
-version that no longer requires a patch, no action is required on your part, as
-the new recipe will be automatically pulled from the official Conan Center.
+In the case we switch to a newer version of a dependency that still requires a patch or add a new dependency, it will be necessary for you to pull in the changes and re-export the updated dependencies with the newer version. However, if we switch to a newer version that no longer requires a patch, no action is required on your part, as the new recipe will be automatically pulled from the official Conan Center.
-> [!NOTE]
-> You might need to add `--lockfile=""` to your `conan install` command
-> to avoid automatic use of the existing `conan.lock` file when you run
-> `conan export` manually on your machine
+> [!NOTE] You might need to add `--lockfile=""` to your `conan install` command to avoid automatic use of the existing `conan.lock` file when you run `conan export` manually on your machine
>
> This is not recommended though, as you might end up using different revisions of recipes.
@@ -88,8 +72,7 @@ Possible values are ['5.0', '5.1', '6.0', '6.1', '7.0', '7.3', '8.0', '8.1',
Read "http://docs.conan.io/2/knowledge/faq.html#error-invalid-setting"
```
-you need to create `$(conan config home)/settings_user.yml` file if it doesn't exist and add the required version number(s)
-to the `version` array specific for your compiler. For example:
+you need to create `$(conan config home)/settings_user.yml` file if it doesn't exist and add the required version number(s) to the `version` array specific for your compiler. For example:
```yaml
compiler:
@@ -99,13 +82,9 @@ compiler:
### Multiple compilers
-If you have multiple compilers installed, make sure to select the one to use in
-your default Conan configuration **before** running `conan profile detect`, by
-setting the `CC` and `CXX` environment variables.
+If you have multiple compilers installed, make sure to select the one to use in your default Conan configuration **before** running `conan profile detect`, by setting the `CC` and `CXX` environment variables.
-For example, if you are running MacOS and have [homebrew
-LLVM@18](https://formulae.brew.sh/formula/llvm@18), and want to use it as a
-compiler in the new Conan profile:
+For example, if you are running MacOS and have [homebrew LLVM@18](https://formulae.brew.sh/formula/llvm@18), and want to use it as a compiler in the new Conan profile:
```bash
export CC=$(brew --prefix llvm@18)/bin/clang
@@ -113,9 +92,7 @@ export CXX=$(brew --prefix llvm@18)/bin/clang++
conan profile detect
```
-You should also explicitly set the path to the compiler in the profile file,
-which helps to avoid errors when `CC` and/or `CXX` are set and disagree with the
-selected Conan profile. For example:
+You should also explicitly set the path to the compiler in the profile file, which helps to avoid errors when `CC` and/or `CXX` are set and disagree with the selected Conan profile. For example:
```text
[conf]
@@ -124,15 +101,11 @@ tools.build:compiler_executables={'c':'/usr/bin/gcc','cpp':'/usr/bin/g++'}
### Multiple profiles
-You can manage multiple Conan profiles in the directory
-`$(conan config home)/profiles`, for example renaming `default` to a different
-name and then creating a new `default` profile for a different compiler.
+You can manage multiple Conan profiles in the directory `$(conan config home)/profiles`, for example renaming `default` to a different name and then creating a new `default` profile for a different compiler.
### Select language
-The default profile created by Conan will typically select different C++ dialect
-than C++23 used by this project. You should set `23` in the profile line
-starting with `compiler.cppstd=`. For example:
+The default profile created by Conan will typically select different C++ dialect than C++23 used by this project. You should set `23` in the profile line starting with `compiler.cppstd=`. For example:
```bash
sed -i.bak -e 's|^compiler\.cppstd=.*$|compiler.cppstd=23|' $(conan config home)/profiles/default
@@ -140,10 +113,7 @@ sed -i.bak -e 's|^compiler\.cppstd=.*$|compiler.cppstd=23|' $(conan config home)
### Select standard library in Linux
-**Linux** developers will commonly have a default Conan [profile][] that
-compiles with GCC and links with libstdc++. If you are linking with libstdc++
-(see profile setting `compiler.libcxx`), then you will need to choose the
-`libstdc++11` ABI:
+**Linux** developers will commonly have a default Conan [profile][] that compiles with GCC and links with libstdc++. If you are linking with libstdc++ (see profile setting `compiler.libcxx`), then you will need to choose the `libstdc++11` ABI:
```bash
sed -i.bak -e 's|^compiler\.libcxx=.*$|compiler.libcxx=libstdc++11|' $(conan config home)/profiles/default
@@ -151,12 +121,9 @@ sed -i.bak -e 's|^compiler\.libcxx=.*$|compiler.libcxx=libstdc++11|' $(conan con
### Select architecture and runtime in Windows
-**Windows** developers may need to use the x64 native build tools. An easy way
-to do that is to run the shortcut "x64 Native Tools Command Prompt" for the
-version of Visual Studio that you have installed.
+**Windows** developers may need to use the x64 native build tools. An easy way to do that is to run the shortcut "x64 Native Tools Command Prompt" for the version of Visual Studio that you have installed.
-Windows developers must also build `xrpld` and its dependencies for the x64
-architecture:
+Windows developers must also build `xrpld` and its dependencies for the x64 architecture:
```bash
sed -i.bak -e 's|^arch=.*$|arch=x86_64|' $(conan config home)/profiles/default
@@ -175,10 +142,8 @@ If you want to experiment with a new package, follow these steps:
1. Search for the package on [Conan Center](https://conan.io/center/).
2. Modify [`conanfile.py`](../../conanfile.py):
- Add a version of the package to the `requires` property.
- - Change any default options for the package by adding them to the
- `default_options` property (with syntax `'$package:$option': $value`).
-3. Regenerate the [Conan lockfile](../../conan/lockfile/README.md) so the new
- dependency is captured:
+ - Change any default options for the package by adding them to the `default_options` property (with syntax `'$package:$option': $value`).
+3. Regenerate the [Conan lockfile](../../conan/lockfile/README.md) so the new dependency is captured:
```bash
./conan/lockfile/regenerate.sh
@@ -186,8 +151,7 @@ If you want to experiment with a new package, follow these steps:
4. Modify [`CMakeLists.txt`](../../CMakeLists.txt):
- Add a call to `find_package($package REQUIRED)`.
- - Link a library from the package to the target `xrpl_libs`
- (search for the existing call to `target_link_libraries(xrpl_libs INTERFACE ...)`).
+ - Link a library from the package to the target `xrpl_libs` (search for the existing call to `target_link_libraries(xrpl_libs INTERFACE ...)`).
5. Start coding! Don't forget to include whatever headers you need from the package.
[profile]: https://docs.conan.io/2/reference/config_files/profiles.html
diff --git a/docs/build/conan.md b/docs/build/conan.md
index 22c25a0bf9..b66da58a11 100644
--- a/docs/build/conan.md
+++ b/docs/build/conan.md
@@ -1,115 +1,44 @@
## A crash course in CMake and Conan
-To better understand how to use Conan,
-we should first understand _why_ we use Conan,
-and to understand that,
-we need to understand how we use CMake.
+To better understand how to use Conan, we should first understand _why_ we use Conan, and to understand that, we need to understand how we use CMake.
### CMake
-Technically, you don't need CMake to build this project.
-You could manually compile every translation unit into an object file,
-using the right compiler options,
-and then manually link all those objects together,
-using the right linker options.
-However, that is very tedious and error-prone,
-which is why we lean on tools like CMake.
+Technically, you don't need CMake to build this project. You could manually compile every translation unit into an object file, using the right compiler options, and then manually link all those objects together, using the right linker options. However, that is very tedious and error-prone, which is why we lean on tools like CMake.
-We have written CMake configuration files
-([`CMakeLists.txt`](./CMakeLists.txt) and friends)
-for this project so that CMake can be used to correctly compile and link
-all of the translation units in it.
-Or rather, CMake will generate files for a separate build system
-(e.g. Make, Ninja, Visual Studio, Xcode, etc.)
-that compile and link all of the translation units.
-Even then, CMake has parameters, some of which are platform-specific.
-In CMake's parlance, parameters are specially-named **variables** like
-[`CMAKE_BUILD_TYPE`][build_type] or
-[`CMAKE_MSVC_RUNTIME_LIBRARY`][runtime].
-Parameters include:
+We have written CMake configuration files ([`CMakeLists.txt`](./CMakeLists.txt) and friends) for this project so that CMake can be used to correctly compile and link all of the translation units in it. Or rather, CMake will generate files for a separate build system (e.g. Make, Ninja, Visual Studio, Xcode, etc.) that compile and link all of the translation units. Even then, CMake has parameters, some of which are platform-specific. In CMake's parlance, parameters are specially-named **variables** like [`CMAKE_BUILD_TYPE`][build_type] or [`CMAKE_MSVC_RUNTIME_LIBRARY`][runtime]. Parameters include:
- what build system to generate files for
- where to find the compiler and linker
- where to find dependencies, e.g. libraries and headers
-- how to link dependencies, e.g. any special compiler or linker flags that
- need to be used with them, including preprocessor definitions
-- how to compile translation units, e.g. with optimizations, debug symbols,
- position-independent code, etc.
+- how to link dependencies, e.g. any special compiler or linker flags that need to be used with them, including preprocessor definitions
+- how to compile translation units, e.g. with optimizations, debug symbols, position-independent code, etc.
- on Windows, which runtime library to link with
-For some of these parameters, like the build system and compiler,
-CMake goes through a complicated search process to choose default values.
-For others, like the dependencies,
-_we_ had written in the CMake configuration files of this project
-our own complicated process to choose defaults.
-For most developers, things "just worked"... until they didn't, and then
-you were left trying to debug one of these complicated processes, instead of
-choosing and manually passing the parameter values yourself.
+For some of these parameters, like the build system and compiler, CMake goes through a complicated search process to choose default values. For others, like the dependencies, _we_ had written in the CMake configuration files of this project our own complicated process to choose defaults. For most developers, things "just worked"... until they didn't, and then you were left trying to debug one of these complicated processes, instead of choosing and manually passing the parameter values yourself.
-You can pass every parameter to CMake on the command line,
-but writing out these parameters every time we want to configure CMake is
-a pain.
-Most humans prefer to put them into a configuration file, once, that
-CMake can read every time it is configured.
-For CMake, that file is a [toolchain file][toolchain].
+You can pass every parameter to CMake on the command line, but writing out these parameters every time we want to configure CMake is a pain. Most humans prefer to put them into a configuration file, once, that CMake can read every time it is configured. For CMake, that file is a [toolchain file][toolchain].
### Conan
-These next few paragraphs on Conan are going to read much like the ones above
-for CMake.
+These next few paragraphs on Conan are going to read much like the ones above for CMake.
-Technically, you don't need Conan to build this project.
-You could manually download, configure, build, and install all of the
-dependencies yourself, and then pass all of the parameters necessary for
-CMake to link to those dependencies.
-To guarantee ABI compatibility, you must be sure to use the same set of
-compiler and linker options for all dependencies _and_ this project.
-However, that is very tedious and error-prone, which is why we lean on tools
-like Conan.
+Technically, you don't need Conan to build this project. You could manually download, configure, build, and install all of the dependencies yourself, and then pass all of the parameters necessary for CMake to link to those dependencies. To guarantee ABI compatibility, you must be sure to use the same set of compiler and linker options for all dependencies _and_ this project. However, that is very tedious and error-prone, which is why we lean on tools like Conan.
-We have written a Conan configuration file ([`conanfile.py`](../../conanfile.py))
-so that Conan can be used to correctly download, configure, build, and install
-all of the dependencies for this project,
-using a single set of compiler and linker options for all of them.
-It generates files that contain almost all of the parameters that CMake
-expects.
-Those files include:
+We have written a Conan configuration file ([`conanfile.py`](../../conanfile.py)) so that Conan can be used to correctly download, configure, build, and install all of the dependencies for this project, using a single set of compiler and linker options for all of them. It generates files that contain almost all of the parameters that CMake expects. Those files include:
- A single toolchain file.
-- For every dependency, a CMake [package configuration file][pcf],
- [package version file][pvf], and for every build type, a package
- targets file.
- Together, these files implement version checking and define `IMPORTED`
- targets for the dependencies.
+- For every dependency, a CMake [package configuration file][pcf], [package version file][pvf], and for every build type, a package targets file. Together, these files implement version checking and define `IMPORTED` targets for the dependencies.
-The toolchain file itself amends the search path
-([`CMAKE_PREFIX_PATH`][prefix_path]) so that [`find_package()`][find_package]
-will [discover][search] the generated package configuration files.
+The toolchain file itself amends the search path ([`CMAKE_PREFIX_PATH`][prefix_path]) so that [`find_package()`][find_package] will [discover][search] the generated package configuration files.
-**Nearly all we must do to properly configure CMake is pass the toolchain
-file.**
-What CMake parameters are left out?
-You'll still need to pick a build system generator,
-and if you choose a single-configuration generator,
-you'll need to pass the `CMAKE_BUILD_TYPE`,
-which should match the `build_type` setting you gave to Conan.
+**Nearly all we must do to properly configure CMake is pass the toolchain file.** What CMake parameters are left out? You'll still need to pick a build system generator, and if you choose a single-configuration generator, you'll need to pass the `CMAKE_BUILD_TYPE`, which should match the `build_type` setting you gave to Conan.
-Even then, Conan has parameters, some of which are platform-specific.
-In Conan's parlance, parameters are either settings or options.
-**Settings** are shared by all packages, e.g. the build type.
-**Options** are specific to a given package, e.g. whether to build and link
-OpenSSL as a shared library.
+Even then, Conan has parameters, some of which are platform-specific. In Conan's parlance, parameters are either settings or options. **Settings** are shared by all packages, e.g. the build type. **Options** are specific to a given package, e.g. whether to build and link OpenSSL as a shared library.
-For settings, Conan goes through a complicated search process to choose
-defaults.
-For options, each package recipe defines its own defaults.
+For settings, Conan goes through a complicated search process to choose defaults. For options, each package recipe defines its own defaults.
-You can pass every parameter to Conan on the command line,
-but it is more convenient to put them in a configuration file, once, that
-Conan can read every time it is configured.
-For Conan, that file is a [profile][].
-**All we must do to properly configure Conan is edit and pass the profile.**
-By default, Conan will use the profile named "default".
+You can pass every parameter to Conan on the command line, but it is more convenient to put them in a configuration file, once, that Conan can read every time it is configured. For Conan, that file is a [profile][]. **All we must do to properly configure Conan is edit and pass the profile.** By default, Conan will use the profile named "default".
[build_type]: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
[find_package]: https://cmake.org/cmake/help/latest/command/find_package.html
diff --git a/docs/build/depend.md b/docs/build/depend.md
index f44519ddf9..ba69248ca0 100644
--- a/docs/build/depend.md
+++ b/docs/build/depend.md
@@ -1,12 +1,8 @@
-We recommend two different methods to depend on libxrpl in your own [CMake][]
-project.
-Both methods add a CMake library target named `xrpl::libxrpl`.
+We recommend two different methods to depend on libxrpl in your own [CMake][] project. Both methods add a CMake library target named `xrpl::libxrpl`.
## Conan requirement
-The first method adds libxrpl as a [Conan][] requirement.
-With this method, there is no need for a Git [submodule][].
-It is good for when you just need a dependency on libxrpl as-is.
+The first method adds libxrpl as a [Conan][] requirement. With this method, there is no need for a Git [submodule][]. It is good for when you just need a dependency on libxrpl as-is.
```
# This conanfile.txt is just an example.
@@ -49,16 +45,7 @@ cmake --build . --parallel
## CMake subdirectory
-The second method adds the [xrpld][] project as a CMake
-[subdirectory][add_subdirectory].
-This method works well when you keep the xrpld project as a Git
-[submodule][].
-It's good for when you want to make changes to libxrpl as part of your own
-project.
-Be careful, though.
-Your project will inherit all of the same CMake options,
-so watch out for name collisions.
-We still recommend using [Conan][] to download, build, and connect dependencies.
+The second method adds the [xrpld][] project as a CMake [subdirectory][add_subdirectory]. This method works well when you keep the xrpld project as a Git [submodule][]. It's good for when you want to make changes to libxrpl as part of your own project. Be careful, though. Your project will inherit all of the same CMake options, so watch out for name collisions. We still recommend using [Conan][] to download, build, and connect dependencies.
```
# Add the project as a Git submodule.
diff --git a/docs/build/environment.md b/docs/build/environment.md
index 51580b12a5..6b7ea66566 100644
--- a/docs/build/environment.md
+++ b/docs/build/environment.md
@@ -1,14 +1,10 @@
-Our [build instructions][BUILD.md] assume you have a C++ development
-environment complete with Git, Python, Conan, CMake, and a C++ compiler.
-This document explains how to set one up.
+Our [build instructions][BUILD.md] assume you have a C++ development environment complete with Git, Python, Conan, CMake, and a C++ compiler. This document explains how to set one up.
[BUILD.md]: ../../BUILD.md
## Tested compiler versions
-`xrpld` is built in the **C++23** dialect by default, so your toolchain has to
-support it — see [compiler support for C++23][cpp23-support].
-The versions currently tested in CI are:
+`xrpld` is built in the **C++23** dialect by default, so your toolchain has to support it — see [compiler support for C++23][cpp23-support]. The versions currently tested in CI are:
| Compiler | Version |
| ----------- | ------------------ |
@@ -21,16 +17,9 @@ LLVM tools (`clang-tidy` and `clang-format`) are also pinned to version 22.
### Older compilers
-Older compilers may fail to build the latest `develop` code: the codebase now
-relies on C++23 features and has been adjusted for `clang-tidy`.
-If the latest code doesn't build for you, update your build toolchain first.
+Older compilers may fail to build the latest `develop` code: the codebase now relies on C++23 features and has been adjusted for `clang-tidy`. If the latest code doesn't build for you, update your build toolchain first.
-If updating isn't an option for you, we do accept pull requests that fix builds
-on older compilers, as long as the change is small and doesn't make the code
-harder to read. What we can't promise is that older compilers will keep working:
-only the versions in the table above are tested in CI, and we won't hold back
-the use of C++23 features or add invasive workarounds to keep an untested
-compiler building. Treat support for anything outside the table as best-effort.
+If updating isn't an option for you, we do accept pull requests that fix builds on older compilers, as long as the change is small and doesn't make the code harder to read. What we can't promise is that older compilers will keep working: only the versions in the table above are tested in CI, and we won't hold back the use of C++23 features or add invasive workarounds to keep an untested compiler building. Treat support for anything outside the table as best-effort.
## Required tools
@@ -43,11 +32,9 @@ Besides a compiler, building `xrpld` requires:
| [Conan](https://conan.io/downloads.html) | 2.17 |
| [CMake](https://cmake.org/download/) | 3.16 |
-On Linux and macOS, the [Nix development shell](./nix.md) provides all of them
-(see below). On Windows they have to be installed manually.
+On Linux and macOS, the [Nix development shell](./nix.md) provides all of them (see below). On Windows they have to be installed manually.
-Building with `-Drust=ON` additionally requires a Rust toolchain, see
-[Rust](#rust). A default build does not, so it is not in the table above.
+Building with `-Drust=ON` additionally requires a Rust toolchain, see [Rust](#rust). A default build does not, so it is not in the table above.
Once they are in place, verify that everything is installed and runnable with:
@@ -57,38 +44,25 @@ Once they are in place, verify that everything is installed and runnable with:
## Linux and macOS
-The **recommended way** to get a development environment on Linux and macOS is
-the Nix development shell. It provides the exact tooling used in CI — `git`,
-`python`, `conan`, `cmake`, `clang-tidy`, `clang-format`, and everything else —
-with a single command and without installing anything system-wide:
+The **recommended way** to get a development environment on Linux and macOS is the Nix development shell. It provides the exact tooling used in CI — `git`, `python`, `conan`, `cmake`, `clang-tidy`, `clang-format`, and everything else — with a single command and without installing anything system-wide:
```bash
nix --experimental-features 'nix-command flakes' develop
```
-On **Linux**, Nix also provides the compiler (GCC); on **macOS**, it provides
-Clang. If you instead opt to use your system-wide Apple Clang (via
-`nix develop .#apple-clang`), you need to manage its version yourself (see
-below).
+On **Linux**, Nix also provides the compiler (GCC); on **macOS**, it provides Clang. If you instead opt to use your system-wide Apple Clang (via `nix develop .#apple-clang`), you need to manage its version yourself (see below).
-See [Using the Nix development shell](./nix.md) for installation and usage
-details, including how to select a different compiler and why we recommend Nix
-over a hand-maintained environment.
+See [Using the Nix development shell](./nix.md) for installation and usage details, including how to select a different compiler and why we recommend Nix over a hand-maintained environment.
### macOS: managing the Apple Clang version
-If you use your system-wide Apple Clang on macOS (via `nix develop .#apple-clang`),
-the compiler version is whatever your installed Xcode (or Command Line Tools)
-provides. The following command should return a version greater than or equal to
-the [tested one](#tested-compiler-versions):
+If you use your system-wide Apple Clang on macOS (via `nix develop .#apple-clang`), the compiler version is whatever your installed Xcode (or Command Line Tools) provides. The following command should return a version greater than or equal to the [tested one](#tested-compiler-versions):
```bash
clang --version
```
-If you develop other applications using Xcode, you might be consistently
-updating to the newest version of Apple Clang, which will likely cause issues
-building xrpld. You may want to install and pin a specific version of Xcode:
+If you develop other applications using Xcode, you might be consistently updating to the newest version of Apple Clang, which will likely cause issues building xrpld. You may want to install and pin a specific version of Xcode:
1. **Download Xcode**
- Visit [Apple Developer Downloads](https://developer.apple.com/download/more/)
@@ -114,45 +88,25 @@ building xrpld. You may want to install and pin a specific version of Xcode:
## Windows
-Nix is not available on Windows, so the required tools have to be installed
-manually:
+Nix is not available on Windows, so the required tools have to be installed manually:
-- [Visual Studio 2026](https://visualstudio.microsoft.com/) with the
- **"Desktop development with C++"** workload — this provides MSVC and the
- "x64 Native Tools Command Prompt". CI configures CMake with the
- `Visual Studio 18 2026` generator.
+- [Visual Studio 2026](https://visualstudio.microsoft.com/) with the **"Desktop development with C++"** workload — this provides MSVC and the "x64 Native Tools Command Prompt". CI configures CMake with the `Visual Studio 18 2026` generator.
- [Git for Windows](https://git-scm.com/download/win)
-- Python, Conan, and CMake, at the versions listed in
- [Required tools](#required-tools).
-- a [Rust toolchain](https://rustup.rs) — only needed to build with
- `-Drust=ON`, see [Rust](#rust)
+- Python, Conan, and CMake, at the versions listed in [Required tools](#required-tools).
+- a [Rust toolchain](https://rustup.rs) — only needed to build with `-Drust=ON`, see [Rust](#rust)
## Rust
-The repository contains a Rust workspace in [`crates/`](../../crates), whose
-crates are exposed to C++ through [cxx](https://cxx.rs) bindings. It is **not**
-part of a default build: the CMake `rust` option is OFF by default, and with it
-off no Rust toolchain is needed. It is only required when configuring with
-`-Drust=ON` (which is what CI does), see [Options](../../BUILD.md#options).
+The repository contains a Rust workspace in [`crates/`](../../crates), whose crates are exposed to C++ through [cxx](https://cxx.rs) bindings. It is **not** part of a default build: the CMake `rust` option is OFF by default, and with it off no Rust toolchain is needed. It is only required when configuring with `-Drust=ON` (which is what CI does), see [Options](../../BUILD.md#options).
-The toolchain (`cargo`, `rustc`) is pinned to the channel in
-[`rust-toolchain.toml`](../../rust-toolchain.toml) at the repository root. If
-you install Rust with [rustup](https://rustup.rs), that file is picked up
-automatically, and `cargo`/`rustc` in the repository will use the pinned
-version.
+The toolchain (`cargo`, `rustc`) is pinned to the channel in [`rust-toolchain.toml`](../../rust-toolchain.toml) at the repository root. If you install Rust with [rustup](https://rustup.rs), that file is picked up automatically, and `cargo`/`rustc` in the repository will use the pinned version.
-Everything else the Rust build needs on the CMake side comes from Conan along
-with the rest of the dependencies, so there is nothing further to install.
+Everything else the Rust build needs on the CMake side comes from Conan along with the rest of the dependencies, so there is nothing further to install.
## Clang-tidy
-`clang-tidy` is required to run static analysis checks locally (see
-[CONTRIBUTING.md](../../CONTRIBUTING.md)). It is not required to build the
-project. The version this project uses is listed in
-[Tested compiler versions](#tested-compiler-versions).
+`clang-tidy` is required to run static analysis checks locally (see [CONTRIBUTING.md](../../CONTRIBUTING.md)). It is not required to build the project. The version this project uses is listed in [Tested compiler versions](#tested-compiler-versions).
-On Linux and macOS, the [Nix development shell](./nix.md) provides that exact
-version out of the box — run it via `run-clang-tidy`. No separate installation
-is needed.
+On Linux and macOS, the [Nix development shell](./nix.md) provides that exact version out of the box — run it via `run-clang-tidy`. No separate installation is needed.
[cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23
diff --git a/docs/build/nix.md b/docs/build/nix.md
index 0b701b39f3..49f355dbb8 100644
--- a/docs/build/nix.md
+++ b/docs/build/nix.md
@@ -38,19 +38,10 @@ The first time you run this command, it will take a few minutes to download and
### Platform notes
-- **Linux**: `nix develop` gives you a shell with all the tooling necessary to develop xrpld
- and with the same GCC/glibc toolchain that Nix builds for CI.
- See [Choosing a different compiler](#choosing-a-different-compiler)
- for the custom-vs-plain toolchain trade-off.
-- **macOS**: `nix develop` gives you a full environment too, with Clang (and
- every other tool, including Conan) provided by Nix. To use your system-wide
- Apple Clang instead, enter `nix develop .#apple-clang`. Conan has no binary in
- the Nix cache for macOS, so it is built from source the first time you enter
- the shell, which makes the initial setup slower (this is handled
- automatically; see [`nix/devshell.nix`](../../nix/devshell.nix)).
+- **Linux**: `nix develop` gives you a shell with all the tooling necessary to develop xrpld and with the same GCC/glibc toolchain that Nix builds for CI. See [Choosing a different compiler](#choosing-a-different-compiler) for the custom-vs-plain toolchain trade-off.
+- **macOS**: `nix develop` gives you a full environment too, with Clang (and every other tool, including Conan) provided by Nix. To use your system-wide Apple Clang instead, enter `nix develop .#apple-clang`. Conan has no binary in the Nix cache for macOS, so it is built from source the first time you enter the shell, which makes the initial setup slower (this is handled automatically; see [`nix/devshell.nix`](../../nix/devshell.nix)).
-> [!TIP]
-> To avoid typing `--experimental-features 'nix-command flakes'` every time, you can permanently enable flakes by creating `~/.config/nix/nix.conf`:
+> [!TIP] To avoid typing `--experimental-features 'nix-command flakes'` every time, you can permanently enable flakes by creating `~/.config/nix/nix.conf`:
>
> ```bash
> mkdir -p ~/.config/nix
@@ -59,21 +50,13 @@ The first time you run this command, it will take a few minutes to download and
>
> After this, you can simply use `nix develop` instead.
-> [!NOTE]
-> The examples below assume you've enabled flakes in your config. If you haven't, add `--experimental-features 'nix-command flakes'` after each `nix` command.
+> [!NOTE] The examples below assume you've enabled flakes in your config. If you haven't, add `--experimental-features 'nix-command flakes'` after each `nix` command.
### Choosing a different compiler
A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#clang`.
-On Linux, `.#gcc` and `.#clang` provide the exact toolchain CI uses:
-the compiler (pinned in [`nix/packages.nix`](../../nix/packages.nix))
-rebuilt against the pinned custom glibc (see [`nix/linux.nix`](../../nix/linux.nix)).
-Building that toolchain the first time is slow unless it is fetched from a Nix binary cache.
-If you don't need the custom glibc, the Linux-only `.#gcc-plain` and `.#clang-plain`
-give you the stock nixpkgs compilers of the same versions.
-On macOS there is no custom glibc, so `.#gcc` and `.#clang` are already the plain nixpkgs toolchain,
-and the `-plain` variants do not exist.
+On Linux, `.#gcc` and `.#clang` provide the exact toolchain CI uses: the compiler (pinned in [`nix/packages.nix`](../../nix/packages.nix)) rebuilt against the pinned custom glibc (see [`nix/linux.nix`](../../nix/linux.nix)). Building that toolchain the first time is slow unless it is fetched from a Nix binary cache. If you don't need the custom glibc, the Linux-only `.#gcc-plain` and `.#clang-plain` give you the stock nixpkgs compilers of the same versions. On macOS there is no custom glibc, so `.#gcc` and `.#clang` are already the plain nixpkgs toolchain, and the `-plain` variants do not exist.
Use `nix flake show` to see all the available development shells.
@@ -111,8 +94,7 @@ nix develop -c fish
nix develop -c "$SHELL"
```
-> [!WARNING]
-> Your shell's interactive startup files (e.g. `config.fish`, `.zshrc`) may prepend other directories — most commonly Homebrew — to `$PATH`, which can shadow the tools provided by the Nix shell. After entering, verify that tools resolve into the Nix store:
+> [!WARNING] Your shell's interactive startup files (e.g. `config.fish`, `.zshrc`) may prepend other directories — most commonly Homebrew — to `$PATH`, which can shadow the tools provided by the Nix shell. After entering, verify that tools resolve into the Nix store:
>
> ```bash
> command -v cmake # should print a /nix/store/... path
@@ -124,80 +106,38 @@ nix develop -c "$SHELL"
Once inside the Nix development shell, follow the standard [build instructions](../../BUILD.md#steps). The Nix shell provides all necessary tools (CMake, Ninja, Conan, etc.).
-Coverage builds (`-Dcoverage=ON`) work in the `gcc` shell (and `gcc-plain` on Linux):
-each ships a `gcov` matching its compiler, since Nix's cc-wrapper does not expose one.
-The `clang` shells do not include `llvm-cov`, so use a `gcc` shell for coverage.
+Coverage builds (`-Dcoverage=ON`) work in the `gcc` shell (and `gcc-plain` on Linux): each ships a `gcov` matching its compiler, since Nix's cc-wrapper does not expose one. The `clang` shells do not include `llvm-cov`, so use a `gcc` shell for coverage.
-Builds of the Rust crates (`-Drust=ON`) also work out of the box: every shell
-provides the Rust toolchain pinned in
-[`rust-toolchain.toml`](../../rust-toolchain.toml) (see
-[Rust](./environment.md#rust)), plus the `cargo-audit`, `cargo-llvm-cov` and
-`cargo-nextest` plugins.
+Builds of the Rust crates (`-Drust=ON`) also work out of the box: every shell provides the Rust toolchain pinned in [`rust-toolchain.toml`](../../rust-toolchain.toml) (see [Rust](./environment.md#rust)), plus the `cargo-audit`, `cargo-llvm-cov` and `cargo-nextest` plugins.
## Conan configuration
-The shell runs [`conan/init.sh`](../../conan/init.sh) on entry, so
-[Set Up Conan](../../BUILD.md#set-up-conan) is already done for you. It installs
-into the shell's own Conan home: `CONAN_HOME=~/.conan2-nix`.
+The shell runs [`conan/init.sh`](../../conan/init.sh) on entry, so [Set Up Conan](../../BUILD.md#set-up-conan) is already done for you. It installs into the shell's own Conan home: `CONAN_HOME=~/.conan2-nix`.
### Prebuilt packages
-On **Linux**, the binaries on the `xrplf` remote are built in this same Nix
-environment — CI runs in Docker images that bundle the dev shell's toolchain (see
-[`nix/docker`](../../nix/docker)) — so `.#gcc` and `.#clang` can reuse them. The
-`-plain` shells do not match that toolchain's glibc, so binaries from the remote
-are not a reliable match there.
+On **Linux**, the binaries on the `xrplf` remote are built in this same Nix environment — CI runs in Docker images that bundle the dev shell's toolchain (see [`nix/docker`](../../nix/docker)) — so `.#gcc` and `.#clang` can reuse them. The `-plain` shells do not match that toolchain's glibc, so binaries from the remote are not a reliable match there.
-On **macOS**, CI also builds in this Nix environment, in Debug and Release (the
-`macos-arm64-*-nix` configurations — Debug because the profile defaults to it).
-The Nix build resolves to `compiler=clang`, so it gets its own package IDs,
-separate from the Apple Clang ones. The
-[dependency upload](../../.github/workflows/upload-conan-deps.yml) publishes them
-on pushes to `develop` and on manual runs — its nightly run rebuilds everything
-from source but uploads nothing — so once a set has been published `nix develop`
-can reuse it instead of compiling every dependency locally. These configurations
-run outside the reduced pull-request matrix, so label a PR `Full CI build` when it
-touches `flake.lock` or `nix/`.
+On **macOS**, CI also builds in this Nix environment, in Debug and Release (the `macos-arm64-*-nix` configurations — Debug because the profile defaults to it). The Nix build resolves to `compiler=clang`, so it gets its own package IDs, separate from the Apple Clang ones. The [dependency upload](../../.github/workflows/upload-conan-deps.yml) publishes them on pushes to `develop` and on manual runs — its nightly run rebuilds everything from source but uploads nothing — so once a set has been published `nix develop` can reuse it instead of compiling every dependency locally. These configurations run outside the reduced pull-request matrix, so label a PR `Full CI build` when it touches `flake.lock` or `nix/`.
-To compile everything from source, add `--build '*'` to the `conan install`
-command.
+To compile everything from source, add `--build '*'` to the `conan install` command.
### Why the nixpkgs revision is not part of the package ID
-A Conan package ID records the compiler and its major version, but nothing about
-the nixpkgs revision the toolchain came from — and `flake.lock` moves far more
-often than the toolchain meaningfully changes, so folding it in would rebuild
-every dependency on every bump for nothing.
+A Conan package ID records the compiler and its major version, but nothing about the nixpkgs revision the toolchain came from — and `flake.lock` moves far more often than the toolchain meaningfully changes, so folding it in would rebuild every dependency on every bump for nothing.
-That is safe as long as no cached artifact resolves a `/nix/store` path at run
-time, because store paths change on every update and the old ones disappear with
-`nix-collect-garbage`. With the `clang` toolchain macOS CI and the dev shell use,
-they do not: it links against `/usr/lib/libc++` and `/usr/lib/libSystem`, and
-store paths reach the `.a` files only through debug info, which nothing resolves
-at link or run time.
+That is safe as long as no cached artifact resolves a `/nix/store` path at run time, because store paths change on every update and the old ones disappear with `nix-collect-garbage`. With the `clang` toolchain macOS CI and the dev shell use, they do not: it links against `/usr/lib/libc++` and `/usr/lib/libSystem`, and store paths reach the `.a` files only through debug info, which nothing resolves at link or run time.
-> [!WARNING]
-> This does not hold for `nix develop .#gcc` on macOS. There is no system
-> libstdc++, so GCC links its own from the store and every binary keeps a
-> `/nix/store` reference. That shell is fine for tooling, but it is not a build
-> configuration CI covers, and no dependency binaries are published for it.
+> [!WARNING] This does not hold for `nix develop .#gcc` on macOS. There is no system libstdc++, so GCC links its own from the store and every binary keeps a `/nix/store` reference. That shell is fine for tooling, but it is not a build configuration CI covers, and no dependency binaries are published for it.
-This is checked rather than assumed.
-[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) takes one file
-or directory and fails if a binary under it resolves a store path at run time.
-CI runs it over the build output and the Conan cache, and again in the upload job
-before anything is published. You can run it yourself:
+This is checked rather than assumed. [`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) takes one file or directory and fails if a binary under it resolves a store path at run time. CI runs it over the build output and the Conan cache, and again in the upload job before anything is published. You can run it yourself:
```bash
bin/check-nix-store-refs.sh build
bin/check-nix-store-refs.sh ~/.conan2-nix
```
-It works on Linux too, but asserts something narrower there: the toolchain always
-writes the store into `PT_INTERP` and `RUNPATH`, and CI builds inside an image
-whose store is fixed for its lifetime, so that is fine. Only the binaries
-[`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake) retargets to the
-system loader have to be clean, and those are what CI checks:
+It works on Linux too, but asserts something narrower there: the toolchain always writes the store into `PT_INTERP` and `RUNPATH`, and CI builds inside an image whose store is fixed for its lifetime, so that is fine. Only the binaries [`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake) retargets to the system loader have to be clean, and those are what CI checks:
```bash
bin/check-nix-store-refs.sh build/xrpld
@@ -205,22 +145,11 @@ bin/check-nix-store-refs.sh build/xrpld
### The libresolv stub
-This is not hypothetical: `xrpld` used to be caught by it. The c-ares package
-tells the linker to pass `-lresolv`, and nixpkgs keeps `libresolv` out of the
-macOS SDK and ships it as an ordinary store dylib — so every Nix-built `xrpld`
-recorded a `/nix/store/…-libresolv-93/lib/libresolv.9.dylib` load command and
-stopped running once that path was collected. Nothing in the link uses a single
-symbol from it.
+This is not hypothetical: `xrpld` used to be caught by it. The c-ares package tells the linker to pass `-lresolv`, and nixpkgs keeps `libresolv` out of the macOS SDK and ships it as an ordinary store dylib — so every Nix-built `xrpld` recorded a `/nix/store/…-libresolv-93/lib/libresolv.9.dylib` load command and stopped running once that path was collected. Nothing in the link uses a single symbol from it.
-Both environments now put a stub on the linker search path
-(`libresolvSystemStub` in [`nix/darwin.nix`](../../nix/darwin.nix)): the
-same library with its install name set to `/usr/lib/libresolv.9.dylib`, which is
-exactly the load command the Apple Clang build records.
+Both environments now put a stub on the linker search path (`libresolvSystemStub` in [`nix/darwin.nix`](../../nix/darwin.nix)): the same library with its install name set to `/usr/lib/libresolv.9.dylib`, which is exactly the load command the Apple Clang build records.
-Package IDs did not change, so Conan keeps serving anything built before the
-stub landed. If a binary fails to start with `Library not loaded: /nix/store/…`,
-see [that entry](./nix_troubleshooting.md#library-not-loaded-nixstore-from-a-binary-that-used-to-work)
-in the troubleshooting guide.
+Package IDs did not change, so Conan keeps serving anything built before the stub landed. If a binary fails to start with `Library not loaded: /nix/store/…`, see [that entry](./nix_troubleshooting.md#library-not-loaded-nixstore-from-a-binary-that-used-to-work) in the troubleshooting guide.
## Automatic Activation with direnv
@@ -233,8 +162,7 @@ The repository already ships an `.envrc` at its root that activates the Nix flak
1. [Install direnv](https://direnv.net/docs/installation.html) and [hook it into your shell](https://direnv.net/docs/hook.html) (bash, zsh, fish, …). Installing [nix-direnv](https://github.com/nix-community/nix-direnv) as well is recommended: it caches the shell so that activation is near-instant after the first run.
2. Run `direnv allow` once in the repository root. direnv will then load (and reload) the Nix development shell automatically whenever you enter the directory.
-> [!NOTE]
-> direnv only caches the `.direnv` directory (already listed in `.gitignore`); no other repository files are affected.
+> [!NOTE] direnv only caches the `.direnv` directory (already listed in `.gitignore`); no other repository files are affected.
## Updating `flake.lock` file
@@ -242,13 +170,8 @@ To update `flake.lock` to the latest revision use `nix flake update` command.
## Tooling snapshots
-The tool versions in each Nix environment are recorded in
-[`nix/check-tools/`](../../nix/check-tools) and verified by CI. If you change the
-environment (bump the CI image tag, update `flake.lock`, or edit the tool list in
-`bin/check-tools.sh`), CI fails until you regenerate and commit the affected
-snapshot — see [`nix/check-tools/README.md`](../../nix/check-tools/README.md).
+The tool versions in each Nix environment are recorded in [`nix/check-tools/`](../../nix/check-tools) and verified by CI. If you change the environment (bump the CI image tag, update `flake.lock`, or edit the tool list in `bin/check-tools.sh`), CI fails until you regenerate and commit the affected snapshot — see [`nix/check-tools/README.md`](../../nix/check-tools/README.md).
## Troubleshooting
-See [Troubleshooting Nix problems](./nix_troubleshooting.md) for common issues,
-such as `nix develop` failing inside Git worktrees.
+See [Troubleshooting Nix problems](./nix_troubleshooting.md) for common issues, such as `nix develop` failing inside Git worktrees.
diff --git a/docs/build/nix_troubleshooting.md b/docs/build/nix_troubleshooting.md
index 49088ab6b4..59fa44eb6e 100644
--- a/docs/build/nix_troubleshooting.md
+++ b/docs/build/nix_troubleshooting.md
@@ -1,7 +1,6 @@
# Troubleshooting Nix problems
-Common issues encountered when using the [Nix development shell](./nix.md), and
-how to resolve them.
+Common issues encountered when using the [Nix development shell](./nix.md), and how to resolve them.
## `command not found: nix` after a macOS update
@@ -12,8 +11,7 @@ $ nix develop
zsh: command not found: nix
```
-then Nix is almost certainly still installed — only the shell hook that puts it
-on your `PATH` is gone. Confirm that first:
+then Nix is almost certainly still installed — only the shell hook that puts it on your `PATH` is gone. Confirm that first:
```bash
ls -l /nix/var/nix/profiles/default/bin/nix
@@ -23,8 +21,7 @@ If that exists, the installation is fine and this is purely a `PATH` problem.
### Why it happens
-The installer does not touch your dotfiles. Instead it sources a setup script
-from the Nix store by editing **system-wide** rc files:
+The installer does not touch your dotfiles. Instead it sources a setup script from the Nix store by editing **system-wide** rc files:
| Shell | File the installer edits |
| ----- | ------------------------------------- |
@@ -32,17 +29,13 @@ from the Nix store by editing **system-wide** rc files:
| zsh | `/etc/zshrc` |
| fish | `$__fish_sysconf_dir/conf.d/nix.fish` |
-macOS manages `/etc/zshrc`, so an OS update can replace it with the vendor copy
-and silently drop the Nix block. `/etc/bashrc` and the fish file usually survive,
-which is why the breakage often shows up in zsh only. You can verify this by
-diffing against the backup the installer left behind:
+macOS manages `/etc/zshrc`, so an OS update can replace it with the vendor copy and silently drop the Nix block. `/etc/bashrc` and the fish file usually survive, which is why the breakage often shows up in zsh only. You can verify this by diffing against the backup the installer left behind:
```bash
diff /etc/zshrc /etc/zshrc.backup-before-nix
```
-If they are identical, the Nix snippet was wiped. This is upstream issue
-[NixOS/nix#3616](https://github.com/NixOS/nix/issues/3616).
+If they are identical, the Nix snippet was wiped. This is upstream issue [NixOS/nix#3616](https://github.com/NixOS/nix/issues/3616).
### Fix
@@ -52,8 +45,7 @@ To unblock the current shell:
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
```
-For a permanent fix, add the snippet to your **user** rc file rather than
-restoring `/etc/zshrc` — user dotfiles are not clobbered by OS updates:
+For a permanent fix, add the snippet to your **user** rc file rather than restoring `/etc/zshrc` — user dotfiles are not clobbered by OS updates:
```bash
cat >>~/.zshrc <<'EOF'
@@ -66,14 +58,9 @@ fi
EOF
```
-The scripts guard against double-sourcing via `__ETC_PROFILE_NIX_SOURCED`, so
-this is safe even if a system-wide hook is later restored.
+The scripts guard against double-sourcing via `__ETC_PROFILE_NIX_SOURCED`, so this is safe even if a system-wide hook is later restored.
-> [!NOTE]
-> `/etc/zshrc` and `~/.zshrc` are only read by **interactive** zsh. If the
-> snippet is present but `zsh -c '…'`, a script, or an IDE terminal still can't
-> find `nix`, that shell is non-interactive — put the snippet in `~/.zshenv`
-> instead.
+> [!NOTE] `/etc/zshrc` and `~/.zshrc` are only read by **interactive** zsh. If the snippet is present but `zsh -c '…'`, a script, or an IDE terminal still can't find `nix`, that shell is non-interactive — put the snippet in `~/.zshenv` instead.
## Git worktrees
@@ -86,56 +73,35 @@ error:
error: opening Git repository "/path/to/rippled": unsupported extension name extensions.relativeworktrees (libgit2 error code = 6)
```
-then your Nix is linked against a libgit2 older than **1.9.4**. Git 2.48+ writes
-the `extensions.relativeWorktrees` config entry when a worktree is created with
-relative paths (`git worktree add --relative-paths`, or with
-`worktree.useRelativePaths=true`), and older libgit2 versions refuse to open a
-repository that uses it. Nix uses libgit2 to read the flake, so evaluation
-fails.
+then your Nix is linked against a libgit2 older than **1.9.4**. Git 2.48+ writes the `extensions.relativeWorktrees` config entry when a worktree is created with relative paths (`git worktree add --relative-paths`, or with `worktree.useRelativePaths=true`), and older libgit2 versions refuse to open a repository that uses it. Nix uses libgit2 to read the flake, so evaluation fails.
-> [!IMPORTANT]
-> This entry is written to the **shared** repository config, so once any
-> relative worktree exists, `nix develop` fails in the main checkout too — not
-> just inside the worktree.
+> [!IMPORTANT] This entry is written to the **shared** repository config, so once any relative worktree exists, `nix develop` fails in the main checkout too — not just inside the worktree.
### Workarounds
These work today, with any Nix version:
-- bypass libgit2 with a `path:` flakeref: `nix develop "path:$PWD"`
- (note: this copies the working tree to the store and ignores `.gitignore`); or
+- bypass libgit2 with a `path:` flakeref: `nix develop "path:$PWD"` (note: this copies the working tree to the store and ignores `.gitignore`); or
- create worktrees with absolute paths (omit `--relative-paths`); or
-- clear the extension if you don't need relative worktrees:
- `git config --unset extensions.relativeWorktrees`.
+- clear the extension if you don't need relative worktrees: `git config --unset extensions.relativeWorktrees`.
### Permanent fix
-The fix is in [libgit2 1.9.4](https://github.com/libgit2/libgit2/releases/tag/v1.9.4),
-so the real solution is a Nix that links against libgit2 `1.9.4` or newer. Check
-which version yours links against:
+The fix is in [libgit2 1.9.4](https://github.com/libgit2/libgit2/releases/tag/v1.9.4), so the real solution is a Nix that links against libgit2 `1.9.4` or newer. Check which version yours links against:
```bash
nix-store -qR "$(readlink -f "$(command -v nix)")" | grep libgit2
```
-> [!WARNING]
-> `nix upgrade-nix` does **not** help yet. It installs the build from the
-> official [`nix-fallback-paths`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/installer/tools/nix-fallback-paths.nix),
-> which is still linked against libgit2 `1.9.2` — there is no new upstream Nix
-> release with the fix. (On some systems that build is even the exact store path
-> you already have, making the upgrade a no-op.)
+> [!WARNING] `nix upgrade-nix` does **not** help yet. It installs the build from the official [`nix-fallback-paths`](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/installer/tools/nix-fallback-paths.nix), which is still linked against libgit2 `1.9.2` — there is no new upstream Nix release with the fix. (On some systems that build is even the exact store path you already have, making the upgrade a no-op.)
-nixpkgs has already rebuilt Nix against the fixed libgit2 (e.g. `nix-2.34.7+1`),
-so the cleanest path is to reinstall Nix using your usual installation method
-once it picks up that rebuild, then re-run the `grep libgit2` check above to
-confirm it reports `1.9.4` or newer.
+nixpkgs has already rebuilt Nix against the fixed libgit2 (e.g. `nix-2.34.7+1`), so the cleanest path is to reinstall Nix using your usual installation method once it picks up that rebuild, then re-run the `grep libgit2` check above to confirm it reports `1.9.4` or newer.
Until then, prefer the workarounds above.
## `wint_t` / `uint32_t` errors from the Nix libc++ headers
-A build that mixes the Nix toolchain with the system SDK fails in libc++ itself,
-with errors that look nothing like your code:
+A build that mixes the Nix toolchain with the system SDK fails in libc++ itself, with errors that look nothing like your code:
```
/nix/store/...-libcxx-.../include/c++/v1/cwchar:136:9: error: target of using declaration conflicts with declaration already in scope
@@ -145,41 +111,31 @@ with errors that look nothing like your code:
error: use of undeclared identifier 'UINT32_C'
```
-The give-away is the second path: Nix's libc++ headers are being combined with
-the **Xcode Command Line Tools** SDK instead of the Nix one.
+The give-away is the second path: Nix's libc++ headers are being combined with the **Xcode Command Line Tools** SDK instead of the Nix one.
### Why it happens
-`SDKROOT` and `DEVELOPER_DIR` are what point the toolchain at the Nix SDK, and
-they are not baked into the compiler — a dev shell gets them from the
-`apple-sdk` setup hook. CMake, finding neither, asks `xcrun`, which answers with
-the system SDK. Nix's `libc++` and Apple's headers then declare the same types
-twice.
+`SDKROOT` and `DEVELOPER_DIR` are what point the toolchain at the Nix SDK, and they are not baked into the compiler — a dev shell gets them from the `apple-sdk` setup hook. CMake, finding neither, asks `xcrun`, which answers with the system SDK. Nix's `libc++` and Apple's headers then declare the same types twice.
### Fix
-Run the build from inside the dev shell (`nix develop`), or from an environment
-that exports both variables. To confirm which SDK a configured build is using:
+Run the build from inside the dev shell (`nix develop`), or from an environment that exports both variables. To confirm which SDK a configured build is using:
```bash
grep -o '\-isysroot [^ ]*' build/compile_commands.json | sort -u
```
-It should print a `/nix/store/...-apple-sdk-*` path. If it prints
-`/Library/Developer/CommandLineTools/...`, re-configure from within the shell —
-CMake caches the sysroot, so an existing `build/` directory keeps the wrong one.
+It should print a `/nix/store/...-apple-sdk-*` path. If it prints `/Library/Developer/CommandLineTools/...`, re-configure from within the shell — CMake caches the sysroot, so an existing `build/` directory keeps the wrong one.
## `Library not loaded: /nix/store/…` from a binary that used to work
-A binary stops starting after a `nix flake update`, or after
-`nix-collect-garbage` removes the paths the previous toolchain used:
+A binary stops starting after a `nix flake update`, or after `nix-collect-garbage` removes the paths the previous toolchain used:
```
dyld[57271]: Library not loaded: /nix/store/…-libresolv-93/lib/libresolv.9.dylib
```
-[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) finds the same
-thing without having to run anything, and names the file:
+[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) finds the same thing without having to run anything, and names the file:
```
$ bin/check-nix-store-refs.sh ~/.conan2-nix
@@ -189,9 +145,7 @@ $ bin/check-nix-store-refs.sh ~/.conan2-nix
/Users/you/.conan2-nix: checked 135, skipped 2495, 1 with Nix store references.
```
-Conan's cache folders are named after a truncated package name plus a hash, so
-ask Conan which package the offending one belongs to — pass the folder holding
-the hash, not the file itself:
+Conan's cache folders are named after a truncated package name plus a hash, so ask Conan which package the offending one belongs to — pass the folder holding the hash, not the file itself:
```
$ conan cache ref ~/.conan2-nix/p/b/c-area24ded30c388c
@@ -200,17 +154,9 @@ c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650:dab5992496abe6d219defb7986ecbf367
### Why it happens
-The binary records a store path that no longer exists. Nothing we build should:
-see [Prebuilt packages](./nix.md#prebuilt-packages) for why, and
-`libresolvSystemStub` in [`nix/darwin.nix`](../../nix/darwin.nix) for the one
-dependency that needed help to comply.
+The binary records a store path that no longer exists. Nothing we build should: see [Prebuilt packages](./nix.md#prebuilt-packages) for why, and `libresolvSystemStub` in [`nix/darwin.nix`](../../nix/darwin.nix) for the one dependency that needed help to comply.
-A Conan package ID does not encode the nixpkgs revision, so a package built
-before that stub existed stays in your local cache and keeps being reused. The
-dev shell is also what tends to produce one: it is a slightly _less_ isolated
-build environment than CI's, because `mkShell` puts every tool's headers and
-libraries on the compiler's search path — which is how c-ares found the Nix
-`libresolv` in the first place.
+A Conan package ID does not encode the nixpkgs revision, so a package built before that stub existed stays in your local cache and keeps being reused. The dev shell is also what tends to produce one: it is a slightly _less_ isolated build environment than CI's, because `mkShell` puts every tool's headers and libraries on the compiler's search path — which is how c-ares found the Nix `libresolv` in the first place.
### Fix
diff --git a/docs/build/sanitizers.md b/docs/build/sanitizers.md
index 6e7284fd06..efc3f03bb9 100644
--- a/docs/build/sanitizers.md
+++ b/docs/build/sanitizers.md
@@ -1,11 +1,8 @@
# Sanitizer Configuration for Xrpld
-This document explains how to properly configure and run sanitizers (`AddressSanitizer`, `UndefinedBehaviorSanitizer`, `ThreadSanitizer`) with the xrpld project.
-Corresponding suppression files are located in the `sanitizers/suppressions` directory.
+This document explains how to properly configure and run sanitizers (`AddressSanitizer`, `UndefinedBehaviorSanitizer`, `ThreadSanitizer`) with the xrpld project. Corresponding suppression files are located in the `sanitizers/suppressions` directory.
-> [!CAUTION]
-> Do not mix Address and Thread sanitizers - they are incompatible.
-> Also, we don't yet support MSVC sanitizers, so this is only for Clang/GCC builds.
+> [!CAUTION] Do not mix Address and Thread sanitizers - they are incompatible. Also, we don't yet support MSVC sanitizers, so this is only for Clang/GCC builds.
- [Sanitizer Configuration for Xrpld](#sanitizer-configuration-for-xrpld)
- [Building with Sanitizers](#building-with-sanitizers)
@@ -35,12 +32,10 @@ Corresponding suppression files are located in the `sanitizers/suppressions` dir
Follow the same instructions as mentioned in [BUILD.md](../../BUILD.md) but with the following changes:
1. Make sure you have a clean build directory.
-2. Set the `SANITIZERS` environment variable before calling `conan install`. Only set it once.
- Example: `export SANITIZERS=address,undefinedbehavior`
+2. Set the `SANITIZERS` environment variable before calling `conan install`. Only set it once. Example: `export SANITIZERS=address,undefinedbehavior`
3. Use `--profile:all sanitizers` with Conan to build dependencies with sanitizer instrumentation.
- > [!NOTE]
- > Building with sanitizer-instrumented dependencies is slower but produces fewer false positives.
+ > [!NOTE] Building with sanitizer-instrumented dependencies is slower but produces fewer false positives.
4. Set `ASAN_OPTIONS`, `LSAN_OPTIONS`, `UBSAN_OPTIONS` and `TSAN_OPTIONS` environment variables to configure sanitizer behavior when running executables. [More details below](#running-tests-with-sanitizers).
diff --git a/docs/consensus.md b/docs/consensus.md
index 2850cf784e..6affca964e 100644
--- a/docs/consensus.md
+++ b/docs/consensus.md
@@ -2,277 +2,116 @@
**This section is a work in progress!!**
-Consensus is the task of reaching agreement within a distributed system in the
-presence of faulty or even malicious participants. This document outlines the
-[XRP Ledger Consensus Algorithm](https://arxiv.org/abs/1802.07242)
-as implemented in [xrpld](https://github.com/XRPLF/rippled), but
-focuses on its utility as a generic consensus algorithm independent of the
-detailed mechanics of the XRPL consensus Ledger. Most notably, the algorithm
-does not require fully synchronous communication between all nodes in the
-network, or even a fixed network topology, but instead achieves consensus via
-collectively trusted subnetworks.
+Consensus is the task of reaching agreement within a distributed system in the presence of faulty or even malicious participants. This document outlines the [XRP Ledger Consensus Algorithm](https://arxiv.org/abs/1802.07242) as implemented in [xrpld](https://github.com/XRPLF/rippled), but focuses on its utility as a generic consensus algorithm independent of the detailed mechanics of the XRPL consensus Ledger. Most notably, the algorithm does not require fully synchronous communication between all nodes in the network, or even a fixed network topology, but instead achieves consensus via collectively trusted subnetworks.
## Distributed Agreement
-A challenge for distributed systems is reaching agreement on changes in shared
-state. For the XRPL network, the shared state is the current ledger--account
-information, account balances, order books and other financial data. We will
-refer to shared distributed state as a /ledger/ throughout the remainder of this
-document.
+A challenge for distributed systems is reaching agreement on changes in shared state. For the XRPL network, the shared state is the current ledger--account information, account balances, order books and other financial data. We will refer to shared distributed state as a /ledger/ throughout the remainder of this document.

-As shown above, new ledgers are made by applying a set of transactions to the
-prior ledger. For the XRPL network, transactions include payments,
-modification of account settings, updates to offers and more.
+As shown above, new ledgers are made by applying a set of transactions to the prior ledger. For the XRPL network, transactions include payments, modification of account settings, updates to offers and more.
-In a centralized system, generating the next ledger is trivial since there is a
-single unique arbiter of which transactions to include and how to apply them to
-a ledger. For decentralized systems, participants must resolve disagreements on
-the set of transactions to include, the order to apply those transactions, and
-even the resulting ledger after applying the transactions. This is even more
-difficult when some participants are faulty or malicious.
+In a centralized system, generating the next ledger is trivial since there is a single unique arbiter of which transactions to include and how to apply them to a ledger. For decentralized systems, participants must resolve disagreements on the set of transactions to include, the order to apply those transactions, and even the resulting ledger after applying the transactions. This is even more difficult when some participants are faulty or malicious.
-The XRPL network is a decentralized and **trust-full** network. Anyone is free
-to join and participants are free to choose a subset of peers that are
-collectively trusted to not collude in an attempt to defraud the participant.
-Leveraging this network of trust, the XRPL algorithm has two main components.
+The XRPL network is a decentralized and **trust-full** network. Anyone is free to join and participants are free to choose a subset of peers that are collectively trusted to not collude in an attempt to defraud the participant. Leveraging this network of trust, the XRPL algorithm has two main components.
-- _Consensus_ in which network participants agree on the transactions to apply
- to a prior ledger, based on the positions of their chosen peers.
-- _Validation_ in which network participants agree on what ledger was
- generated, based on the ledgers generated by chosen peers.
+- _Consensus_ in which network participants agree on the transactions to apply to a prior ledger, based on the positions of their chosen peers.
+- _Validation_ in which network participants agree on what ledger was generated, based on the ledgers generated by chosen peers.
-These phases are continually repeated to process transactions submitted to the
-network, generating successive ledgers and giving rise to the blockchain ledger
-history depicted below. In this diagram, time is flowing to the right, but
-links between ledgers point backward to the parent. Also note the alternate
-Ledger 2 that was generated by some participants, but which failed validation
-and was abandoned.
+These phases are continually repeated to process transactions submitted to the network, generating successive ledgers and giving rise to the blockchain ledger history depicted below. In this diagram, time is flowing to the right, but links between ledgers point backward to the parent. Also note the alternate Ledger 2 that was generated by some participants, but which failed validation and was abandoned.

-The remainder of this section describes the Consensus and Validation algorithms
-in more detail and is meant as a companion guide to understanding the generic
-implementation in `xrpld`. The document **does not** discuss correctness,
-fault-tolerance or liveness properties of the algorithms or the full details of
-how they integrate within `xrpld` to support the XRPL consensus Ledger.
+The remainder of this section describes the Consensus and Validation algorithms in more detail and is meant as a companion guide to understanding the generic implementation in `xrpld`. The document **does not** discuss correctness, fault-tolerance or liveness properties of the algorithms or the full details of how they integrate within `xrpld` to support the XRPL consensus Ledger.
## Consensus Overview
### Definitions
-- The _ledger_ is the shared distributed state. Each ledger has a unique ID to
- distinguish it from all other ledgers. During consensus, the _previous_,
- _prior_ or _last-closed_ ledger is the most recent ledger seen by consensus
- and is the basis upon which it will build the next ledger.
-- A _transaction_ is an instruction for an atomic change in the ledger state. A
- unique ID distinguishes a transaction from other transactions.
-- A _transaction set_ is a set of transactions under consideration by consensus.
- The goal of consensus is to reach agreement on this set. The generic
- consensus algorithm does not rely on an ordering of transactions within the
- set, nor does it specify how to apply a transaction set to a ledger to
- generate a new ledger. A unique ID distinguishes a set of transactions from
- all other sets of transactions.
-- A _node_ is one of the distributed actors running the consensus algorithm. It
- has a unique ID to distinguish it from all other nodes.
-- A _peer_ of a node is another node that it has chosen to follow and which it
- believes will not collude with other chosen peers. The choice of peers is not
- symmetric, since participants can decide on their chosen sets independently.
-- A /position/ is the current belief of the next ledger's transaction set and
- close time. Position can refer to the node's own position or the position of a
- peer.
-- A _proposal_ is one of a sequence of positions a node shares during consensus.
- An initial proposal contains the starting position taken by a node before it
- considers any peer positions. If a node subsequently updates its position in
- response to its peers, it will issue an updated proposal. A proposal is
- uniquely identified by the ID of the proposing node, the ID of the position
- taken, the ID of the prior ledger the proposal is for, and the sequence number
- of the proposal.
-- A _dispute_ is a transaction that is either not part of a node's position or
- not in a peer's position. During consensus, the node will add or remove
- disputed transactions from its position based on that transaction's support
- amongst its peers.
+- The _ledger_ is the shared distributed state. Each ledger has a unique ID to distinguish it from all other ledgers. During consensus, the _previous_, _prior_ or _last-closed_ ledger is the most recent ledger seen by consensus and is the basis upon which it will build the next ledger.
+- A _transaction_ is an instruction for an atomic change in the ledger state. A unique ID distinguishes a transaction from other transactions.
+- A _transaction set_ is a set of transactions under consideration by consensus. The goal of consensus is to reach agreement on this set. The generic consensus algorithm does not rely on an ordering of transactions within the set, nor does it specify how to apply a transaction set to a ledger to generate a new ledger. A unique ID distinguishes a set of transactions from all other sets of transactions.
+- A _node_ is one of the distributed actors running the consensus algorithm. It has a unique ID to distinguish it from all other nodes.
+- A _peer_ of a node is another node that it has chosen to follow and which it believes will not collude with other chosen peers. The choice of peers is not symmetric, since participants can decide on their chosen sets independently.
+- A /position/ is the current belief of the next ledger's transaction set and close time. Position can refer to the node's own position or the position of a peer.
+- A _proposal_ is one of a sequence of positions a node shares during consensus. An initial proposal contains the starting position taken by a node before it considers any peer positions. If a node subsequently updates its position in response to its peers, it will issue an updated proposal. A proposal is uniquely identified by the ID of the proposing node, the ID of the position taken, the ID of the prior ledger the proposal is for, and the sequence number of the proposal.
+- A _dispute_ is a transaction that is either not part of a node's position or not in a peer's position. During consensus, the node will add or remove disputed transactions from its position based on that transaction's support amongst its peers.
-Note that most types have an ID as a lightweight identifier of instances of that
-type. Consensus often operates on the IDs directly since the underlying type is
-potentially expensive to share over the network. For example, proposal's only
-contain the ID of the position of a peer. Since many peers likely have the same
-position, this reduces the need to send the full transaction set multiple times.
-Instead, a node can request the transaction set from the network if necessary.
+Note that most types have an ID as a lightweight identifier of instances of that type. Consensus often operates on the IDs directly since the underlying type is potentially expensive to share over the network. For example, proposal's only contain the ID of the position of a peer. Since many peers likely have the same position, this reduces the need to send the full transaction set multiple times. Instead, a node can request the transaction set from the network if necessary.
### Overview

-The diagram above is an overview of the consensus process from the perspective
-of a single participant. Recall that during a single consensus round, a node is
-trying to agree with its peers on which transactions to apply to its prior
-ledger when generating the next ledger. It also attempts to agree on the
-[network time when the ledger closed](#effective_close_time). There are
-3 main phases to a consensus round:
+The diagram above is an overview of the consensus process from the perspective of a single participant. Recall that during a single consensus round, a node is trying to agree with its peers on which transactions to apply to its prior ledger when generating the next ledger. It also attempts to agree on the [network time when the ledger closed](#effective_close_time). There are 3 main phases to a consensus round:
-- A call to `startRound` places the node in the `Open` phase. In this phase,
- the node is waiting for transactions to include in its open ledger.
-- At some point, the node will `Close` the open ledger and transition to the
- `Establish` phase. In this phase, the node shares/receives peer proposals on
- which transactions should be accepted in the closed ledger.
-- At some point, the node determines it has reached consensus with its peers on
- which transactions to include. It transitions to the `Accept` phase. In this
- phase, the node works on applying the transactions to the prior ledger to
- generate a new closed ledger. Once the new ledger is completed, the node shares
- the validated ledger hash with the network and makes a call to `startRound` to
- start the cycle again for the next ledger.
+- A call to `startRound` places the node in the `Open` phase. In this phase, the node is waiting for transactions to include in its open ledger.
+- At some point, the node will `Close` the open ledger and transition to the `Establish` phase. In this phase, the node shares/receives peer proposals on which transactions should be accepted in the closed ledger.
+- At some point, the node determines it has reached consensus with its peers on which transactions to include. It transitions to the `Accept` phase. In this phase, the node works on applying the transactions to the prior ledger to generate a new closed ledger. Once the new ledger is completed, the node shares the validated ledger hash with the network and makes a call to `startRound` to start the cycle again for the next ledger.
-Throughout, a heartbeat timer calls `timerEntry` at a regular frequency to drive
-the process forward. Although the `startRound` call occurs at arbitrary times
-based on when the initial round began and the time it takes to apply
-transactions, the transitions from `Open` to `Establish` and `Establish` to
-`Accept` only occur during calls to `timerEntry`. Similarly, transactions can
-arrive at arbitrary times, independent of the heartbeat timer. Transactions
-received after the `Open` to `Close` transition and not part of peer proposals
-won't be considered until the next consensus round. They are represented above
-by the light green triangles.
+Throughout, a heartbeat timer calls `timerEntry` at a regular frequency to drive the process forward. Although the `startRound` call occurs at arbitrary times based on when the initial round began and the time it takes to apply transactions, the transitions from `Open` to `Establish` and `Establish` to `Accept` only occur during calls to `timerEntry`. Similarly, transactions can arrive at arbitrary times, independent of the heartbeat timer. Transactions received after the `Open` to `Close` transition and not part of peer proposals won't be considered until the next consensus round. They are represented above by the light green triangles.
-Peer proposals are issued by a node during a `timerEntry` call, but since peers
-do not synchronize `timerEntry` calls, they are received by other peers at
-arbitrary times. Peer proposals are only considered if received prior to the
-`Establish` to `Accept` transition, and only if the peer is working on the same
-prior ledger. Peer proposals received after consensus is reached will not be
-meaningful and are represented above by the circle with the X in it. Only
-proposals from chosen peers are considered.
+Peer proposals are issued by a node during a `timerEntry` call, but since peers do not synchronize `timerEntry` calls, they are received by other peers at arbitrary times. Peer proposals are only considered if received prior to the `Establish` to `Accept` transition, and only if the peer is working on the same prior ledger. Peer proposals received after consensus is reached will not be meaningful and are represented above by the circle with the X in it. Only proposals from chosen peers are considered.
### Effective Close Time ### {#effective_close_time}
-In addition to agreeing on a transaction set, each consensus round tries to
-agree on the time the ledger closed. Each node calculates its own close time
-when it closes the open ledger. This exact close time is rounded to the nearest
-multiple of the current _effective close time resolution_. It is this
-_effective close time_ that nodes seek to agree on. This allows servers to
-derive a common time for a ledger without the need for perfectly synchronized
-clocks. As depicted below, the 3 pink arrows represent exact close times from 3
-consensus nodes that round to the same effective close time given the current
-resolution. The purple arrow represents a peer whose estimate rounds to a
-different effective close time given the current resolution.
+In addition to agreeing on a transaction set, each consensus round tries to agree on the time the ledger closed. Each node calculates its own close time when it closes the open ledger. This exact close time is rounded to the nearest multiple of the current _effective close time resolution_. It is this _effective close time_ that nodes seek to agree on. This allows servers to derive a common time for a ledger without the need for perfectly synchronized clocks. As depicted below, the 3 pink arrows represent exact close times from 3 consensus nodes that round to the same effective close time given the current resolution. The purple arrow represents a peer whose estimate rounds to a different effective close time given the current resolution.

-The effective close time is part of the node's position and is shared with peers
-in its proposals. Just like the position on the consensus transaction set, a
-node will update its close time position in response to its peers' effective
-close time positions. Peers can agree to disagree on the close time, in which
-case the effective close time is taken as 1 second past the prior close.
+The effective close time is part of the node's position and is shared with peers in its proposals. Just like the position on the consensus transaction set, a node will update its close time position in response to its peers' effective close time positions. Peers can agree to disagree on the close time, in which case the effective close time is taken as 1 second past the prior close.
-The close time resolution is itself dynamic, decreasing (coarser) resolution in
-subsequent consensus rounds if nodes are unable to reach consensus on an
-effective close time and increasing (finer) resolution if nodes consistently
-reach close time consensus.
+The close time resolution is itself dynamic, decreasing (coarser) resolution in subsequent consensus rounds if nodes are unable to reach consensus on an effective close time and increasing (finer) resolution if nodes consistently reach close time consensus.
### Modes
-Internally, a node operates under one of the following consensus modes. Either
-of the first two modes may be chosen when a consensus round starts.
+Internally, a node operates under one of the following consensus modes. Either of the first two modes may be chosen when a consensus round starts.
-- _Proposing_ indicates the node is a full-fledged consensus participant. It
- takes on positions and sends proposals to its peers.
-- _Observing_ indicates the node is a passive consensus participant. It
- maintains a position internally, but does not propose that position to its
- peers. Instead, it receives peer proposals and updates its position
- to track the majority of its peers. This may be preferred if the node is only
- being used to track the state of the network or during a start-up phase while
- it is still synchronizing with the network.
+- _Proposing_ indicates the node is a full-fledged consensus participant. It takes on positions and sends proposals to its peers.
+- _Observing_ indicates the node is a passive consensus participant. It maintains a position internally, but does not propose that position to its peers. Instead, it receives peer proposals and updates its position to track the majority of its peers. This may be preferred if the node is only being used to track the state of the network or during a start-up phase while it is still synchronizing with the network.
-The other two modes are set internally during the consensus round when the node
-believes it is no longer working on the dominant ledger chain based on peer
-validations. It checks this on every call to `timerEntry`.
+The other two modes are set internally during the consensus round when the node believes it is no longer working on the dominant ledger chain based on peer validations. It checks this on every call to `timerEntry`.
-- _Wrong Ledger_ indicates the node is not working on the correct prior ledger
- and does not have it available. It requests that ledger from the network, but
- continues to work towards consensus this round while waiting. If it had been
- _proposing_, it will send a special "bow-out" proposal to its peers to indicate
- its change in mode for the rest of this round. For the duration of the round,
- it defers to peer positions for determining the consensus outcome as if it
- were just _observing_.
-- _Switch Ledger_ indicates that the node has acquired the correct prior ledger
- from the network. Although it now has the correct prior ledger, the fact that
- it had the wrong one at some point during this round means it is likely behind
- and should defer to peer positions for determining the consensus outcome.
+- _Wrong Ledger_ indicates the node is not working on the correct prior ledger and does not have it available. It requests that ledger from the network, but continues to work towards consensus this round while waiting. If it had been _proposing_, it will send a special "bow-out" proposal to its peers to indicate its change in mode for the rest of this round. For the duration of the round, it defers to peer positions for determining the consensus outcome as if it were just _observing_.
+- _Switch Ledger_ indicates that the node has acquired the correct prior ledger from the network. Although it now has the correct prior ledger, the fact that it had the wrong one at some point during this round means it is likely behind and should defer to peer positions for determining the consensus outcome.

-Once either wrong ledger or switch ledger are reached, the node cannot
-return to proposing or observing until the next consensus round. However,
-the node could change its view of the correct prior ledger, so going from
-switch ledger to wrong ledger and back again is possible.
+Once either wrong ledger or switch ledger are reached, the node cannot return to proposing or observing until the next consensus round. However, the node could change its view of the correct prior ledger, so going from switch ledger to wrong ledger and back again is possible.
-The distinction between the wrong and switched ledger modes arises because a
-ledger's unique identifier may be known by a node before the ledger itself. This
-reflects that fact that the data corresponding to a ledger may be large and take
-time to share over the network, whereas the smaller ID could be shared in a peer
-validation much more quickly. Distinguishing the two states allows the node to
-decide how best to generate the next ledger once it declares consensus.
+The distinction between the wrong and switched ledger modes arises because a ledger's unique identifier may be known by a node before the ledger itself. This reflects that fact that the data corresponding to a ledger may be large and take time to share over the network, whereas the smaller ID could be shared in a peer validation much more quickly. Distinguishing the two states allows the node to decide how best to generate the next ledger once it declares consensus.
### Phases
-As depicted in the overview diagram, consensus is best viewed as a progression
-through 3 phases. There are 4 public methods of the generic consensus algorithm
-that determine this progression
+As depicted in the overview diagram, consensus is best viewed as a progression through 3 phases. There are 4 public methods of the generic consensus algorithm that determine this progression
- `startRound` begins a consensus round.
-- `timerEntry` is called at a regular frequency (`LEDGER_MIN_CLOSE`) and is the
- only call to consensus that can change the phase from `Open` to `Establish`
- or `Accept`.
-- `peerProposal` is called whenever a peer proposal is received and is what
- allows a node to update its position in a subsequent `timerEntry` call.
-- `gotTxSet` is called when a transaction set is received from the network. This
- is typically in response to a prior request from the node to acquire the
- transaction set corresponding to a disagreeing peer's position.
+- `timerEntry` is called at a regular frequency (`LEDGER_MIN_CLOSE`) and is the only call to consensus that can change the phase from `Open` to `Establish` or `Accept`.
+- `peerProposal` is called whenever a peer proposal is received and is what allows a node to update its position in a subsequent `timerEntry` call.
+- `gotTxSet` is called when a transaction set is received from the network. This is typically in response to a prior request from the node to acquire the transaction set corresponding to a disagreeing peer's position.
-The following subsections describe each consensus phase in more detail and what
-actions are taken in response to these calls.
+The following subsections describe each consensus phase in more detail and what actions are taken in response to these calls.
#### Open
-The `Open` phase is a quiescent period to allow transactions to build up in the
-node's open ledger. The duration is a trade-off between latency and throughput.
-A shorter window reduces the latency to generating the next ledger, but also
-reduces transaction throughput due to fewer transactions accepted into the
-ledger.
+The `Open` phase is a quiescent period to allow transactions to build up in the node's open ledger. The duration is a trade-off between latency and throughput. A shorter window reduces the latency to generating the next ledger, but also reduces transaction throughput due to fewer transactions accepted into the ledger.
-A call to `startRound` would forcibly begin the next consensus round, skipping
-completion of the current round. This is not expected during normal operation.
-Calls to `peerProposal` or `gotTxSet` simply store the proposal or transaction
-set for use in the coming `Establish` phase.
+A call to `startRound` would forcibly begin the next consensus round, skipping completion of the current round. This is not expected during normal operation. Calls to `peerProposal` or `gotTxSet` simply store the proposal or transaction set for use in the coming `Establish` phase.
-A call to `timerEntry` first checks that the node is working on the correct
-prior ledger. If not, it will update the mode and request the correct ledger.
-Otherwise, the node checks whether to switch to the `Establish` phase and close
-the ledger.
+A call to `timerEntry` first checks that the node is working on the correct prior ledger. If not, it will update the mode and request the correct ledger. Otherwise, the node checks whether to switch to the `Establish` phase and close the ledger.
##### Ledger Close
-Under normal circumstances, the open ledger period ends when one of the following
-is true
+Under normal circumstances, the open ledger period ends when one of the following is true
-- if there are transactions in the open ledger and more than `LEDGER_MIN_CLOSE`
- have elapsed. This is the typical behavior.
-- if there are no open transactions and a suitably longer idle interval has
- elapsed. This increases the opportunity to get some transaction into
- the next ledger and avoids doing useless work closing an empty ledger.
-- if more than half the number of prior round peers have already closed or finished
- this round. This indicates the node is falling behind and needs to catch up.
+- if there are transactions in the open ledger and more than `LEDGER_MIN_CLOSE` have elapsed. This is the typical behavior.
+- if there are no open transactions and a suitably longer idle interval has elapsed. This increases the opportunity to get some transaction into the next ledger and avoids doing useless work closing an empty ledger.
+- if more than half the number of prior round peers have already closed or finished this round. This indicates the node is falling behind and needs to catch up.
-When closing the ledger, the node takes its initial position based on the
-transactions in the open ledger and uses the current time as
-its initial close time estimate. If in the proposing mode, the node shares its
-initial position with peers. Now that the node has taken a position, it will
-consider any peer positions for this round that arrived earlier. The node
-generates disputed transactions for each transaction not in common with a peer's
-position. The node also records the vote of each peer for each disputed
-transaction.
+When closing the ledger, the node takes its initial position based on the transactions in the open ledger and uses the current time as its initial close time estimate. If in the proposing mode, the node shares its initial position with peers. Now that the node has taken a position, it will consider any peer positions for this round that arrived earlier. The node generates disputed transactions for each transaction not in common with a peer's position. The node also records the vote of each peer for each disputed transaction.
-In the example below, we suppose our node has closed with transactions 1,2 and 3. It creates disputes
-for transactions 2,3 and 4, since at least one peer position differs on each.
+In the example below, we suppose our node has closed with transactions 1,2 and 3. It creates disputes for transactions 2,3 and 4, since at least one peer position differs on each.
##### disputes ##### {#disputes_image}
@@ -280,119 +119,55 @@ for transactions 2,3 and 4, since at least one peer position differs on each.
#### Establish
-The establish phase is the active period of consensus in which the node
-exchanges proposals with peers in an attempt to reach agreement on the consensus
-transactions and effective close time.
+The establish phase is the active period of consensus in which the node exchanges proposals with peers in an attempt to reach agreement on the consensus transactions and effective close time.
-A call to `startRound` would forcibly begin the next consensus round, skipping
-completion of the current round. This is not expected during normal operation.
-Calls to `peerProposal` or `gotTxSet` that reflect new positions will generate
-disputed transactions for any new disagreements and will update the peer's vote
-for all disputed transactions.
+A call to `startRound` would forcibly begin the next consensus round, skipping completion of the current round. This is not expected during normal operation. Calls to `peerProposal` or `gotTxSet` that reflect new positions will generate disputed transactions for any new disagreements and will update the peer's vote for all disputed transactions.
-A call to `timerEntry` first checks that the node is working from the correct
-prior ledger. If not, the node will update the mode and request the correct
-ledger. Otherwise, the node updates the node's position and considers whether
-to switch to the `Accepted` phase and declare consensus reached. However, at
-least `LEDGER_MIN_CONSENSUS` time must have elapsed before doing either. This
-allows peers an opportunity to take an initial position and share it.
+A call to `timerEntry` first checks that the node is working from the correct prior ledger. If not, the node will update the mode and request the correct ledger. Otherwise, the node updates the node's position and considers whether to switch to the `Accepted` phase and declare consensus reached. However, at least `LEDGER_MIN_CONSENSUS` time must have elapsed before doing either. This allows peers an opportunity to take an initial position and share it.
##### Update Position
-In order to achieve consensus, the node is looking for a transaction set that is
-supported by a super-majority of peers. The node works towards this set by
-adding or removing disputed transactions from its position based on an
-increasing threshold for inclusion.
+In order to achieve consensus, the node is looking for a transaction set that is supported by a super-majority of peers. The node works towards this set by adding or removing disputed transactions from its position based on an increasing threshold for inclusion.

-By starting with a lower threshold, a node initially allows a wide set of
-transactions into its position. If the establish round continues and the node is
-"stuck", a higher threshold can focus on accepting transactions with the most
-support. The constants that define the thresholds and durations at which the
-thresholds change are given by `AV_XXX_CONSENSUS_PCT` and
-`AV_XXX_CONSENSUS_TIME` respectively, where `XXX` is `INIT`,`MID`,`LATE` and
-`STUCK`. The effective close time position is updated using the same
-thresholds.
+By starting with a lower threshold, a node initially allows a wide set of transactions into its position. If the establish round continues and the node is "stuck", a higher threshold can focus on accepting transactions with the most support. The constants that define the thresholds and durations at which the thresholds change are given by `AV_XXX_CONSENSUS_PCT` and `AV_XXX_CONSENSUS_TIME` respectively, where `XXX` is `INIT`,`MID`,`LATE` and `STUCK`. The effective close time position is updated using the same thresholds.
-Given the [example disputes above](#disputes_image) and an initial threshold
-of 50%, our node would retain its position since transaction 1 was not in
-dispute and transactions 2 and 3 have 75% support. Since its position did not
-change, it would not need to send a new proposal to peers. Peer C would not
-change either. Peer A would add transaction 3 to its position and Peer B would
-remove transaction 4 from its position; both would then send an updated
-position.
+Given the [example disputes above](#disputes_image) and an initial threshold of 50%, our node would retain its position since transaction 1 was not in dispute and transactions 2 and 3 have 75% support. Since its position did not change, it would not need to send a new proposal to peers. Peer C would not change either. Peer A would add transaction 3 to its position and Peer B would remove transaction 4 from its position; both would then send an updated position.
-Conversely, if the diagram reflected a later call to =timerEntry= that occurs in
-the stuck region with a threshold of say 95%, our node would remove transactions
-2 and 3 from its candidate set and send an updated position. Likewise, all the
-other peers would end up with only transaction 1 in their position.
+Conversely, if the diagram reflected a later call to =timerEntry= that occurs in the stuck region with a threshold of say 95%, our node would remove transactions 2 and 3 from its candidate set and send an updated position. Likewise, all the other peers would end up with only transaction 1 in their position.
-Lastly, if our node were not in the proposing mode, it would not include its own
-vote and just take the majority (>50%) position of its peers. In this example,
-our node would maintain its position of transactions 1, 2 and 3.
+Lastly, if our node were not in the proposing mode, it would not include its own vote and just take the majority (>50%) position of its peers. In this example, our node would maintain its position of transactions 1, 2 and 3.
##### Checking Consensus
-After updating its position, the node checks for supermajority agreement with
-its peers on its current position. This agreement is of the exact transaction
-set, not just the support of individual transactions. That is, if our position
-is a subset of a peer's position, that counts as a disagreement. Also recall
-that effective close time agreement allows a supermajority of participants
-agreeing to disagree.
+After updating its position, the node checks for supermajority agreement with its peers on its current position. This agreement is of the exact transaction set, not just the support of individual transactions. That is, if our position is a subset of a peer's position, that counts as a disagreement. Also recall that effective close time agreement allows a supermajority of participants agreeing to disagree.
Consensus is declared when the following 3 clauses are true:
- `LEDGER_MIN_CONSENSUS` time has elapsed in the establish phase
-- At least 75% of the prior round proposers have proposed OR this establish
- phase is `LEDGER_MIN_CONSENSUS` longer than the last round's establish phase
+- At least 75% of the prior round proposers have proposed OR this establish phase is `LEDGER_MIN_CONSENSUS` longer than the last round's establish phase
- `minimumConsensusPercentage` of ourself and our peers share the same position
-The middle condition ensures slower peers have a chance to share positions, but
-prevents waiting too long on peers that have disconnected. Additionally, a node
-can declare that consensus has moved on if `minimumConsensusPercentage` peers
-have sent validations and moved on to the next ledger. This outcome indicates
-the node has fallen behind its peers and needs to catch up.
+The middle condition ensures slower peers have a chance to share positions, but prevents waiting too long on peers that have disconnected. Additionally, a node can declare that consensus has moved on if `minimumConsensusPercentage` peers have sent validations and moved on to the next ledger. This outcome indicates the node has fallen behind its peers and needs to catch up.
-If a node is not proposing, it does not include its own position when
-calculating the percent of agreeing participants but otherwise follows the above
-logic.
+If a node is not proposing, it does not include its own position when calculating the percent of agreeing participants but otherwise follows the above logic.
##### Accepting Consensus
-Once consensus is reached (or moved on), the node switches to the `Accept` phase
-and signals to the implementing code that the round is complete. That code is
-responsible for using the consensus transaction set to generate the next ledger
-and calling `startRound` to begin the next round. The implementation has total
-freedom on ordering transactions, deciding what to do if consensus moved on,
-determining whether to retry or abandon local transactions that did not make the
-consensus set and updating any internal state based on the consensus progress.
+Once consensus is reached (or moved on), the node switches to the `Accept` phase and signals to the implementing code that the round is complete. That code is responsible for using the consensus transaction set to generate the next ledger and calling `startRound` to begin the next round. The implementation has total freedom on ordering transactions, deciding what to do if consensus moved on, determining whether to retry or abandon local transactions that did not make the consensus set and updating any internal state based on the consensus progress.
#### Accept
-The `Accept` phase is the terminal phase of the consensus algorithm. Calls to
-`timerEntry`, `peerProposal` and `gotTxSet` will not change the internal
-consensus state while in the accept phase. The expectation is that the
-application specific code is working to generate the new ledger based on the
-consensus outcome. Once complete, that code should make a call to `startRound`
-to kick off the next consensus round. The `startRound` call includes the new
-prior ledger, prior ledger ID and whether the round should begin in the
-proposing or observing mode. After setting some initial state, the phase
-transitions to `Open`. The node will also check if the provided prior ledger
-and ID are correct, updating the mode and requesting the proper ledger from the
-network if necessary.
+The `Accept` phase is the terminal phase of the consensus algorithm. Calls to `timerEntry`, `peerProposal` and `gotTxSet` will not change the internal consensus state while in the accept phase. The expectation is that the application specific code is working to generate the new ledger based on the consensus outcome. Once complete, that code should make a call to `startRound` to kick off the next consensus round. The `startRound` call includes the new prior ledger, prior ledger ID and whether the round should begin in the proposing or observing mode. After setting some initial state, the phase transitions to `Open`. The node will also check if the provided prior ledger and ID are correct, updating the mode and requesting the proper ledger from the network if necessary.
## Consensus Type Requirements
-The consensus type requirements are given below as minimal implementation stubs.
-Actual implementations would augment these stubs with members appropriate for
-managing the details of transactions and ledgers within the larger application
-framework.
+The consensus type requirements are given below as minimal implementation stubs. Actual implementations would augment these stubs with members appropriate for managing the details of transactions and ledgers within the larger application framework.
### Transaction
-The transaction type `Tx` encapsulates a single transaction under consideration
-by consensus.
+The transaction type `Tx` encapsulates a single transaction under consideration by consensus.
```{.cpp}
struct Tx
@@ -406,10 +181,7 @@ struct Tx
### Transaction Set
-The transaction set type `TxSet` represents a set of `Tx`s that are collectively
-under consideration by consensus. A `TxSet` can be compared against other `TxSet`s
-(typically from peers) and can be modified to add or remove transactions via
-the mutable subtype.
+The transaction set type `TxSet` represents a set of `Tx`s that are collectively under consideration by consensus. A `TxSet` can be compared against other `TxSet`s (typically from peers) and can be modified to add or remove transactions via the mutable subtype.
```{.cpp}
struct TxSet
@@ -446,12 +218,7 @@ struct TxSet
### Ledger
-The `Ledger` type represents the state shared amongst the
-distributed participants. Notice that the details of how the next ledger is
-generated from the prior ledger and the consensus accepted transaction set is
-not part of the interface. Within the generic code, this type is primarily used
-to know that peers are working on the same tip of the ledger chain and to
-provide some basic timing data for consensus.
+The `Ledger` type represents the state shared amongst the distributed participants. Notice that the details of how the next ledger is generated from the prior ledger and the consensus accepted transaction set is not part of the interface. Within the generic code, this type is primarily used to know that peers are working on the same tip of the ledger chain and to provide some basic timing data for consensus.
```{.cpp}
struct Ledger
@@ -485,9 +252,7 @@ struct Ledger
### PeerProposal
-The `PeerProposal` type represents the signed position taken
-by a peer during consensus. The only type requirement is owning an instance of a
-generic `ConsensusProposal`.
+The `PeerProposal` type represents the signed position taken by a peer during consensus. The only type requirement is owning an instance of a generic `ConsensusProposal`.
```{.cpp}
// Represents our proposed position or a peer's proposed position
@@ -508,11 +273,7 @@ struct PeerPosition
### Generic Consensus Interface
-The generic `Consensus` relies on `Adaptor` template class to implement a set
-of helper functions that plug the consensus algorithm into a specific application.
-The `Adaptor` class also defines the types above needed by the algorithm. Below
-are excerpts of the generic consensus implementation and of helper types that will
-interact with the concrete implementing class.
+The generic `Consensus` relies on `Adaptor` template class to implement a set of helper functions that plug the consensus algorithm into a specific application. The `Adaptor` class also defines the types above needed by the algorithm. Below are excerpts of the generic consensus implementation and of helper types that will interact with the concrete implementing class.
```{.cpp}
// Represents a transaction under dispute this round
@@ -653,26 +414,11 @@ struct Adaptor
};
```
-The implementing class hides many details of the peer communication
-model from the generic code.
+The implementing class hides many details of the peer communication model from the generic code.
-- The `share` member functions are responsible for sharing the given type with a
- node's peers, but are agnostic to the mechanism. Ideally, messages are delivered
- faster than `LEDGER_GRANULARITY`.
-- The generic code does not specify how transactions are submitted by clients,
- propagated through the network or stored in the open ledger. Indeed, the open
- ledger is only conceptual from the perspective of the generic code---the
- initial position and transaction set are opaquely generated in a
- `Consensus::Result` instance returned from the `onClose` callback.
-- The calls to `acquireLedger` and `acquireTxSet` only have non-trivial return
- if the ledger or transaction set of interest is available. The implementing
- class is free to block while acquiring, or return the empty option while
- servicing the request asynchronously. Due to legacy reasons, the two calls
- are not symmetric. `acquireTxSet` requires the host application to call
- `gotTxSet` when an asynchronous `acquire` completes. Conversely,
- `acquireLedger` will be called again later by the consensus code if it still
- desires the ledger with the hope that the asynchronous acquisition is
- complete.
+- The `share` member functions are responsible for sharing the given type with a node's peers, but are agnostic to the mechanism. Ideally, messages are delivered faster than `LEDGER_GRANULARITY`.
+- The generic code does not specify how transactions are submitted by clients, propagated through the network or stored in the open ledger. Indeed, the open ledger is only conceptual from the perspective of the generic code---the initial position and transaction set are opaquely generated in a `Consensus::Result` instance returned from the `onClose` callback.
+- The calls to `acquireLedger` and `acquireTxSet` only have non-trivial return if the ledger or transaction set of interest is available. The implementing class is free to block while acquiring, or return the empty option while servicing the request asynchronously. Due to legacy reasons, the two calls are not symmetric. `acquireTxSet` requires the host application to call `gotTxSet` when an asynchronous `acquire` completes. Conversely, `acquireLedger` will be called again later by the consensus code if it still desires the ledger with the hope that the asynchronous acquisition is complete.
## Validation
diff --git a/docs/install-legacy.md b/docs/install-legacy.md
index 0a6800f17f..0a3bff4261 100644
--- a/docs/install-legacy.md
+++ b/docs/install-legacy.md
@@ -1,29 +1,18 @@
# Installing xrpld 3.3.0 and earlier
-> [!IMPORTANT]
-> These instructions apply to xrpld 3.3.0 and earlier, published to
-> repos.ripple.com.
-> For later releases see [install.md](./install.md).
+> [!IMPORTANT] These instructions apply to xrpld 3.3.0 and earlier, published to repos.ripple.com. For later releases see [install.md](./install.md).
-This document contains instructions for installing xrpld.
-The APT package manager is common on Debian-based Linux distributions like
-Ubuntu,
-while the YUM package manager is common on Red Hat-based Linux distributions
-like CentOS.
-Installing from source is an option for all platforms,
-and the only supported option for installing custom builds.
+This document contains instructions for installing xrpld. The APT package manager is common on Debian-based Linux distributions like Ubuntu, while the YUM package manager is common on Red Hat-based Linux distributions like CentOS. Installing from source is an option for all platforms, and the only supported option for installing custom builds.
## From source
-From a source build, you can install xrpld and libxrpl using CMake's
-`--install` mode:
+From a source build, you can install xrpld and libxrpl using CMake's `--install` mode:
```
cmake --install . --prefix /opt/local
```
-The default [prefix][1] is typically `/usr/local` on Linux and macOS and
-`C:/Program Files/xrpld` on Windows.
+The default [prefix][1] is typically `/usr/local` on Linux and macOS and `C:/Program Files/xrpld` on Windows.
[1]: https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html
diff --git a/docs/install.md b/docs/install.md
index 4c52b587b6..98ff956259 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -1,13 +1,8 @@
# Installing xrpld
-> [!NOTE]
-> These instructions apply to packages published from 2026-08-19 onwards.
-> For xrpld 3.3.0 and earlier see [install-legacy.md](./install-legacy.md).
+> [!NOTE] These instructions apply to packages published from 2026-08-19 onwards. For xrpld 3.3.0 and earlier see [install-legacy.md](./install-legacy.md).
-`xrpld` is published as DEB and RPM packages for 64-bit x86 Linux.
-Use APT on Debian-based distributions such as Debian and Ubuntu,
-and YUM on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux.
-To build from source instead, see [BUILD.md](../BUILD.md).
+`xrpld` is published as DEB and RPM packages for 64-bit x86 Linux. Use APT on Debian-based distributions such as Debian and Ubuntu, and YUM on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux. To build from source instead, see [BUILD.md](../BUILD.md).
## Release channels
@@ -20,13 +15,9 @@ Packages are published to four channels:
See [Publishing packages](../package/README.md#publishing-packages) for how channels are produced.
-The instructions below use `stable`.
-To follow another channel, replace `stable` with its name
-wherever it appears in the repository configuration.
+The instructions below use `stable`. To follow another channel, replace `stable` with its name wherever it appears in the repository configuration.
-> [!WARNING]
-> Channels other than `stable` may be broken at any time.
-> Do not use them for production servers.
+> [!WARNING] Channels other than `stable` may be broken at any time. Do not use them for production servers.
## Install the xrpld package
@@ -103,8 +94,7 @@ wherever it appears in the repository configuration.
REPOFILE
```
- `gpgcheck=1` verifies each package against the key above.
- `repo_gpgcheck=1` verifies the repository metadata, which the server signs with the same key.
+ `gpgcheck=1` verifies each package against the key above. `repo_gpgcheck=1` verifies the repository metadata, which the server signs with the same key.
3. Install the `xrpld` package:
@@ -114,8 +104,7 @@ wherever it appears in the repository configuration.
## The xrpld service
-Both package managers install a systemd unit and enable it, so `xrpld` starts on boot.
-Check whether it is already running:
+Both package managers install a systemd unit and enable it, so `xrpld` starts on boot. Check whether it is already running:
```bash
systemctl status xrpld.service
@@ -129,8 +118,7 @@ sudo systemctl start xrpld.service
### Optional: binding to privileged ports
-To serve incoming API requests on port 80 or 443, grant the service the capability to bind them.
-You must also update the config file's port settings.
+To serve incoming API requests on port 80 or 443, grant the service the capability to bind them. You must also update the config file's port settings.
```bash
sudo install -d -m 0755 /etc/systemd/system/xrpld.service.d
diff --git a/include/xrpl/basics/README.md b/include/xrpl/basics/README.md
index b20b837ed7..419be2779f 100644
--- a/include/xrpl/basics/README.md
+++ b/include/xrpl/basics/README.md
@@ -15,8 +15,7 @@ The module xrpl/basics should contain no dependencies on other modules.
- `std::list`
- For ordered containers with inserts and erases to the middle.
- For containers with iterators stable over insert and erase.
- - Generally slower and bigger than `std::vector` or `std::deque` except for
- those cases.
+ - Generally slower and bigger than `std::vector` or `std::deque` except for those cases.
- `std::set`
- For sorted containers.
@@ -26,9 +25,7 @@ The module xrpl/basics should contain no dependencies on other modules.
- For "small" sets, `std::set` might be faster and smaller.
- `xrpl::hardened_hash_set`
- - For data sets where the key could be manipulated by an attacker
- in an attempt to mount an algorithmic complexity attack: see
- http://en.wikipedia.org/wiki/Algorithmic_complexity_attack
+ - For data sets where the key could be manipulated by an attacker in an attempt to mount an algorithmic complexity attack: see http://en.wikipedia.org/wiki/Algorithmic_complexity_attack
The following container is deprecated
diff --git a/include/xrpl/consensus/README.md b/include/xrpl/consensus/README.md
index 3cc1294c4f..a29ba82e95 100644
--- a/include/xrpl/consensus/README.md
+++ b/include/xrpl/consensus/README.md
@@ -1,8 +1,3 @@
# Consensus
-This directory contains the implementation of a
-generic consensus algorithm. The implementation
-follows a CRTP design, requiring client code to implement
-specific functions and types to use consensus in their
-application. The interface is undergoing refactoring and
-is not yet finalized.
+This directory contains the implementation of a generic consensus algorithm. The implementation follows a CRTP design, requiring client code to implement specific functions and types to use consensus in their application. The interface is undergoing refactoring and is not yet finalized.
diff --git a/include/xrpl/crypto/README.md b/include/xrpl/crypto/README.md
index 5e3e4a1dc3..9c530b7a0e 100644
--- a/include/xrpl/crypto/README.md
+++ b/include/xrpl/crypto/README.md
@@ -1,4 +1,3 @@
# SSLUtil
-This module exposes the OpenSSL headers and provides utilities to
-operate with OpenSSL / BIGNUM objects.
+This module exposes the OpenSSL headers and provides utilities to operate with OpenSSL / BIGNUM objects.
diff --git a/include/xrpl/nodestore/README.md b/include/xrpl/nodestore/README.md
index b78c99e27d..8a3d39237d 100644
--- a/include/xrpl/nodestore/README.md
+++ b/include/xrpl/nodestore/README.md
@@ -7,16 +7,11 @@
## Introduction
-A `NodeObject` is a simple object that the Ledger uses to store entries. It is
-comprised of a type, a hash and a blob. It can be uniquely
-identified by the hash, which is a 256 bit hash of the blob. The blob is a
-variable length block of serialized data. The type identifies what the blob
-contains. The fields are as follows:
+A `NodeObject` is a simple object that the Ledger uses to store entries. It is comprised of a type, a hash and a blob. It can be uniquely identified by the hash, which is a 256 bit hash of the blob. The blob is a variable length block of serialized data. The type identifies what the blob contains. The fields are as follows:
- `mType`
-An enumeration that determines what the blob holds. There are four
-different types of objects stored.
+An enumeration that determines what the blob holds. There are four different types of objects stored.
- **ledger**
@@ -50,19 +45,11 @@ A blob containing the payload. Stored in the following format.
---
-The `NodeStore` provides an interface that stores, in a persistent database, a
-collection of NodeObjects that xrpld uses as its primary representation of
-ledger entries. All ledger entries are stored as NodeObjects and as such, need
-to be persisted between launches. If a NodeObject is accessed and is not in
-memory, it will be retrieved from the database.
+The `NodeStore` provides an interface that stores, in a persistent database, a collection of NodeObjects that xrpld uses as its primary representation of ledger entries. All ledger entries are stored as NodeObjects and as such, need to be persisted between launches. If a NodeObject is accessed and is not in memory, it will be retrieved from the database.
## Backend
-The `NodeStore` implementation provides the `Backend` abstract interface,
-which lets different key/value databases to be chosen at run-time. This allows
-experimentation with different engines. Improvements in the performance of the
-NodeStore are a constant area of research. The database can be specified in
-the configuration file [node_db] section as follows.
+The `NodeStore` implementation provides the `Backend` abstract interface, which lets different key/value databases to be chosen at run-time. This allows experimentation with different engines. Improvements in the performance of the NodeStore are a constant area of research. The database can be specified in the configuration file [node_db] section as follows.
One or more lines of key / value pairs
@@ -106,75 +93,30 @@ Choices for 'compression'
# Benchmarks
-The `NodeStore.Timing` test is used to execute a set of read/write workloads to
-compare current available nodestore backends. It can be executed with:
+The `NodeStore.Timing` test is used to execute a set of read/write workloads to compare current available nodestore backends. It can be executed with:
```
$xrpld --unittest=NodeStoreTiming
```
-It is also possible to use alternate DB config params by passing config strings
-as `--unittest-arg`.
+It is also possible to use alternate DB config params by passing config strings as `--unittest-arg`.
## Addendum
-The discussion below refers to a `RocksDBQuick` backend that has since been
-removed from the code as it was not working and not maintained. That backend
-primarily used one of the several rocks `Optimize*` methods to setup the
-majority of the DB options/params, whereas the primary RocksDB backend exposes
-many of the available config options directly. The code for RocksDBQuick can be
-found in versions of this repo 1.2 and earlier if you need to refer back to it.
-The conclusions below date from about 2014 and may need revisiting based on
-newer versions of RocksDB (TBD).
+The discussion below refers to a `RocksDBQuick` backend that has since been removed from the code as it was not working and not maintained. That backend primarily used one of the several rocks `Optimize*` methods to setup the majority of the DB options/params, whereas the primary RocksDB backend exposes many of the available config options directly. The code for RocksDBQuick can be found in versions of this repo 1.2 and earlier if you need to refer back to it. The conclusions below date from about 2014 and may need revisiting based on newer versions of RocksDB (TBD).
## Discussion
-RocksDBQuickFactory is intended to provide a testbed for comparing potential
-rocksdb performance with the existing recommended configuration in xrpld.cfg.
-Through various executions and profiling some conclusions are presented below.
+RocksDBQuickFactory is intended to provide a testbed for comparing potential rocksdb performance with the existing recommended configuration in xrpld.cfg. Through various executions and profiling some conclusions are presented below.
-- If the write ahead log is enabled, insert speed soon clogs up under load. The
- BatchWriter class intends to stop this from blocking the main threads by queuing
- up writes and running them in a separate thread. However, rocksdb already has
- separate threads dedicated to flushing the memtable to disk and the memtable is
- itself an in-memory queue. The result is two queues with a guarantee of
- durability in between. However if the memtable was used as the sole queue and
- the rocksdb::Flush() call was manually triggered at opportune moments, possibly
- just after ledger close, then that would provide similar, but more predictable
- guarantees. It would also remove an unneeded thread and unnecessary memory
- usage. An alternative point of view is that because there will always be many
- other xrpld instances running there is no need for such guarantees. The nodes
- will always be available from another peer.
+- If the write ahead log is enabled, insert speed soon clogs up under load. The BatchWriter class intends to stop this from blocking the main threads by queuing up writes and running them in a separate thread. However, rocksdb already has separate threads dedicated to flushing the memtable to disk and the memtable is itself an in-memory queue. The result is two queues with a guarantee of durability in between. However if the memtable was used as the sole queue and the rocksdb::Flush() call was manually triggered at opportune moments, possibly just after ledger close, then that would provide similar, but more predictable guarantees. It would also remove an unneeded thread and unnecessary memory usage. An alternative point of view is that because there will always be many other xrpld instances running there is no need for such guarantees. The nodes will always be available from another peer.
-- Lookup in a block was previously using binary search. With xrpld's use case
- it is highly unlikely that two adjacent key/values will ever be requested one
- after the other. Therefore hash indexing of blocks makes much more sense.
- Rocksdb has a number of options for hash indexing both memtables and blocks and
- these need more testing to find the best choice.
+- Lookup in a block was previously using binary search. With xrpld's use case it is highly unlikely that two adjacent key/values will ever be requested one after the other. Therefore hash indexing of blocks makes much more sense. Rocksdb has a number of options for hash indexing both memtables and blocks and these need more testing to find the best choice.
-- The current Database implementation has two forms of caching, so the LRU cache
- of blocks at Factory level does not make any sense. However, if the hash
- indexing and potentially the new [bloom
- filter](http://rocksdb.org/blog/1427/new-bloom-filter-format/) can provide
- faster lookup for non-existent keys, then potentially the caching could exist at
- Factory level.
+- The current Database implementation has two forms of caching, so the LRU cache of blocks at Factory level does not make any sense. However, if the hash indexing and potentially the new [bloom filter](http://rocksdb.org/blog/1427/new-bloom-filter-format/) can provide faster lookup for non-existent keys, then potentially the caching could exist at Factory level.
-- Multiple runs of the benchmarks can yield surprisingly different results. This
- can perhaps be attributed to the asynchronous nature of rocksdb's compaction
- process. The benchmarks are artificial and create highly unlikely write load to
- create the dataset to measure different read access patterns. Therefore multiple
- runs of the benchmarks are required to get a feel for the effectiveness of the
- changes. This contrasts sharply with the keyvadb benchmarking were highly
- repeatable timings were discovered. Also realistically sized datasets are
- required to get a correct insight. The number of 2,000,000 key/values (actually
- 4,000,000 after the two insert benchmarks complete) is too low to get a full
- picture.
+- Multiple runs of the benchmarks can yield surprisingly different results. This can perhaps be attributed to the asynchronous nature of rocksdb's compaction process. The benchmarks are artificial and create highly unlikely write load to create the dataset to measure different read access patterns. Therefore multiple runs of the benchmarks are required to get a feel for the effectiveness of the changes. This contrasts sharply with the keyvadb benchmarking were highly repeatable timings were discovered. Also realistically sized datasets are required to get a correct insight. The number of 2,000,000 key/values (actually 4,000,000 after the two insert benchmarks complete) is too low to get a full picture.
-- An interesting side effect of running the benchmarks in a profiler was that a
- clear pattern of what RocksDB does under the hood was observable. This led to
- the decision to trial hash indexing and also the discovery of the native CRC32
- instruction not being used.
+- An interesting side effect of running the benchmarks in a profiler was that a clear pattern of what RocksDB does under the hood was observable. This led to the decision to trial hash indexing and also the discovery of the native CRC32 instruction not being used.
-- Important point to note that is if this factory is tested with an existing set
- of sst files none of the old sst files will benefit from indexing changes until
- they are compacted at a future point in time.
+- Important point to note that is if this factory is tested with an existing set of sst files none of the old sst files will benefit from indexing changes until they are compacted at a future point in time.
diff --git a/include/xrpl/proto/README.md b/include/xrpl/proto/README.md
index 14d6494bb0..0c47cf38b0 100644
--- a/include/xrpl/proto/README.md
+++ b/include/xrpl/proto/README.md
@@ -1,4 +1,3 @@
# Proto
-This holds protocol buffers source code. The protoc tool stores the output
-of the .proto files in the build directory.
+This holds protocol buffers source code. The protoc tool stores the output of the .proto files in the build directory.
diff --git a/include/xrpl/proto/org/xrpl/rpc/v1/README.md b/include/xrpl/proto/org/xrpl/rpc/v1/README.md
index d0ff14cd13..95a0e97c9b 100644
--- a/include/xrpl/proto/org/xrpl/rpc/v1/README.md
+++ b/include/xrpl/proto/org/xrpl/rpc/v1/README.md
@@ -1,81 +1,35 @@
# Protocol buffer definitions for gRPC
-This folder contains the protocol buffer definitions used by the xrpld gRPC API.
-The gRPC API attempts to mimic the JSON/Websocket API as much as possible.
-As of April 2020, the gRPC API supports a subset of the full xrpld API:
-tx, account_tx, account_info, fee and submit.
+This folder contains the protocol buffer definitions used by the xrpld gRPC API. The gRPC API attempts to mimic the JSON/Websocket API as much as possible. As of April 2020, the gRPC API supports a subset of the full xrpld API: tx, account_tx, account_info, fee and submit.
### Making Changes
#### Wire Format and Backwards Compatibility
-When making changes to the protocol buffer definitions in this folder, care must
-be taken to ensure the changes do not break the wire format, which would break
-backwards compatibility. At a high level, do not change any existing fields.
-This includes the field's name, type and field number. Do not remove any
-existing fields. It is always safe to add fields; just remember to give each of
-the new fields a unique field number. The field numbers don't have to be in any
-particular order and there can be gaps. More info about what changes break the
-wire format can be found
-[here](https://developers.google.com/protocol-buffers/docs/proto3#updating).
+When making changes to the protocol buffer definitions in this folder, care must be taken to ensure the changes do not break the wire format, which would break backwards compatibility. At a high level, do not change any existing fields. This includes the field's name, type and field number. Do not remove any existing fields. It is always safe to add fields; just remember to give each of the new fields a unique field number. The field numbers don't have to be in any particular order and there can be gaps. More info about what changes break the wire format can be found [here](https://developers.google.com/protocol-buffers/docs/proto3#updating).
#### Conventions
-For fields that are reused across different message types, we define the field as a unique
-message type in common.proto. The name of the message type is the same as the
-field name, with the exception that the field name itself is snake case, whereas
-the message type is in Pascal case. The message type has one field, called
-`value`. This pattern does not need to be strictly followed across the entire API,
-but should be followed for transactions and ledger objects, since there is a high rate
-of field reuse across different transactions and ledger objects.
-The motivation for this pattern is two-fold. First, we ensure the field has the
-same type everywhere that the field is used. Second, wrapping primitive types in
-their own message type prevents default initialization of those primitive types.
-For example, `uint32` is initialized to `0` if not explicitly set;
-there is no way to tell if the client or server set the field to `0` (which may be
-a valid value for the field) or the field was default initialized.
+For fields that are reused across different message types, we define the field as a unique message type in common.proto. The name of the message type is the same as the field name, with the exception that the field name itself is snake case, whereas the message type is in Pascal case. The message type has one field, called `value`. This pattern does not need to be strictly followed across the entire API, but should be followed for transactions and ledger objects, since there is a high rate of field reuse across different transactions and ledger objects. The motivation for this pattern is two-fold. First, we ensure the field has the same type everywhere that the field is used. Second, wrapping primitive types in their own message type prevents default initialization of those primitive types. For example, `uint32` is initialized to `0` if not explicitly set; there is no way to tell if the client or server set the field to `0` (which may be a valid value for the field) or the field was default initialized.
#### Name Collisions
-Each message type must have a unique name. To resolve collisions, add a suffix
-to one or more message types. For instance, ledger objects and transaction types
-often have the same name (`DepositPreauth` for example). To resolve this, the
-`DepositPreauth` ledger object is named `DepositPreauthObject`.
+Each message type must have a unique name. To resolve collisions, add a suffix to one or more message types. For instance, ledger objects and transaction types often have the same name (`DepositPreauth` for example). To resolve this, the `DepositPreauth` ledger object is named `DepositPreauthObject`.
#### To add a field or message type
-To add a field to a message, define the fields type, name and unique index.
-To add a new message type, give the message type a unique name.
-Then, add the appropriate C++ code in GRPCHelpers.cpp, or in the handler itself,
-to serialize/deserialize the new field or message type.
+To add a field to a message, define the fields type, name and unique index. To add a new message type, give the message type a unique name. Then, add the appropriate C++ code in GRPCHelpers.cpp, or in the handler itself, to serialize/deserialize the new field or message type.
#### To add a new gRPC method
-To add a new gRPC method, add the gRPC method in xrp_ledger.proto. The method name
-should begin with a verb. Define the request and response types in their own
-file. The name of the request type should be the method name suffixed with `Request`, and
-the response type name should be the method name suffixed with `Response`. For
-example, the `GetAccountInfo` method has request type `GetAccountInfoRequest` and
-response type `GetAccountInfoResponse`.
+To add a new gRPC method, add the gRPC method in xrp_ledger.proto. The method name should begin with a verb. Define the request and response types in their own file. The name of the request type should be the method name suffixed with `Request`, and the response type name should be the method name suffixed with `Response`. For example, the `GetAccountInfo` method has request type `GetAccountInfoRequest` and response type `GetAccountInfoResponse`.
-After defining the protobuf messages for the new method, add an instantiation of the
-templated `CallData` class in GRPCServerImpl::setupListeners(). The template
-parameters should be the request type and the response type.
+After defining the protobuf messages for the new method, add an instantiation of the templated `CallData` class in GRPCServerImpl::setupListeners(). The template parameters should be the request type and the response type.
-Finally, define the handler itself in the appropriate file under the
-src/xrpld/rpc/handlers folder. If the method already has a JSON/Websocket
-equivalent, write the gRPC handler in the same file, and abstract common logic
-into helper functions (see Tx.cpp or AccountTx.cpp for an example).
+Finally, define the handler itself in the appropriate file under the src/xrpld/rpc/handlers folder. If the method already has a JSON/Websocket equivalent, write the gRPC handler in the same file, and abstract common logic into helper functions (see Tx.cpp or AccountTx.cpp for an example).
#### Testing
-When modifying an existing gRPC method, be sure to test that modification in the
-corresponding, existing unit test. When creating a new gRPC method, create a
-client stub with `XRPLedgerAPIService::NewStub` and `grpc::CreateChannel`, and
-use it to call the new method. See `GRPCServerTLS_test.cpp` for an example.
-The gRPC tests are paired with their JSON counterpart, and the tests should
-mirror the JSON test as much as possible.
+When modifying an existing gRPC method, be sure to test that modification in the corresponding, existing unit test. When creating a new gRPC method, create a client stub with `XRPLedgerAPIService::NewStub` and `grpc::CreateChannel`, and use it to call the new method. See `GRPCServerTLS_test.cpp` for an example. The gRPC tests are paired with their JSON counterpart, and the tests should mirror the JSON test as much as possible.
-Refer to the Protocol Buffers [language
-guide](https://developers.google.com/protocol-buffers/docs/proto3)
-for more detailed information about Protocol Buffers.
+Refer to the Protocol Buffers [language guide](https://developers.google.com/protocol-buffers/docs/proto3) for more detailed information about Protocol Buffers.
diff --git a/include/xrpl/protocol/README.md b/include/xrpl/protocol/README.md
index d679c583d4..2f75313a57 100644
--- a/include/xrpl/protocol/README.md
+++ b/include/xrpl/protocol/README.md
@@ -1,42 +1,24 @@
# protocol
-Classes and functions for handling data and
-values associated with the XRP Ledger protocol.
+Classes and functions for handling data and values associated with the XRP Ledger protocol.
## Serialized Objects
-Objects transmitted over the network must be
-serialized into a canonical format. The prefix "ST" refers
-to classes that deal with the serialized format.
+Objects transmitted over the network must be serialized into a canonical format. The prefix "ST" refers to classes that deal with the serialized format.
-The term "Tx" or "tx" is an abbreviation for "Transaction",
-a commonly occurring object type.
+The term "Tx" or "tx" is an abbreviation for "Transaction", a commonly occurring object type.
### Optional Fields
-Our serialized fields have some "type magic" to make
-optional fields easier to read:
+Our serialized fields have some "type magic" to make optional fields easier to read:
-- The operation `x[sfFoo]` means "return the value of 'Foo'
- if it exists, or the default value if it doesn't."
-- The operation `x[~sfFoo]` means "return the value of 'Foo'
- if it exists, or nothing if it doesn't." This usage of the
- tilde/bitwise NOT operator is not standard outside of the
- `xrpld` codebase.
- - As a consequence of this, `x[~sfFoo] = y[~sfFoo]`
- assigns the value of Foo from y to x, including omitting
- Foo from x if it doesn't exist in y.
+- The operation `x[sfFoo]` means "return the value of 'Foo' if it exists, or the default value if it doesn't."
+- The operation `x[~sfFoo]` means "return the value of 'Foo' if it exists, or nothing if it doesn't." This usage of the tilde/bitwise NOT operator is not standard outside of the `xrpld` codebase.
+ - As a consequence of this, `x[~sfFoo] = y[~sfFoo]` assigns the value of Foo from y to x, including omitting Foo from x if it doesn't exist in y.
-Typically, for things that are guaranteed to exist, you use
-`x[sfFoo]` and avoid having to deal with a container that may
-or may not hold a value. For things not guaranteed to exist,
-you use `x[~sfFoo]` because you want such a container. It
-avoids having to look something up twice, once just to see if
-it exists and a second time to get/set its value.
-([Real example](https://github.com/XRPLF/rippled/blob/35f4698aed5dce02f771b34cfbb690495cb5efcc/src/ripple/app/tx/impl/PayChan.cpp#L229-L236))
+Typically, for things that are guaranteed to exist, you use `x[sfFoo]` and avoid having to deal with a container that may or may not hold a value. For things not guaranteed to exist, you use `x[~sfFoo]` because you want such a container. It avoids having to look something up twice, once just to see if it exists and a second time to get/set its value. ([Real example](https://github.com/XRPLF/rippled/blob/35f4698aed5dce02f771b34cfbb690495cb5efcc/src/ripple/app/tx/impl/PayChan.cpp#L229-L236))
-The source of this "type magic" is in
-[SField.h](./SField.h#L296-L302).
+The source of this "type magic" is in [SField.h](./SField.h#L296-L302).
### Related Resources
diff --git a/include/xrpl/protocol_autogen/README.md b/include/xrpl/protocol_autogen/README.md
index ed649a05fc..0f77c367a5 100644
--- a/include/xrpl/protocol_autogen/README.md
+++ b/include/xrpl/protocol_autogen/README.md
@@ -11,21 +11,16 @@ The files in this directory are generated from macro definition files:
## Generation Process
-Generation requires a one-time setup step to create a virtual environment
-and install Python dependencies, followed by running the generation target:
+Generation requires a one-time setup step to create a virtual environment and install Python dependencies, followed by running the generation target:
```bash
cmake --build . --target setup_code_gen # create venv and install dependencies (once)
cmake --build . --target code_gen # generate code
```
-By default, `CODEGEN_VENV_DIR` points to `.venv` in the project root. The
-`setup_code_gen` target creates a venv there and installs the required packages.
-The `code_gen` target then uses the venv's Python interpreter to run generation.
+By default, `CODEGEN_VENV_DIR` points to `.venv` in the project root. The `setup_code_gen` target creates a venv there and installs the required packages. The `code_gen` target then uses the venv's Python interpreter to run generation.
-Generation is pure Python, so the same targets are also available as a
-standalone project that needs neither the dependencies nor a compiler. This is
-what CI uses, and it is handy if you only want to regenerate these files:
+Generation is pure Python, so the same targets are also available as a standalone project that needs neither the dependencies nor a compiler. This is what CI uses, and it is handy if you only want to regenerate these files:
```bash
cmake -S cmake/codegen -B build/codegen
diff --git a/include/xrpl/resource/README.md b/include/xrpl/resource/README.md
index 96b6c3d603..0d6e445833 100644
--- a/include/xrpl/resource/README.md
+++ b/include/xrpl/resource/README.md
@@ -9,69 +9,38 @@ The ResourceManager module has these responsibilities:
## Description
-To prevent monopolization of server resources or attacks on servers,
-resource consumption is monitored at each endpoint. When consumption
-exceeds certain thresholds, costs are imposed. Costs could include charging
-additional XRP for transactions, requiring a proof of work to be
-performed, or simply disconnecting the endpoint.
+To prevent monopolization of server resources or attacks on servers, resource consumption is monitored at each endpoint. When consumption exceeds certain thresholds, costs are imposed. Costs could include charging additional XRP for transactions, requiring a proof of work to be performed, or simply disconnecting the endpoint.
-Currently, consumption endpoints include websocket connections used to
-service clients, and peer connections used to create the peer to peer
-overlay network implementing the XRPL protocol.
+Currently, consumption endpoints include websocket connections used to service clients, and peer connections used to create the peer to peer overlay network implementing the XRPL protocol.
-The current "balance" of a Consumer represents resource consumption
-debt or credit. Debt is accrued when bad loads are imposed. Credit is
-granted when good loads are imposed. When the balance crosses heuristic
-thresholds, costs are increased on the endpoint. The balance is
-represented as a unitless relative quantity. This balance is currently
-held by the Entry struct in the impl/Entry.h file.
+The current "balance" of a Consumer represents resource consumption debt or credit. Debt is accrued when bad loads are imposed. Credit is granted when good loads are imposed. When the balance crosses heuristic thresholds, costs are increased on the endpoint. The balance is represented as a unitless relative quantity. This balance is currently held by the Entry struct in the impl/Entry.h file.
-Costs associated with specific transactions are defined in the
-impl/Fees files.
+Costs associated with specific transactions are defined in the impl/Fees files.
-Although RPC connections consume resources, they are transient and
-cannot be rate limited. It is advised not to expose RPC interfaces
-to the general public.
+Although RPC connections consume resources, they are transient and cannot be rate limited. It is advised not to expose RPC interfaces to the general public.
## Consumer Types
-Consumers are placed into three classifications (as identified by the
-resource::Kind enumeration):
+Consumers are placed into three classifications (as identified by the resource::Kind enumeration):
- InBound,
- OutBound, and
- Admin
-Each caller determines for itself the classification of the Consumer it is
-creating.
+Each caller determines for itself the classification of the Consumer it is creating.
## Resource Loading
-It is expected that a client will impose a higher load on the server
-when it first connects: the client may need to catch up on transactions
-it has missed, or get trust lines, or transfer fees. The Manager must
-expect this initial peak load, but not allow that high load to continue
-because over the long term that would unduly stress the server.
+It is expected that a client will impose a higher load on the server when it first connects: the client may need to catch up on transactions it has missed, or get trust lines, or transfer fees. The Manager must expect this initial peak load, but not allow that high load to continue because over the long term that would unduly stress the server.
-If a client places a sustained high load on the server, that client
-is initially given a warning message. If that high load continues
-the Manager may tell the heavily loaded server to drop the connection
-entirely and not allow re-connection for some amount of time.
+If a client places a sustained high load on the server, that client is initially given a warning message. If that high load continues the Manager may tell the heavily loaded server to drop the connection entirely and not allow re-connection for some amount of time.
-Each load is monitored by capturing peaks and then decaying those peak
-values over time: this is implemented by the DecayingSample class.
+Each load is monitored by capturing peaks and then decaying those peak values over time: this is implemented by the DecayingSample class.
## Gossip
-Each server in a cluster creates a list of IP addresses of end points
-that are imposing a significant load. This list is called Gossip, which
-is passed to other nodes in that cluster. Gossip helps individual
-servers in the cluster identify IP addresses that might be unduly loading
-the entire cluster. Again the recourse of the individual servers is to
-drop connections to those IP addresses that occur commonly in the gossip.
+Each server in a cluster creates a list of IP addresses of end points that are imposing a significant load. This list is called Gossip, which is passed to other nodes in that cluster. Gossip helps individual servers in the cluster identify IP addresses that might be unduly loading the entire cluster. Again the recourse of the individual servers is to drop connections to those IP addresses that occur commonly in the gossip.
## Access
-In xrpld, the Application holds a unique instance of resource::Manager,
-which may be retrieved by calling the method
-`Application::getResourceManager()`.
+In xrpld, the Application holds a unique instance of resource::Manager, which may be retrieved by calling the method `Application::getResourceManager()`.
diff --git a/include/xrpl/shamap/README.md b/include/xrpl/shamap/README.md
index 8931a1b50c..89ee710fd5 100644
--- a/include/xrpl/shamap/README.md
+++ b/include/xrpl/shamap/README.md
@@ -2,25 +2,18 @@
March 2020
-The `SHAMap` is a Merkle tree (http://en.wikipedia.org/wiki/Merkle_tree).
-The `SHAMap` is also a radix trie of radix 16
-(http://en.wikipedia.org/wiki/Radix_tree).
+The `SHAMap` is a Merkle tree (http://en.wikipedia.org/wiki/Merkle_tree). The `SHAMap` is also a radix trie of radix 16 (http://en.wikipedia.org/wiki/Radix_tree).
-The Merkle trie data structure is important because subtrees and even the entire
-tree can be compared with other trees in O(1) time by simply comparing the hashes.
-This makes it very efficient to determine if two `SHAMap`s contain the same set of
-transactions or account state modifications.
+The Merkle trie data structure is important because subtrees and even the entire tree can be compared with other trees in O(1) time by simply comparing the hashes. This makes it very efficient to determine if two `SHAMap`s contain the same set of transactions or account state modifications.
-The radix trie property is helpful in that a key (hash) of a transaction
-or account state can be used to navigate the trie.
+The radix trie property is helpful in that a key (hash) of a transaction or account state can be used to navigate the trie.
A `SHAMap` is a trie with two node types:
1. SHAMapInnerNode
2. SHAMapLeafNode
-Both of these nodes directly inherit from SHAMapTreeNode which holds data
-common to both of the node types.
+Both of these nodes directly inherit from SHAMapTreeNode which holds data common to both of the node types.
All non-leaf nodes have type SHAMapInnerNode.
@@ -34,20 +27,13 @@ A given `SHAMap` always stores only one of three kinds of data:
- Transactions without metadata, or
- Account states.
-So all of the leaf nodes of a particular `SHAMap` will always have a uniform type.
-The inner nodes carry no data other than the hash of the nodes beneath them.
+So all of the leaf nodes of a particular `SHAMap` will always have a uniform type. The inner nodes carry no data other than the hash of the nodes beneath them.
-All nodes are owned by shared_ptrs resident in either other nodes, or in case of
-the root node, a shared_ptr in the `SHAMap` itself. The use of shared_ptrs
-permits more than one `SHAMap` at a time to share ownership of a node. This
-occurs (for example), when a copy of a `SHAMap` is made.
+All nodes are owned by shared_ptrs resident in either other nodes, or in case of the root node, a shared_ptr in the `SHAMap` itself. The use of shared_ptrs permits more than one `SHAMap` at a time to share ownership of a node. This occurs (for example), when a copy of a `SHAMap` is made.
-Copies are made with the `snapShot` function as opposed to the `SHAMap` copy
-constructor. See the section on `SHAMap` creation for more details about
-`snapShot`.
+Copies are made with the `snapShot` function as opposed to the `SHAMap` copy constructor. See the section on `SHAMap` creation for more details about `snapShot`.
-Sequence numbers are used to further customize the node ownership strategy. See
-the section on sequence numbers for details on sequence numbers.
+Sequence numbers are used to further customize the node ownership strategy. See the section on sequence numbers for details on sequence numbers.

@@ -58,145 +44,63 @@ There are two different ways of building and using a `SHAMap`:
1. A mutable `SHAMap` and
2. An immutable `SHAMap`
-The distinction here is not of the classic C++ immutable-means-unchanging sense.
-An immutable `SHAMap` contains _nodes_ that are immutable. Also, once a node has
-been located in an immutable `SHAMap`, that node is guaranteed to persist in that
-`SHAMap` for the lifetime of the `SHAMap`.
+The distinction here is not of the classic C++ immutable-means-unchanging sense. An immutable `SHAMap` contains _nodes_ that are immutable. Also, once a node has been located in an immutable `SHAMap`, that node is guaranteed to persist in that `SHAMap` for the lifetime of the `SHAMap`.
-So, somewhat counter-intuitively, an immutable `SHAMap` may grow as new nodes are
-introduced. But an immutable `SHAMap` will never get smaller (until it entirely
-evaporates when it is destroyed). Nodes, once introduced to the immutable
-`SHAMap`, also never change their location in memory. So nodes in an immutable
-`SHAMap` can be handled using raw pointers (if you're careful).
+So, somewhat counter-intuitively, an immutable `SHAMap` may grow as new nodes are introduced. But an immutable `SHAMap` will never get smaller (until it entirely evaporates when it is destroyed). Nodes, once introduced to the immutable `SHAMap`, also never change their location in memory. So nodes in an immutable `SHAMap` can be handled using raw pointers (if you're careful).
-One consequence of this design is that an immutable `SHAMap` can never be
-"trimmed". There is no way to identify unnecessary nodes in an immutable `SHAMap`
-that could be removed. Once a node has been brought into the in-memory `SHAMap`,
-that node stays in memory for the life of the `SHAMap`.
+One consequence of this design is that an immutable `SHAMap` can never be "trimmed". There is no way to identify unnecessary nodes in an immutable `SHAMap` that could be removed. Once a node has been brought into the in-memory `SHAMap`, that node stays in memory for the life of the `SHAMap`.
-Most `SHAMap`s are immutable, in the sense that they don't modify or remove their
-contained nodes.
+Most `SHAMap`s are immutable, in the sense that they don't modify or remove their contained nodes.
-An example where a mutable `SHAMap` is required is when we want to apply
-transactions to the last closed ledger. To do so we'd make a mutable snapshot
-of the state trie and then start applying transactions to it. Because the
-snapshot is mutable, changes to nodes in the snapshot will not affect nodes in
-other `SHAMap`s.
+An example where a mutable `SHAMap` is required is when we want to apply transactions to the last closed ledger. To do so we'd make a mutable snapshot of the state trie and then start applying transactions to it. Because the snapshot is mutable, changes to nodes in the snapshot will not affect nodes in other `SHAMap`s.
-An example using a immutable ledger would be when there's an open ledger and
-some piece of code wishes to query the state of the ledger. In this case we
-don't wish to change the state of the `SHAMap`, so we'd use an immutable snapshot.
+An example using a immutable ledger would be when there's an open ledger and some piece of code wishes to query the state of the ledger. In this case we don't wish to change the state of the `SHAMap`, so we'd use an immutable snapshot.
## Sequence numbers
-Both `SHAMap`s and their nodes carry a sequence number. This is simply an
-unsigned number that indicates ownership or membership, or a non-membership.
+Both `SHAMap`s and their nodes carry a sequence number. This is simply an unsigned number that indicates ownership or membership, or a non-membership.
-`SHAMap`s sequence numbers normally start out as 1. However when a snap-shot of
-a `SHAMap` is made, the copy's sequence number is 1 greater than the original.
+`SHAMap`s sequence numbers normally start out as 1. However when a snap-shot of a `SHAMap` is made, the copy's sequence number is 1 greater than the original.
-The nodes of a `SHAMap` have their own copy of a sequence number. If the `SHAMap`
-is mutable, meaning it can change, then all of its nodes must have the
-same sequence number as the `SHAMap` itself. This enforces an invariant that none
-of the nodes are shared with other `SHAMap`s.
+The nodes of a `SHAMap` have their own copy of a sequence number. If the `SHAMap` is mutable, meaning it can change, then all of its nodes must have the same sequence number as the `SHAMap` itself. This enforces an invariant that none of the nodes are shared with other `SHAMap`s.
-When a `SHAMap` needs to have a private copy of a node, not shared by any other
-`SHAMap`, it first clones it and then sets the new copy to have a sequence number
-equal to the `SHAMap` sequence number. The `unshareNode` is a private utility
-which automates the task of first checking if the node is already sharable, and
-if so, cloning it and giving it the proper sequence number. An example case
-where a private copy is needed is when an inner node needs to have a child
-pointer altered. Any modification to a node will require a non-shared node.
+When a `SHAMap` needs to have a private copy of a node, not shared by any other `SHAMap`, it first clones it and then sets the new copy to have a sequence number equal to the `SHAMap` sequence number. The `unshareNode` is a private utility which automates the task of first checking if the node is already sharable, and if so, cloning it and giving it the proper sequence number. An example case where a private copy is needed is when an inner node needs to have a child pointer altered. Any modification to a node will require a non-shared node.
-When a `SHAMap` decides that it is safe to share a node of its own, it sets the
-node's sequence number to 0 (a `SHAMap` never has a sequence number of 0). This
-is done for every node in the trie when `SHAMap::walkSubTree` is executed.
+When a `SHAMap` decides that it is safe to share a node of its own, it sets the node's sequence number to 0 (a `SHAMap` never has a sequence number of 0). This is done for every node in the trie when `SHAMap::walkSubTree` is executed.
-Note that other objects in xrpld also have sequence numbers (e.g. ledgers).
-The `SHAMap` and node sequence numbers should not be confused with these other
-sequence numbers (no relation).
+Note that other objects in xrpld also have sequence numbers (e.g. ledgers). The `SHAMap` and node sequence numbers should not be confused with these other sequence numbers (no relation).
## SHAMap Creation
-A `SHAMap` is usually not created from vacuum. Once an initial `SHAMap` is
-constructed, later `SHAMap`s are usually created by calling snapShot(bool
-isMutable) on the original `SHAMap`. The returned `SHAMap` has the expected
-characteristics (mutable or immutable) based on the passed in flag.
+A `SHAMap` is usually not created from vacuum. Once an initial `SHAMap` is constructed, later `SHAMap`s are usually created by calling snapShot(bool isMutable) on the original `SHAMap`. The returned `SHAMap` has the expected characteristics (mutable or immutable) based on the passed in flag.
-It is cheaper to make an immutable snapshot of a `SHAMap` than to make a mutable
-snapshot. If the `SHAMap` snapshot is mutable then sharable nodes must be
-copied before they are placed in the mutable map.
+It is cheaper to make an immutable snapshot of a `SHAMap` than to make a mutable snapshot. If the `SHAMap` snapshot is mutable then sharable nodes must be copied before they are placed in the mutable map.
-A new `SHAMap` is created with each new ledger round. Transactions not executed
-in the previous ledger populate the `SHAMap` for the new ledger.
+A new `SHAMap` is created with each new ledger round. Transactions not executed in the previous ledger populate the `SHAMap` for the new ledger.
## Storing SHAMap data in the database
-When consensus is reached, the ledger is closed. As part of this process, the
-`SHAMap` is stored to the database by calling `SHAMap::flushDirty`.
+When consensus is reached, the ledger is closed. As part of this process, the `SHAMap` is stored to the database by calling `SHAMap::flushDirty`.
-Both `unshare()` and `flushDirty` walk the `SHAMap` by calling
-`SHAMap::walkSubTree`. As `unshare()` walks the trie, nodes are not written to
-the database, and as `flushDirty` walks the trie nodes are written to the
-database. `walkSubTree` visits every node in the trie. This process must ensure
-that each node is only owned by this trie, and so "unshares" as it walks each
-node (from the root down). This is done in the `preFlushNode` function by
-ensuring that the node has a sequence number equal to that of the `SHAMap`. If
-the node doesn't, it is cloned.
+Both `unshare()` and `flushDirty` walk the `SHAMap` by calling `SHAMap::walkSubTree`. As `unshare()` walks the trie, nodes are not written to the database, and as `flushDirty` walks the trie nodes are written to the database. `walkSubTree` visits every node in the trie. This process must ensure that each node is only owned by this trie, and so "unshares" as it walks each node (from the root down). This is done in the `preFlushNode` function by ensuring that the node has a sequence number equal to that of the `SHAMap`. If the node doesn't, it is cloned.
-For each inner node encountered (starting with the root node), each of the
-children are inspected (from 1 to 16). For each child, if it has a non-zero
-sequence number (unshareable), the child is first copied. Then if the child is
-an inner node, we recurse down to that node's children. Otherwise we've found a
-leaf node and that node is written to the database. A count of each leaf node
-that is visited is kept. The hash of the data in the leaf node is computed at
-this time, and the child is reassigned back into the parent inner node just in
-case the COW operation created a new pointer to this leaf node.
+For each inner node encountered (starting with the root node), each of the children are inspected (from 1 to 16). For each child, if it has a non-zero sequence number (unshareable), the child is first copied. Then if the child is an inner node, we recurse down to that node's children. Otherwise we've found a leaf node and that node is written to the database. A count of each leaf node that is visited is kept. The hash of the data in the leaf node is computed at this time, and the child is reassigned back into the parent inner node just in case the COW operation created a new pointer to this leaf node.
-After processing each node, the node is then marked as sharable again by setting
-its sequence number to 0.
+After processing each node, the node is then marked as sharable again by setting its sequence number to 0.
-After all of an inner node's children are processed, then its hash is updated
-and the inner node is written to the database. Then this inner node is assigned
-back into it's parent node, again in case the COW operation created a new
-pointer to it.
+After all of an inner node's children are processed, then its hash is updated and the inner node is written to the database. Then this inner node is assigned back into it's parent node, again in case the COW operation created a new pointer to it.
## Walking a SHAMap
-The private function `SHAMap::walkTowardsKey` is a good example of _how_ to walk
-a `SHAMap`, and the various functions that call `walkTowardsKey` are good examples
-of _why_ one would want to walk a `SHAMap` (e.g. `SHAMap::findKey`).
-`walkTowardsKey` always starts at the root of the `SHAMap` and traverses down
-through the inner nodes, looking for a leaf node along a path in the trie
-designated by a `uint256`.
+The private function `SHAMap::walkTowardsKey` is a good example of _how_ to walk a `SHAMap`, and the various functions that call `walkTowardsKey` are good examples of _why_ one would want to walk a `SHAMap` (e.g. `SHAMap::findKey`). `walkTowardsKey` always starts at the root of the `SHAMap` and traverses down through the inner nodes, looking for a leaf node along a path in the trie designated by a `uint256`.
-As one walks the trie, one can _optionally_ keep a stack of nodes that one has
-passed through. This isn't necessary for walking the trie, but many clients
-will use the stack after finding the desired node. For example if one is
-deleting a node from the trie, the stack is handy for repairing invariants in
-the trie after the deletion.
+As one walks the trie, one can _optionally_ keep a stack of nodes that one has passed through. This isn't necessary for walking the trie, but many clients will use the stack after finding the desired node. For example if one is deleting a node from the trie, the stack is handy for repairing invariants in the trie after the deletion.
-To assist in walking the trie, `SHAMap::walkTowardsKey` uses a `SHAMapNodeID`
-that identifies a node by its path from the root and its depth in the trie. The
-path is just a "list" of numbers, each in the range [0 .. 15], depicting which
-child was chosen at each node starting from the root. Each choice is represented
-by 4 bits, and then packed in sequence into a `uint256` (such that the longest
-path possible has 256 / 4 = 64 steps). The high 4 bits of the first byte
-identify which child of the root is chosen, the lower 4 bits of the first byte
-identify the child of that node, and so on. The `SHAMapNodeID` identifying the
-root node has an ID of 0 and a depth of 0. See `selectBranch` for details of
-how we use a `SHAMapNodeID` to select a "branch" (child) by indexing into a
-path at a given depth.
+To assist in walking the trie, `SHAMap::walkTowardsKey` uses a `SHAMapNodeID` that identifies a node by its path from the root and its depth in the trie. The path is just a "list" of numbers, each in the range [0 .. 15], depicting which child was chosen at each node starting from the root. Each choice is represented by 4 bits, and then packed in sequence into a `uint256` (such that the longest path possible has 256 / 4 = 64 steps). The high 4 bits of the first byte identify which child of the root is chosen, the lower 4 bits of the first byte identify the child of that node, and so on. The `SHAMapNodeID` identifying the root node has an ID of 0 and a depth of 0. See `selectBranch` for details of how we use a `SHAMapNodeID` to select a "branch" (child) by indexing into a path at a given depth.
-While the current node is an inner node, traversing down the trie from the root
-continues, unless the path indicates a child that does not exist. And in this
-case, `nullptr` is returned to indicate no leaf node along the given path
-exists. Otherwise a leaf node is found and a (non-owning) pointer to it is
-returned. At each step, if a stack is requested, a
-`pair, SHAMapNodeID>` is pushed onto the stack.
+While the current node is an inner node, traversing down the trie from the root continues, unless the path indicates a child that does not exist. And in this case, `nullptr` is returned to indicate no leaf node along the given path exists. Otherwise a leaf node is found and a (non-owning) pointer to it is returned. At each step, if a stack is requested, a `pair, SHAMapNodeID>` is pushed onto the stack.
-When a child node is found by `selectBranch`, the traversal to that node
-consists of two steps:
+When a child node is found by `selectBranch`, the traversal to that node consists of two steps:
1. Update the `shared_ptr` to the current node.
2. Update the `SHAMapNodeID`.
@@ -207,126 +111,79 @@ The first step consists of several attempts to find the node in various places:
2. In the node cache.
3. In the database.
-If the node is not found in the trie, then it is installed into the trie as part
-of the traversal process.
+If the node is not found in the trie, then it is installed into the trie as part of the traversal process.
## Late-arriving Nodes
-As we noted earlier, `SHAMap`s (even immutable ones) may grow. If a `SHAMap` is
-searching for a node and runs into an empty spot in the trie, then the `SHAMap`
-looks to see if the node exists but has not yet been made part of the map. This
-operation is performed in the `SHAMap::fetchNodeNT()` method. The _NT_
-is this case stands for 'No Throw'.
+As we noted earlier, `SHAMap`s (even immutable ones) may grow. If a `SHAMap` is searching for a node and runs into an empty spot in the trie, then the `SHAMap` looks to see if the node exists but has not yet been made part of the map. This operation is performed in the `SHAMap::fetchNodeNT()` method. The _NT_ is this case stands for 'No Throw'.
The `fetchNodeNT()` method goes through three phases:
-1. By calling `cacheLookup()` we attempt to locate the missing node in the
- TreeNodeCache. The TreeNodeCache is a cache of immutable SHAMapTreeNodes
- that are shared across all `SHAMap`s.
+1. By calling `cacheLookup()` we attempt to locate the missing node in the TreeNodeCache. The TreeNodeCache is a cache of immutable SHAMapTreeNodes that are shared across all `SHAMap`s.
- Any SHAMapLeafNode that is immutable has a sequence number of zero
- (sharable). When a mutable `SHAMap` is created then its SHAMapTreeNodes are
- given non-zero sequence numbers (unshareable). But all nodes in the
- TreeNodeCache are immutable, so if one is found here, its sequence number
- will be 0.
+ Any SHAMapLeafNode that is immutable has a sequence number of zero (sharable). When a mutable `SHAMap` is created then its SHAMapTreeNodes are given non-zero sequence numbers (unshareable). But all nodes in the TreeNodeCache are immutable, so if one is found here, its sequence number will be 0.
-2. If the node is not in the TreeNodeCache, we attempt to locate the node
- in the historic data stored by the data base. The call to
- `fetchNodeFromDB(hash)` does that work for us.
+2. If the node is not in the TreeNodeCache, we attempt to locate the node in the historic data stored by the data base. The call to `fetchNodeFromDB(hash)` does that work for us.
-3. Finally if a filter exists, we check if it can supply the node. This is
- typically the LedgerMaster which tracks the current ledger and ledgers
- in the process of closing.
+3. Finally if a filter exists, we check if it can supply the node. This is typically the LedgerMaster which tracks the current ledger and ledgers in the process of closing.
## Canonicalize
`canonicalize()` is called every time a node is introduced into the `SHAMap`.
-A call to `canonicalize()` stores the node in the `TreeNodeCache` if it does not
-already exist in the `TreeNodeCache`.
+A call to `canonicalize()` stores the node in the `TreeNodeCache` if it does not already exist in the `TreeNodeCache`.
-The calls to `canonicalize()` make sure that if the resulting node is already in
-the `SHAMap`, node `TreeNodeCache` or database, then we don't create duplicates
-by favoring the copy already in the `TreeNodeCache`.
+The calls to `canonicalize()` make sure that if the resulting node is already in the `SHAMap`, node `TreeNodeCache` or database, then we don't create duplicates by favoring the copy already in the `TreeNodeCache`.
-By using `canonicalize()` we manage a thread race condition where two different
-threads might both recognize the lack of a SHAMapLeafNode at the same time
-(during a fetch). If they both attempt to insert the node into the `SHAMap`, then
-`canonicalize` makes sure that the first node in wins and the slower thread
-receives back a pointer to the node inserted by the faster thread. Recall
-that these two `SHAMap`s will share the same `TreeNodeCache`.
+By using `canonicalize()` we manage a thread race condition where two different threads might both recognize the lack of a SHAMapLeafNode at the same time (during a fetch). If they both attempt to insert the node into the `SHAMap`, then `canonicalize` makes sure that the first node in wins and the slower thread receives back a pointer to the node inserted by the faster thread. Recall that these two `SHAMap`s will share the same `TreeNodeCache`.
## `TreeNodeCache`
-The `TreeNodeCache` is a `std::unordered_map` keyed on the hash of the
-`SHAMap` node. The stored type consists of `shared_ptr`,
-`weak_ptr`, and a time point indicating the most recent
-access of this node in the cache. The time point is based on
-`std::chrono::steady_clock`.
+The `TreeNodeCache` is a `std::unordered_map` keyed on the hash of the `SHAMap` node. The stored type consists of `shared_ptr`, `weak_ptr`, and a time point indicating the most recent access of this node in the cache. The time point is based on `std::chrono::steady_clock`.
The container uses a cryptographically secure hash that is randomly seeded.
-The `TreeNodeCache` also carries with it various data used for statistics
-and logging, and a target age for the contained nodes. When the target age
-for a node is exceeded, and there are no more references to the node, the
-node is removed from the `TreeNodeCache`.
+The `TreeNodeCache` also carries with it various data used for statistics and logging, and a target age for the contained nodes. When the target age for a node is exceeded, and there are no more references to the node, the node is removed from the `TreeNodeCache`.
## `FullBelowCache`
-This cache remembers which trie keys have all of their children resident in a
-`SHAMap`. This optimizes the process of acquiring a complete trie. This is used
-when creating the missing nodes list. Missing nodes are those nodes that a
-`SHAMap` refers to but that are not stored in the local database.
+This cache remembers which trie keys have all of their children resident in a `SHAMap`. This optimizes the process of acquiring a complete trie. This is used when creating the missing nodes list. Missing nodes are those nodes that a `SHAMap` refers to but that are not stored in the local database.
-As a depth-first walk of a `SHAMap` is performed, if an inner node answers true to
-`isFullBelow()` then it is known that none of this node's children are missing
-nodes, and thus that subtree does not need to be walked. These nodes are stored
-in the FullBelowCache. Subsequent walks check the FullBelowCache first when
-encountering a node, and ignore that subtree if found.
+As a depth-first walk of a `SHAMap` is performed, if an inner node answers true to `isFullBelow()` then it is known that none of this node's children are missing nodes, and thus that subtree does not need to be walked. These nodes are stored in the FullBelowCache. Subsequent walks check the FullBelowCache first when encountering a node, and ignore that subtree if found.
## `SHAMapTreeNode`
-This is an abstract base class for the concrete node types. It holds the
-following common data:
+This is an abstract base class for the concrete node types. It holds the following common data:
1. A hash
2. An identifier used to perform copy-on-write operations
### `SHAMapInnerNode`
-`SHAMapInnerNode` publicly inherits directly from `SHAMapTreeNode`. It holds
-the following data:
+`SHAMapInnerNode` publicly inherits directly from `SHAMapTreeNode`. It holds the following data:
1. Up to 16 child nodes, each held with a shared_ptr.
2. A hash for each child.
3. A bitset to indicate which of the 16 children exist.
-4. An identifier used to determine whether the map below this node is
- fully populated
+4. An identifier used to determine whether the map below this node is fully populated
### `SHAMapLeafNode`
-`SHAMapLeafNode` is an abstract class which publicly inherits directly from
-`SHAMapTreeNode`. It isIt holds the
-following data:
+`SHAMapLeafNode` is an abstract class which publicly inherits directly from `SHAMapTreeNode`. It isIt holds the following data:
1. A shared_ptr to a const SHAMapItem.
#### `SHAMapAccountStateLeafNode`
-`SHAMapAccountStateLeafNode` is a class which publicly inherits directly from
-`SHAMapLeafNode`. It is used to represent entries (i.e. account objects, escrow
-objects, trust lines, etc.) in a state map.
+`SHAMapAccountStateLeafNode` is a class which publicly inherits directly from `SHAMapLeafNode`. It is used to represent entries (i.e. account objects, escrow objects, trust lines, etc.) in a state map.
#### `SHAMapTxLeafNode`
-`SHAMapTxLeafNode` is a class which publicly inherits directly from
-`SHAMapLeafNode`. It is used to represent transactions in a state map.
+`SHAMapTxLeafNode` is a class which publicly inherits directly from `SHAMapLeafNode`. It is used to represent transactions in a state map.
#### `SHAMapTxPlusMetaLeafNode`
-`SHAMapTxPlusMetaLeafNode` is a class which publicly inherits directly from
-`SHAMapLeafNode`. It is used to represent transactions along with metadata
-associated with this transaction in a state map.
+`SHAMapTxPlusMetaLeafNode` is a class which publicly inherits directly from `SHAMapLeafNode`. It is used to represent transactions along with metadata associated with this transaction in a state map.
## SHAMapItem
diff --git a/nix/check-tools/README.md b/nix/check-tools/README.md
index f23b2dcc21..5ba3448ad0 100644
--- a/nix/check-tools/README.md
+++ b/nix/check-tools/README.md
@@ -1,8 +1,6 @@
# check-tools snapshots
-These files capture the output of [`bin/check-tools.sh`](../../bin/check-tools.sh)
-— the version and resolved store path of each development tool — in each Nix
-environment:
+These files capture the output of [`bin/check-tools.sh`](../../bin/check-tools.sh) — the version and resolved store path of each development tool — in each Nix environment:
| File | Environment |
| ---------------------- | ------------------------------------ |
@@ -10,26 +8,15 @@ environment:
| `nix-ubuntu-arm64.txt` | `nix-ubuntu` CI image, `linux/arm64` |
| `macos.txt` | macOS, inside `nix develop` |
-The [`check-tools`](../../.github/workflows/check-tools.yml) workflow regenerates
-each snapshot in its environment and fails if it differs from the committed file.
-So if you change the environment (bump the image tag in
-[`linux.json`](../../.github/scripts/strategy-matrix/linux.json), update
-`flake.lock`, change the tool list in `check-tools.sh`, …) you must regenerate
-and commit the affected snapshots.
+The [`check-tools`](../../.github/workflows/check-tools.yml) workflow regenerates each snapshot in its environment and fails if it differs from the committed file. So if you change the environment (bump the image tag in [`linux.json`](../../.github/scripts/strategy-matrix/linux.json), update `flake.lock`, change the tool list in `check-tools.sh`, …) you must regenerate and commit the affected snapshots.
-Each snapshot is `check-tools.sh` stdout with the git-clone connectivity check
-skipped (`CHECK_TOOLS_SKIP_CLONE=1`), so it is deterministic for a given
-environment. On macOS the dev-shell greeting that `nix develop` prints first is
-dropped with `sed -n '/^Detected OS:/,$p'`.
+Each snapshot is `check-tools.sh` stdout with the git-clone connectivity check skipped (`CHECK_TOOLS_SKIP_CLONE=1`), so it is deterministic for a given environment. On macOS the dev-shell greeting that `nix develop` prints first is dropped with `sed -n '/^Detected OS:/,$p'`.
-The store paths carry their derivation hash, so they change whenever a tool is
-rebuilt — a `flake.lock` update generally rewrites most of them even when no
-version moves. That is deliberate: it makes tooling changes visible in review.
+The store paths carry their derivation hash, so they change whenever a tool is rebuilt — a `flake.lock` update generally rewrites most of them even when no version moves. That is deliberate: it makes tooling changes visible in review.
## Regenerating
-The two Linux snapshots come from the `nix-ubuntu` image (Docker or a compatible
-runtime such as Apple `container`). The image tag is pinned in `linux.json`:
+The two Linux snapshots come from the `nix-ubuntu` image (Docker or a compatible runtime such as Apple `container`). The image tag is pinned in `linux.json`:
```bash
img="ghcr.io/xrplf/xrpld/nix-ubuntu:$(jq -r .image_tag .github/scripts/strategy-matrix/linux.json)"
@@ -40,12 +27,9 @@ for arch in amd64 arm64; do
done
```
-(With Docker, replace `container run … -a "${arch}"` with
-`docker run … --platform "linux/${arch}"`.)
+(With Docker, replace `container run … -a "${arch}"` with `docker run … --platform "linux/${arch}"`.)
-The macOS snapshot is generated locally. `CI=` is unset so `check-tools.sh`
-checks the full dev-shell tool set (it otherwise skips some tools when `CI` is
-set):
+The macOS snapshot is generated locally. `CI=` is unset so `check-tools.sh` checks the full dev-shell tool set (it otherwise skips some tools when `CI` is set):
```bash
CI= nix develop -c bash -c 'CHECK_TOOLS_SKIP_CLONE=1 bash bin/check-tools.sh' |
diff --git a/nix/docker/README.md b/nix/docker/README.md
index 06e3cd4ea3..5da28865c5 100644
--- a/nix/docker/README.md
+++ b/nix/docker/README.md
@@ -1,101 +1,52 @@
# Nix CI Docker images
-This directory builds the Docker images used by xrpld's Linux CI. Each image
-bundles the **exact same toolchain that the Nix development shell provides**
-(see [`docs/build/nix.md`](../../docs/build/nix.md)), so what runs in CI matches
-what developers get locally from `nix develop`.
+This directory builds the Docker images used by xrpld's Linux CI. Each image bundles the **exact same toolchain that the Nix development shell provides** (see [`docs/build/nix.md`](../../docs/build/nix.md)), so what runs in CI matches what developers get locally from `nix develop`.
-The toolchain (CMake, Ninja, Conan, GCC, Clang, clang-tidy, the
-sanitizer/coverage tools, …) is defined in [`nix/packages.nix`](../packages.nix)
-and assembled for CI by [`nix/ci-env.nix`](../ci-env.nix). The Docker build
-turns that Nix environment into an ordinary container image layered on top of a
-conventional base image (Ubuntu, Debian, RHEL, or `nixos/nix`).
+The toolchain (CMake, Ninja, Conan, GCC, Clang, clang-tidy, the sanitizer/coverage tools, …) is defined in [`nix/packages.nix`](../packages.nix) and assembled for CI by [`nix/ci-env.nix`](../ci-env.nix). The Docker build turns that Nix environment into an ordinary container image layered on top of a conventional base image (Ubuntu, Debian, RHEL, or `nixos/nix`).
## Images
-The images are built by the [`build-nix-images.yml`](../../.github/workflows/build-nix-images.yml)
-workflow and pushed to `ghcr.io/xrplf/xrpld/nix-`. The `` is
-selected through the `BASE_IMAGE` build argument; the base images are the
-**oldest supported version** of each distribution we target:
+The images are built by the [`build-nix-images.yml`](../../.github/workflows/build-nix-images.yml) workflow and pushed to `ghcr.io/xrplf/xrpld/nix-`. The `` is selected through the `BASE_IMAGE` build argument; the base images are the **oldest supported version** of each distribution we target:
-| Image | `BASE_IMAGE` | Notes |
-| ------------ | -------------------------------------------- | -------------------------------------------------- |
-| `nix-nixos` | `nixos/nix:latest` | Build/lint only; binaries are not run (see below). |
-| `nix-ubuntu` | `ubuntu:20.04` | Oldest supported Ubuntu (glibc 2.31). |
-| `nix-debian` | `debian:bookworm` | |
-| `nix-rhel` | `registry.access.redhat.com/ubi9/ubi:latest` | |
+| Image | `BASE_IMAGE` | Notes |
+| --- | --- | --- |
+| `nix-nixos` | `nixos/nix:latest` | Build/lint only; binaries are not run (see below). |
+| `nix-ubuntu` | `ubuntu:20.04` | Oldest supported Ubuntu (glibc 2.31). |
+| `nix-debian` | `debian:bookworm` | |
+| `nix-rhel` | `registry.access.redhat.com/ubi9/ubi:latest` | |
-All images carry the full toolchain on `PATH` (via `/nix/ci-env/bin`) plus the
-CA bundle shipped in the Nix environment, so HTTPS clients (git, curl, Conan)
-work without `ca-certificates` being installed in the base image.
+All images carry the full toolchain on `PATH` (via `/nix/ci-env/bin`) plus the CA bundle shipped in the Nix environment, so HTTPS clients (git, curl, Conan) work without `ca-certificates` being installed in the base image.
## Build stages
[`Dockerfile`](./Dockerfile) is a multi-stage build:
-1. **`builder`** — On a `nixos/nix` builder, evaluate the flake and build the
- CI environment (`nix/ci-env.nix`). The resulting Nix store closure (the
- complete set of store paths the toolchain depends on) is copied into a
- staging directory.
-2. **`final`** — Start from `BASE_IMAGE`, copy in the Nix store closure and the
- `ci-env` symlink tree, and wire up `PATH` and the CA bundle. It then:
- - installs the dynamic linker if the base image lacks one (see
- [How libc is handled](#how-libc-is-handled)),
- - runs [`bin/check-tools.sh`](../../bin/check-tools.sh) to verify every
- expected tool is present and runnable.
- - compiles the C++ test programs in
- [`test_files/cpp/sources/`](./test_files/cpp/sources) with both `g++` and
- `clang++`, and sanitizers, and
- - compiles the Rust test programs in
- [`test_files/rust/sources/`](./test_files/rust/sources) with `rustc`, and
- builds the [`test_files/rust/proc_macro/`](./test_files/rust/proc_macro)
- workspace with `cargo` to exercise proc-macro dylib loading.
-3. **`tester`** — Start again from a clean `BASE_IMAGE` (no Nix toolchain),
- install only the sanitizer runtime libraries
- ([`install-sanitizer-libs.sh`](./install-sanitizer-libs.sh)), and run the
- binaries compiled in `final`. This proves the binaries built with the Nix
- toolchain actually run on a vanilla base image. On `nixos/nix` this step is
- skipped (the binaries are patched for a conventional FHS loader).
-4. **Output** — The final image is gated on the tester succeeding: it copies a
- sentinel file out of `tester`, so a failed test run fails the whole build.
+1. **`builder`** — On a `nixos/nix` builder, evaluate the flake and build the CI environment (`nix/ci-env.nix`). The resulting Nix store closure (the complete set of store paths the toolchain depends on) is copied into a staging directory.
+2. **`final`** — Start from `BASE_IMAGE`, copy in the Nix store closure and the `ci-env` symlink tree, and wire up `PATH` and the CA bundle. It then:
+ - installs the dynamic linker if the base image lacks one (see [How libc is handled](#how-libc-is-handled)),
+ - runs [`bin/check-tools.sh`](../../bin/check-tools.sh) to verify every expected tool is present and runnable.
+ - compiles the C++ test programs in [`test_files/cpp/sources/`](./test_files/cpp/sources) with both `g++` and `clang++`, and sanitizers, and
+ - compiles the Rust test programs in [`test_files/rust/sources/`](./test_files/rust/sources) with `rustc`, and builds the [`test_files/rust/proc_macro/`](./test_files/rust/proc_macro) workspace with `cargo` to exercise proc-macro dylib loading.
+3. **`tester`** — Start again from a clean `BASE_IMAGE` (no Nix toolchain), install only the sanitizer runtime libraries ([`install-sanitizer-libs.sh`](./install-sanitizer-libs.sh)), and run the binaries compiled in `final`. This proves the binaries built with the Nix toolchain actually run on a vanilla base image. On `nixos/nix` this step is skipped (the binaries are patched for a conventional FHS loader).
+4. **Output** — The final image is gated on the tester succeeding: it copies a sentinel file out of `tester`, so a failed test run fails the whole build.
## How libc is handled
-The goal is for binaries built in these images to run on the **oldest supported
-base image** (Ubuntu 20.04, glibc 2.31) and newer — without the developer's Nix
-toolchain being present at runtime. Two pieces make that work:
+The goal is for binaries built in these images to run on the **oldest supported base image** (Ubuntu 20.04, glibc 2.31) and newer — without the developer's Nix toolchain being present at runtime. Two pieces make that work:
-- **Compilers linked against an old glibc.** The Nix CI environment does not use
- nixpkgs' current glibc. Instead it pins a 2020 nixpkgs snapshot whose primary
- glibc is **2.31** (matching Ubuntu 20.04), via the `nixpkgs-custom-glibc`
- flake input. GCC, Clang, binutils and compiler-rt are all rebuilt/wrapped
- against this custom glibc (see [`nix/ci-env.nix`](../ci-env.nix)). As a result
- the libraries they emit (`libstdc++`, `libgcc_s`, the sanitizer runtimes)
- reference only symbols available in glibc 2.31.
+- **Compilers linked against an old glibc.** The Nix CI environment does not use nixpkgs' current glibc. Instead it pins a 2020 nixpkgs snapshot whose primary glibc is **2.31** (matching Ubuntu 20.04), via the `nixpkgs-custom-glibc` flake input. GCC, Clang, binutils and compiler-rt are all rebuilt/wrapped against this custom glibc (see [`nix/ci-env.nix`](../ci-env.nix)). As a result the libraries they emit (`libstdc++`, `libgcc_s`, the sanitizer runtimes) reference only symbols available in glibc 2.31.
-- **An expected dynamic linker in the image.**
- Binaries built in Nix environments reference a dynamic linker from Nix store paths, which won't be present in the base image. However,
- [`bin/default-loader-path.sh`](../../bin/default-loader-path.sh) reports the
- expected loader path for the current architecture, so we can patch the binaries
- to use the correct loader.
+- **An expected dynamic linker in the image.** Binaries built in Nix environments reference a dynamic linker from Nix store paths, which won't be present in the base image. However, [`bin/default-loader-path.sh`](../../bin/default-loader-path.sh) reports the expected loader path for the current architecture, so we can patch the binaries to use the correct loader.
-The build then verifies all of this end to end, and the C++ and Rust programs
-go through the same pipeline: each is compiled in `final`, has its `PT_INTERP`
-patched to the target loader, and is then run in the clean `tester` stage to
-confirm it emits the expected diagnostic on a stock base image. The C++ programs
-are in `test_files/cpp/sources/` (a regular binary plus ASan/TSan/UBSan
-variants); the Rust programs are in `test_files/rust/sources/` (a hello binary
-plus panic and overflow-check variants), plus the `test_files/rust/proc_macro/`
-workspace — a crate whose compilation additionally loads a proc-macro dylib, and
-whose resulting binary is patched and run like the others.
+The build then verifies all of this end to end, and the C++ and Rust programs go through the same pipeline: each is compiled in `final`, has its `PT_INTERP` patched to the target loader, and is then run in the clean `tester` stage to confirm it emits the expected diagnostic on a stock base image. The C++ programs are in `test_files/cpp/sources/` (a regular binary plus ASan/TSan/UBSan variants); the Rust programs are in `test_files/rust/sources/` (a hello binary plus panic and overflow-check variants), plus the `test_files/rust/proc_macro/` workspace — a crate whose compilation additionally loads a proc-macro dylib, and whose resulting binary is patched and run like the others.
## Files
-| File | Purpose |
-| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
-| [`./Dockerfile`](./Dockerfile) | Multi-stage build described above. |
-| [`./test_files/cpp/`](./test_files/cpp) | C++ sanitizer smoke test: sources + compile/run scripts. |
-| [`./test_files/rust/`](./test_files/rust) | Rust smoke test: rustc sources + a cargo proc-macro workspace + compile/run scripts. |
-| [`/bin/check-tools.sh`](../../bin/check-tools.sh) | Verify every expected tools are present and runnable. |
-| [`/bin/default-loader-path.sh`](../../bin/default-loader-path.sh) | Print the dynamic-linker (`PT_INTERP`) path for the current architecture. |
-| [`/bin/install-sanitizer-libs.sh`](../../bin/install-sanitizer-libs.sh) | Install `libasan`/`libtsan`/`libubsan` runtimes on the supported base images. |
+| File | Purpose |
+| --- | --- |
+| [`./Dockerfile`](./Dockerfile) | Multi-stage build described above. |
+| [`./test_files/cpp/`](./test_files/cpp) | C++ sanitizer smoke test: sources + compile/run scripts. |
+| [`./test_files/rust/`](./test_files/rust) | Rust smoke test: rustc sources + a cargo proc-macro workspace + compile/run scripts. |
+| [`/bin/check-tools.sh`](../../bin/check-tools.sh) | Verify every expected tools are present and runnable. |
+| [`/bin/default-loader-path.sh`](../../bin/default-loader-path.sh) | Print the dynamic-linker (`PT_INTERP`) path for the current architecture. |
+| [`/bin/install-sanitizer-libs.sh`](../../bin/install-sanitizer-libs.sh) | Install `libasan`/`libtsan`/`libubsan` runtimes on the supported base images. |
diff --git a/package/README.md b/package/README.md
index 027a374898..34c693b051 100644
--- a/package/README.md
+++ b/package/README.md
@@ -1,8 +1,6 @@
# Linux Packaging
-This directory contains all files needed to build RPM and Debian packages for
-`xrpld`. The packages also ship the `validator-keys` tool, so packaging requires
-a build configured with `-Dvalidator_keys=ON`.
+This directory contains all files needed to build RPM and Debian packages for `xrpld`. The packages also ship the `validator-keys` tool, so packaging requires a build configured with `-Dvalidator_keys=ON`.
## Directory layout
@@ -25,22 +23,14 @@ package/
## Prerequisites
-Packaging is declared on the build configs themselves, in
-[`.github/scripts/strategy-matrix/linux.json`](../.github/scripts/strategy-matrix/linux.json):
-a config that is also packaged carries a `package` map, so its binaries and its
-packaging job cannot drift apart. Today only `linux/amd64` is emitted. The map
-pins the full container image in `image` — edit that field to move to a new
-image and both CI and local builds pick it up — and names the format that image
-builds in `type`, which CI passes to `build_pkg.py` as `--package-type`; the two
-have to stay in step.
+Packaging is declared on the build configs themselves, in [`.github/scripts/strategy-matrix/linux.json`](../.github/scripts/strategy-matrix/linux.json): a config that is also packaged carries a `package` map, so its binaries and its packaging job cannot drift apart. Today only `linux/amd64` is emitted. The map pins the full container image in `image` — edit that field to move to a new image and both CI and local builds pick it up — and names the format that image builds in `type`, which CI passes to `build_pkg.py` as `--package-type`; the two have to stay in step.
-| Package type | Image (`configs.[].package.image` in `linux.json`) | Tools required |
-| ------------ | ---------------------------------------------------------- | --------------------------------------------------- |
-| RPM | `ghcr.io/xrplf/xrpld/packaging-rhel:sha-` | `rpmbuild`, `rpmsign` |
-| DEB | `ghcr.io/xrplf/xrpld/packaging-debian:sha-` | `dpkg-buildpackage`, debhelper with compat level 13 |
+| Package type | Image (`configs.[].package.image` in `linux.json`) | Tools required |
+| --- | --- | --- |
+| RPM | `ghcr.io/xrplf/xrpld/packaging-rhel:sha-` | `rpmbuild`, `rpmsign` |
+| DEB | `ghcr.io/xrplf/xrpld/packaging-debian:sha-` | `dpkg-buildpackage`, debhelper with compat level 13 |
-To print the full packaging matrix (artifact names and images) for the current
-`linux.json`:
+To print the full packaging matrix (artifact names and images) for the current `linux.json`:
```bash
./.github/scripts/strategy-matrix/generate.py --packaging
@@ -50,32 +40,15 @@ To print the full packaging matrix (artifact names and images) for the current
### Via CI
-Caller workflows (`on-pr.yml`, `on-tag.yml`, `on-trigger.yml`) call
-`reusable-package.yml`. That workflow generates its own packaging matrix from
-the configs that carry a `package` map (via `generate.py --packaging`) and fans
-out one job per distro. Each job downloads the pre-built `xrpld` and
-`validator-keys` binary artifacts and runs in that distro's container, building
-the format `package.type` declares. The packaging script derives the package
-version from the downloaded binary's `xrpld --version` output; no CMake
-configure or build step is needed inside the packaging job.
+Caller workflows (`on-pr.yml`, `on-tag.yml`, `on-trigger.yml`) call `reusable-package.yml`. That workflow generates its own packaging matrix from the configs that carry a `package` map (via `generate.py --packaging`) and fans out one job per distro. Each job downloads the pre-built `xrpld` and `validator-keys` binary artifacts and runs in that distro's container, building the format `package.type` declares. The packaging script derives the package version from the downloaded binary's `xrpld --version` output; no CMake configure or build step is needed inside the packaging job.
-The binaries come from the `debian` and `rhel` build configs themselves — the
-ones carrying the `package` map — which pass `-Dvalidator_keys=ON` so that the
-build job produces `validator-keys` next to `xrpld` and uploads it as the
-`validator-keys-` artifact. The packaging matrix names both
-artifacts (`xrpld_artifact_name` and `validator_keys_artifact_name`) after that
-same config, so a packaged config must keep `-Dvalidator_keys=ON`. Those configs
-are not `minimal`, so `on-pr.yml` only packages once a PR runs the full matrix.
+The binaries come from the `debian` and `rhel` build configs themselves — the ones carrying the `package` map — which pass `-Dvalidator_keys=ON` so that the build job produces `validator-keys` next to `xrpld` and uploads it as the `validator-keys-` artifact. The packaging matrix names both artifacts (`xrpld_artifact_name` and `validator_keys_artifact_name`) after that same config, so a packaged config must keep `-Dvalidator_keys=ON`. Those configs are not `minimal`, so `on-pr.yml` only packages once a PR runs the full matrix.
-`validator-keys` is fetched from an exact commit pinned in
-[`cmake/XrplValidatorKeys.cmake`](../cmake/XrplValidatorKeys.cmake), so a given
-`xrpld` version always packages the same tool; bump that commit deliberately.
+`validator-keys` is fetched from an exact commit pinned in [`cmake/XrplValidatorKeys.cmake`](../cmake/XrplValidatorKeys.cmake), so a given `xrpld` version always packages the same tool; bump that commit deliberately.
### Locally (mirrors CI)
-With `xrpld` and `validator-keys` binaries already built at `build/xrpld` and
-`build/validator-keys`, run the packaging step inside the same container CI uses.
-The image tag is derived from `linux.json` so you don't need to hardcode a SHA.
+With `xrpld` and `validator-keys` binaries already built at `build/xrpld` and `build/validator-keys`, run the packaging step inside the same container CI uses. The image tag is derived from `linux.json` so you don't need to hardcode a SHA.
```bash
# From the repo root. Each distro's container image is the `package.image` field
@@ -101,9 +74,7 @@ docker run --rm \
### Via CMake (host-side target)
-If you run CMake configure on a host that has `rpmbuild` or `dpkg-buildpackage`
-installed natively, you can use the CMake target directly — no container
-needed, but the host toolchain replaces the pinned CI image:
+If you run CMake configure on a host that has `rpmbuild` or `dpkg-buildpackage` installed natively, you can use the CMake target directly — no container needed, but the host toolchain replaces the pinned CI image:
```bash
cmake \
@@ -116,101 +87,49 @@ cmake \
cmake --build . --target package # deb on Debian/Ubuntu, rpm on RHEL
```
-The `cmake/XrplPackaging.cmake` module defines the `package` target only if at
-least one of `rpmbuild` / `dpkg-buildpackage` is present and both the `xrpld` and
-`validator-keys` targets exist (`-Dxrpld=ON -Dvalidator_keys=ON`); the target
-builds both binaries before packaging, passing `--package-type deb` when
-`dpkg-buildpackage` is present and `rpm` otherwise, and `--channel UNRELEASED`.
-The packaging script installs to FHS-standard paths (`/usr/bin`, `/etc/xrpld`,
-etc.) regardless of `CMAKE_INSTALL_PREFIX`.
+The `cmake/XrplPackaging.cmake` module defines the `package` target only if at least one of `rpmbuild` / `dpkg-buildpackage` is present and both the `xrpld` and `validator-keys` targets exist (`-Dxrpld=ON -Dvalidator_keys=ON`); the target builds both binaries before packaging, passing `--package-type deb` when `dpkg-buildpackage` is present and `rpm` otherwise, and `--channel UNRELEASED`. The packaging script installs to FHS-standard paths (`/usr/bin`, `/etc/xrpld`, etc.) regardless of `CMAKE_INSTALL_PREFIX`.
-The package version is not a CMake input on this path: `build_pkg.py` derives it
-from the just-built `xrpld` binary's `xrpld --version` output. The package
-release defaults to 1 and is overridable with `-Dpkg_release=N`.
+The package version is not a CMake input on this path: `build_pkg.py` derives it from the just-built `xrpld` binary's `xrpld --version` output. The package release defaults to 1 and is overridable with `-Dpkg_release=N`.
## Publishing packages
-Packages are published to the XRPLF repositories on Sonatype Nexus at
-`https://packages.xrplf.org`. The `release-info` action decides the channel from
-the event, and `publish_pkg.py` maps that channel to its repositories:
+Packages are published to the XRPLF repositories on Sonatype Nexus at `https://packages.xrplf.org`. The `release-info` action decides the channel from the event, and `publish_pkg.py` maps that channel to its repositories:
-| Event | Version | Channel | DEB repository | RPM upload repository |
-| ------------------------ | ----------------- | --------- | -------------- | --------------------- |
-| tag | `X.Y.Z` | `stable` | `deb-stable` | `rpm-stable-hosted` |
-| tag | `X.Y.Z-rcN` | `rc` | `deb-rc` | `rpm-rc-hosted` |
-| tag | `X.Y.Z-bN` | `beta` | `deb-beta` | `rpm-beta-hosted` |
-| push to `develop` | `xrpld --version` | `develop` | `deb-develop` | `rpm-develop-hosted` |
-| tag, non-public codebase | _any_ | `private` | `deb-private` | `rpm-private-hosted` |
+| Event | Version | Channel | DEB repository | RPM upload repository |
+| --- | --- | --- | --- | --- |
+| tag | `X.Y.Z` | `stable` | `deb-stable` | `rpm-stable-hosted` |
+| tag | `X.Y.Z-rcN` | `rc` | `deb-rc` | `rpm-rc-hosted` |
+| tag | `X.Y.Z-bN` | `beta` | `deb-beta` | `rpm-beta-hosted` |
+| push to `develop` | `xrpld --version` | `develop` | `deb-develop` | `rpm-develop-hosted` |
+| tag, non-public codebase | _any_ | `private` | `deb-private` | `rpm-private-hosted` |
-Only a tag names a channel — do not extend that to `develop`, where
-`BuildInfo.cpp`'s `versionString` moves through `-bN`, `-rcN` and even the final
-version during a release cycle, which would send develop builds into `stable`.
-Versions sort in row order, so moving to a more mature channel never downgrades.
+Only a tag names a channel — do not extend that to `develop`, where `BuildInfo.cpp`'s `versionString` moves through `-bN`, `-rcN` and even the final version during a release cycle, which would send develop builds into `stable`. Versions sort in row order, so moving to a more mature channel never downgrades.
-The action decides the package release number on the same split: a tag's version
-is unique, so its packages are release 1, while develop repeats the same version
-and takes `.git`, e.g.
-`857.20260826gitb6a8995` — the leading run number keeps each push superseding
-the last, and the date and hash say which commit a package on
-`packages.xrplf.org` came from. Both reach the packaging scripts as arguments,
-so neither script derives anything itself.
+The action decides the package release number on the same split: a tag's version is unique, so its packages are release 1, while develop repeats the same version and takes `.git`, e.g. `857.20260826gitb6a8995` — the leading run number keeps each push superseding the last, and the date and hash say which commit a package on `packages.xrplf.org` came from. Both reach the packaging scripts as arguments, so neither script derives anything itself.
-Publishing is the last step of each packaging job, uploading from the container
-that built the packages with the `publish_pkg.py` shipped in the image — the
-same copy other repositories run. Without `publish: true` the step is a
-`--dry-run`, listing the uploads it would make without needing credentials, so
-any run that builds packages also exercises the upload routing. `on-trigger.yml`
-passes `publish: true` for develop pushes in `XRPLF/rippled` and `on-tag.yml`
-for tags in any `XRPLF` repository, both authenticating with the
-`NEXUS_REMOTE_USERNAME` / `NEXUS_REMOTE_PASSWORD` secrets already used for the
-Conan remote; `on-pr.yml` never publishes.
+Publishing is the last step of each packaging job, uploading from the container that built the packages with the `publish_pkg.py` shipped in the image — the same copy other repositories run. Without `publish: true` the step is a `--dry-run`, listing the uploads it would make without needing credentials, so any run that builds packages also exercises the upload routing. `on-trigger.yml` passes `publish: true` for develop pushes in `XRPLF/rippled` and `on-tag.yml` for tags in any `XRPLF` repository, both authenticating with the `NEXUS_REMOTE_USERNAME` / `NEXUS_REMOTE_PASSWORD` secrets already used for the Conan remote; `on-pr.yml` never publishes.
Nexus owns the repository metadata; nothing here indexes anything. Worth knowing:
-- Each apt-hosted repository needs a distribution (ours use `any`) and a PGP
- signing keypair configured in Nexus, which rejects one created without a
- keypair. Nexus signs the apt metadata with it, never the packages.
-- Hosted yum repositories cannot be signed by Nexus, so each `rpm--hosted`
- repository sits behind a `rpm-` yum group repository whose metadata
- Nexus signs. Uploads go to the hosted repository; clients point at the group
- and verify the metadata with `repo_gpgcheck=1`. Nexus never signs the RPMs
- themselves, so `sign_rpm.py` signs them before they are uploaded, and clients
- verify them with `gpgcheck=1`.
-- yum metadata is rebuilt asynchronously, so a successful publish is not
- immediately installable.
-- Each job uploads only what it built, and uploads are not transactional, so a
- failure can leave one format published alone. Re-running is safe: both the apt
- POST and the yum PUT replace an existing asset.
-- The `develop` repositories gain a package per push, so they need a cleanup
- policy to stay bounded; tagged channels publish each version once.
+- Each apt-hosted repository needs a distribution (ours use `any`) and a PGP signing keypair configured in Nexus, which rejects one created without a keypair. Nexus signs the apt metadata with it, never the packages.
+- Hosted yum repositories cannot be signed by Nexus, so each `rpm--hosted` repository sits behind a `rpm-` yum group repository whose metadata Nexus signs. Uploads go to the hosted repository; clients point at the group and verify the metadata with `repo_gpgcheck=1`. Nexus never signs the RPMs themselves, so `sign_rpm.py` signs them before they are uploaded, and clients verify them with `gpgcheck=1`.
+- yum metadata is rebuilt asynchronously, so a successful publish is not immediately installable.
+- Each job uploads only what it built, and uploads are not transactional, so a failure can leave one format published alone. Re-running is safe: both the apt POST and the yum PUT replace an existing asset.
+- The `develop` repositories gain a package per push, so they need a cleanup policy to stay bounded; tagged channels publish each version once.
### Publishing from other repositories
-`publish_pkg.py` knows nothing about `xrpld`, so the packaging image
-installs it at `/usr/local/bin/publish_pkg.py` for other XRPLF repositories that
-build their packages elsewhere.
+`publish_pkg.py` knows nothing about `xrpld`, so the packaging image installs it at `/usr/local/bin/publish_pkg.py` for other XRPLF repositories that build their packages elsewhere.
## How `build_pkg.py` works
-`build_pkg.py` derives the `xrpld` software version from
-`${BUILD_DIR}/xrpld --version` in both package formats.
+`build_pkg.py` derives the `xrpld` software version from `${BUILD_DIR}/xrpld --version` in both package formats.
-The binary's version is already SemVer-validated by `BuildInfo`.
-`build_pkg.py` converts pre-release versions such as `3.2.0-b1` or
-`3.2.0-rc1` from `-` to `~` for package metadata so pre-releases sort before
-the final release. If that normalized package version still contains `-`,
-packaging fails because RPM forbids `-` in `Version`, and Debian uses `-` as
-the upstream/revision separator.
+The binary's version is already SemVer-validated by `BuildInfo`. `build_pkg.py` converts pre-release versions such as `3.2.0-b1` or `3.2.0-rc1` from `-` to `~` for package metadata so pre-releases sort before the final release. If that normalized package version still contains `-`, packaging fails because RPM forbids `-` in `Version`, and Debian uses `-` as the upstream/revision separator.
-`pkg_version` is the normalized package metadata version derived inside
-`build_pkg.py` from the binary-reported `xrpld` version (`-` pre-release
-separator converted to `~`). It is not a separate user input.
+`pkg_version` is the normalized package metadata version derived inside `build_pkg.py` from the binary-reported `xrpld` version (`-` pre-release separator converted to `~`). It is not a separate user input.
-`PKG_RELEASE` is a different value: the package release iteration for that
-`xrpld` version. RPM receives the normalized `pkg_version` and `PKG_RELEASE` as
-the `pkg_version` and `pkg_release` macros for its `Version` and `Release`
-values; DEB writes them as `${pkg_version}-${PKG_RELEASE}` in
-`debian/changelog`.
+`PKG_RELEASE` is a different value: the package release iteration for that `xrpld` version. RPM receives the normalized `pkg_version` and `PKG_RELEASE` as the `pkg_version` and `pkg_release` macros for its `Version` and `Release` values; DEB writes them as `${pkg_version}-${PKG_RELEASE}` in `debian/changelog`.
With `PKG_RELEASE=1`, the package metadata becomes:
@@ -221,70 +140,38 @@ With `PKG_RELEASE=1`, the package metadata becomes:
| `3.2.0-b1` | `3.2.0~b1-1%{?dist}` | `3.2.0~b1-1` |
| `3.2.0-rc1` | `3.2.0~rc1-1%{?dist}` | `3.2.0~rc1-1` |
-`build_pkg.py` defines `dist` as `.el9` rather than letting rpmbuild take it
-from the build host, so the RHEL image can track a newer release without
-changing what the packages claim to target.
+`build_pkg.py` defines `dist` as `.el9` rather than letting rpmbuild take it from the build host, so the RHEL image can track a newer release without changing what the packages claim to target.
-The Debian changelog entry carries the channel passed as `--channel`, which
-only accepts the channels in the table above plus `UNRELEASED`, the Debian
-convention for a build that targets no channel at all — what local and CMake
-builds pass, since nothing publishes them. An unsupported pre-release, and
-build metadata on a final release such as `3.2.0+abc123`, are both rejected.
+The Debian changelog entry carries the channel passed as `--channel`, which only accepts the channels in the table above plus `UNRELEASED`, the Debian convention for a build that targets no channel at all — what local and CMake builds pass, since nothing publishes them. An unsupported pre-release, and build metadata on a final release such as `3.2.0+abc123`, are both rejected.
-The RPM path intentionally uses `~` in `Version`, matching the Debian
-pre-release ordering convention, so RPM filenames/NVRs begin with forms like
-`xrpld-3.2.0~b1-...` and `xrpld-3.2.0~rc1-...` instead of encoding
-pre-releases with an older `0..` RPM `Release` value.
+The RPM path intentionally uses `~` in `Version`, matching the Debian pre-release ordering convention, so RPM filenames/NVRs begin with forms like `xrpld-3.2.0~b1-...` and `xrpld-3.2.0~rc1-...` instead of encoding pre-releases with an older `0..` RPM `Release` value.
-The package format is `--package-type`, either `deb` or `rpm`. It is required,
-so a job never silently builds the wrong format for the image it runs in; the
-matching build tool still has to be on PATH.
+The package format is `--package-type`, either `deb` or `rpm`. It is required, so a job never silently builds the wrong format for the image it runs in; the matching build tool still has to be on PATH.
-Every input is a named argument, and every argument but `--build-dir` and
-`--pkg-release` is required. The repository root is not an argument
-at all: the script reads it from its own location. Only secrets stay in the
-environment, so they never reach the process list -- `PKG_SIGNING_KEY` for
-`sign_rpm.py`, and `NEXUS_USERNAME` / `NEXUS_PASSWORD` for `publish_pkg.py`.
+Every input is a named argument, and every argument but `--build-dir` and `--pkg-release` is required. The repository root is not an argument at all: the script reads it from its own location. Only secrets stay in the environment, so they never reach the process list -- `PKG_SIGNING_KEY` for `sign_rpm.py`, and `NEXUS_USERNAME` / `NEXUS_PASSWORD` for `publish_pkg.py`.
-Signing is not part of this script. `sign_rpm.py` does it in a separate CI step
-that only runs when publishing, so a published RPM is always signed and a local
-build never needs a key.
+Signing is not part of this script. `sign_rpm.py` does it in a separate CI step that only runs when publishing, so a published RPM is always signed and a local build never needs a key.
-It resolves the build directory to an absolute path, then calls
-`stage_common()` to copy the `xrpld` and `validator-keys` binaries, config files,
-and shared support files into the staging area, and invokes the platform build
-tool. Both binaries must be present in the build directory and must run in the
-packaging environment; a missing or non-runnable one fails early. That runtime
-check is what catches a binary still linked against the Nix store's ELF loader (see
-`patch_nix_binary` in `cmake/PatchNixBinary.cmake`).
+It resolves the build directory to an absolute path, then calls `stage_common()` to copy the `xrpld` and `validator-keys` binaries, config files, and shared support files into the staging area, and invokes the platform build tool. Both binaries must be present in the build directory and must run in the packaging environment; a missing or non-runnable one fails early. That runtime check is what catches a binary still linked against the Nix store's ELF loader (see `patch_nix_binary` in `cmake/PatchNixBinary.cmake`).
### RPM
1. Creates the standard `rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}` tree inside the build directory.
2. Copies `xrpld.spec` and all shared source files (binaries, configs, service files) into `SOURCES/`.
-3. Runs `rpmbuild -bb`, passing the normalized package metadata version as the
- `pkg_version` RPM macro and `PKG_RELEASE` as the `pkg_release` RPM macro.
- The spec uses manual `install` commands to place files, disables `dwz`, and
- generates debuginfo packages.
+3. Runs `rpmbuild -bb`, passing the normalized package metadata version as the `pkg_version` RPM macro and `PKG_RELEASE` as the `pkg_release` RPM macro. The spec uses manual `install` commands to place files, disables `dwz`, and generates debuginfo packages.
4. Output: `rpmbuild/RPMS/x86_64/xrpld-*.rpm`
-RPM upgrades intentionally do not restart a running `xrpld` service. The spec
-uses `%systemd_postun`, matching Debian's `dh_installsystemd
---no-stop-on-upgrade` behavior; operators pick up the new binary on the next
-service restart.
+RPM upgrades intentionally do not restart a running `xrpld` service. The spec uses `%systemd_postun`, matching Debian's `dh_installsystemd --no-stop-on-upgrade` behavior; operators pick up the new binary on the next service restart.
### DEB
1. Creates a staging source tree at `debbuild/source/` inside the build directory.
-2. Stages the binaries, configs, `README.md`, `LICENSE.md`, and
- `validator-keys-LICENSE`.
+2. Stages the binaries, configs, `README.md`, `LICENSE.md`, and `validator-keys-LICENSE`.
3. Copies `package/debian/` control files into `debbuild/source/debian/`.
4. Copies shared service/sysusers/tmpfiles into `debian/` where `dh_installsystemd`, `dh_installsysusers`, and `dh_installtmpfiles` pick them up automatically.
-5. Generates a minimal `debian/changelog` using `${pkg_version}-${PKG_RELEASE}`,
- where `pkg_version` is derived from the binary-reported `xrpld` version.
+5. Generates a minimal `debian/changelog` using `${pkg_version}-${PKG_RELEASE}`, where `pkg_version` is derived from the binary-reported `xrpld` version.
6. Runs `dpkg-buildpackage -b --no-sign -d` (`-d` skips the build-dependency check, since the binary is already built). `debian/rules` uses manual `install` commands.
-7. Output: `debbuild/*.deb`, the binary package and the `-dbgsym` package.
- Debian gives dbgsym packages a `.deb` extension; only Ubuntu uses `.ddeb`.
+7. Output: `debbuild/*.deb`, the binary package and the `-dbgsym` package. Debian gives dbgsym packages a `.deb` extension; only Ubuntu uses `.ddeb`.
## Post-build verification
@@ -301,11 +188,7 @@ lintian -I debbuild/*.deb
## Reproducibility
-`build_pkg.py` sets `SOURCE_DATE_EPOCH` from the latest git commit time and
-exports it; the RPM spec clamps file modification times to it via
-`%build_mtime_policy`. The remaining variables
-below further improve reproducibility but are _not_ set by the script — export
-them yourself if needed:
+`build_pkg.py` sets `SOURCE_DATE_EPOCH` from the latest git commit time and exports it; the RPM spec clamps file modification times to it via `%build_mtime_policy`. The remaining variables below further improve reproducibility but are _not_ set by the script — export them yourself if needed:
```bash
export TZ=UTC
diff --git a/src/test/README.md b/src/test/README.md
index 179d75941b..04248ebf86 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -2,28 +2,12 @@
## Running Tests
-Unit tests are bundled in the `xrpld` executable and can be executed using the
-`--unittest` parameter. Without any arguments to this option, all non-manual
-unit tests will be executed. If you want to run one or more manual tests, you
-must specify it by suite or full-name (e.g. `xrpl.app.NoRippleCheckLimits` or
-just `NoRippleCheckLimits`).
+Unit tests are bundled in the `xrpld` executable and can be executed using the `--unittest` parameter. Without any arguments to this option, all non-manual unit tests will be executed. If you want to run one or more manual tests, you must specify it by suite or full-name (e.g. `xrpl.app.NoRippleCheckLimits` or just `NoRippleCheckLimits`).
-More than one suite or group of suites can be specified as a comma separated
-list via the argument. For example, `--unittest=beast,OversizeMeta` will run
-all suites in the `beast` library (root identifier) as well as the test suite
-named `OversizeMeta`). All name matches are case sensitive.
+More than one suite or group of suites can be specified as a comma separated list via the argument. For example, `--unittest=beast,OversizeMeta` will run all suites in the `beast` library (root identifier) as well as the test suite named `OversizeMeta`). All name matches are case sensitive.
-Tests can be executed in parallel using several child processes by specifying
-the `--unittest-jobs=N` parameter. The default behavior is to execute serially
-using a single process.
+Tests can be executed in parallel using several child processes by specifying the `--unittest-jobs=N` parameter. The default behavior is to execute serially using a single process.
-The order that suites are executed is determined by the suite priority that
-is optionally specified when the suite is declared in the code with one of the
-`BEAST_DEFINE_TESTSUITE` macros. By default, suites have a priority of 0, and
-other suites can choose to declare an integer priority value to make themselves
-execute before or after other suites based on their specified priority value.
+The order that suites are executed is determined by the suite priority that is optionally specified when the suite is declared in the code with one of the `BEAST_DEFINE_TESTSUITE` macros. By default, suites have a priority of 0, and other suites can choose to declare an integer priority value to make themselves execute before or after other suites based on their specified priority value.
-By default, the framework will emit the name of each testcase/testsuite when it
-starts and any messages sent to the suite `log` stream. The `--quiet` option will
-suppress both types of messages, but combining `--unittest-log` with `--quiet`
-will cause `log` messages to be emitted while suite/case names are suppressed.
+By default, the framework will emit the name of each testcase/testsuite when it starts and any messages sent to the suite `log` stream. The `--quiet` option will suppress both types of messages, but combining `--unittest-log` with `--quiet` will cause `log` messages to be emitted while suite/case names are suppressed.
diff --git a/src/tests/README.md b/src/tests/README.md
index 2a642a7633..6257877911 100644
--- a/src/tests/README.md
+++ b/src/tests/README.md
@@ -1,5 +1,3 @@
# Unit tests
-This directory contains unit tests for the project. The difference from existing `src/test` folder
-is that we switch to 3rd party testing framework (`gtest`). We intend to gradually move existing tests
-from our own framework to `gtest` and such tests will be moved to this new folder.
+This directory contains unit tests for the project. The difference from existing `src/test` folder is that we switch to 3rd party testing framework (`gtest`). We intend to gradually move existing tests from our own framework to `gtest` and such tests will be moved to this new folder.
diff --git a/src/tests/libxrpl/csf/README.md b/src/tests/libxrpl/csf/README.md
index 081c9807d7..c6f8902735 100644
--- a/src/tests/libxrpl/csf/README.md
+++ b/src/tests/libxrpl/csf/README.md
@@ -1,59 +1,30 @@
# Consensus Simulation Framework
-The Consensus Simulation Framework is a set of software components for
-describing, running and analyzing simulations of the consensus algorithm in a
-controlled manner. It is also used to unit test the generic XRPL consensus
-algorithm implementation. The framework is in its early stages, so the design
-and supported features are subject to change.
+The Consensus Simulation Framework is a set of software components for describing, running and analyzing simulations of the consensus algorithm in a controlled manner. It is also used to unit test the generic XRPL consensus algorithm implementation. The framework is in its early stages, so the design and supported features are subject to change.
## Overview
-The simulation framework focuses on simulating the core consensus and validation
-algorithms as a [discrete event
-simulation](https://en.wikipedia.org/wiki/Discrete_event_simulation). It is
-completely abstracted from the details of the XRP ledger and transactions. In
-the simulation, a ledger is simply a set of observed integers and transactions
-are single integers. The consensus process works to agree on the set of integers
-to include in the next ledger.
+The simulation framework focuses on simulating the core consensus and validation algorithms as a [discrete event simulation](https://en.wikipedia.org/wiki/Discrete_event_simulation). It is completely abstracted from the details of the XRP ledger and transactions. In the simulation, a ledger is simply a set of observed integers and transactions are single integers. The consensus process works to agree on the set of integers to include in the next ledger.

-The diagram above gives a stylized overview of the components provided by the
-framework. These are combined by the simulation author into the simulation
-specification, which defines the configuration of the system and the data to
-collect when running the simulation. The specification includes:
+The diagram above gives a stylized overview of the components provided by the framework. These are combined by the simulation author into the simulation specification, which defines the configuration of the system and the data to collect when running the simulation. The specification includes:
-- A collection of [`Peer`s](./Peer.h) that represent the participants in the
- network, with each independently running the consensus algorithm.
-- The `Peer` trust relationships as a `TrustGraph`. This is a directed graph
- whose edges define what other `Peer`s a given `Peer` trusts. In other words,
- the set of out edges for a `Peer` in the graph correspond to the UNL of that
- `Peer`.
-- The network communication layer as a `BasicNetwork`. This models the overlay
- network topology in which messages are routed between `Peer`s. This graph
- topology can be configured independently from the `TrustGraph`.
-- Transaction `Submitter`s that model the submission of client transactions to
- the network.
-- `Collector`s that aggregate, filter and analyze data from the simulation.
- Typically, this is used to monitor invariants or generate reports.
+- A collection of [`Peer`s](./Peer.h) that represent the participants in the network, with each independently running the consensus algorithm.
+- The `Peer` trust relationships as a `TrustGraph`. This is a directed graph whose edges define what other `Peer`s a given `Peer` trusts. In other words, the set of out edges for a `Peer` in the graph correspond to the UNL of that `Peer`.
+- The network communication layer as a `BasicNetwork`. This models the overlay network topology in which messages are routed between `Peer`s. This graph topology can be configured independently from the `TrustGraph`.
+- Transaction `Submitter`s that model the submission of client transactions to the network.
+- `Collector`s that aggregate, filter and analyze data from the simulation. Typically, this is used to monitor invariants or generate reports.
-Once specified, the simulation runs using a single `Scheduler` that manages the
-global clock and sequencing of activity. During the course of simulation,
-`Peer`s generate `Ledger`s and `Validation`s as a result of consensus,
-eventually fully validating the consensus history of accepted transactions. Each
-`Peer` also issues various `Event`s during the simulation, which are analyzed by
-the registered `Collector`s.
+Once specified, the simulation runs using a single `Scheduler` that manages the global clock and sequencing of activity. During the course of simulation, `Peer`s generate `Ledger`s and `Validation`s as a result of consensus, eventually fully validating the consensus history of accepted transactions. Each `Peer` also issues various `Event`s during the simulation, which are analyzed by the registered `Collector`s.
## Example Simulation
-Below is a basic simulation we can walk through to get an understanding of the
-framework. This simulation is for a set of 5 validators that aren't directly
-connected but rely on a single hub node for communication.
+Below is a basic simulation we can walk through to get an understanding of the framework. This simulation is for a set of 5 validators that aren't directly connected but rely on a single hub node for communication.

-Each Peer has a unique transaction submitted, then runs one round of the
-consensus algorithm.
+Each Peer has a unique transaction submitted, then runs one round of the consensus algorithm.
```c++
Sim sim;
@@ -96,22 +67,9 @@ center[0]->runAsValidator = false;
```
-The simulation code starts by creating a single instance of the [`Sim`
-class](./Sim.h). This class is used to manage the overall simulation and
-internally owns most other components, including the `Peer`s, `Scheduler`,
-`BasicNetwork` and `TrustGraph`. The next two lines create two differ
-`PeerGroup`s of size 5 and 1 . A [`PeerGroup`](./PeerGroup.h) is a convenient
-way for configuring a set of related peers together and internally has a vector
-of pointers to the `Peer`s which are owned by the `Sim`. `PeerGroup`s can be
-combined using `+/-` operators to configure more complex relationships of nodes
-as shown by `PeerGroup network`. Note that each call to `createGroup` adds that
-many new `Peer`s to the simulation, but does not specify any trust or network
-relationships for the new `Peer`s.
+The simulation code starts by creating a single instance of the [`Sim` class](./Sim.h). This class is used to manage the overall simulation and internally owns most other components, including the `Peer`s, `Scheduler`, `BasicNetwork` and `TrustGraph`. The next two lines create two differ `PeerGroup`s of size 5 and 1 . A [`PeerGroup`](./PeerGroup.h) is a convenient way for configuring a set of related peers together and internally has a vector of pointers to the `Peer`s which are owned by the `Sim`. `PeerGroup`s can be combined using `+/-` operators to configure more complex relationships of nodes as shown by `PeerGroup network`. Note that each call to `createGroup` adds that many new `Peer`s to the simulation, but does not specify any trust or network relationships for the new `Peer`s.
-Lastly, the single `Peer` in the size 1 `center` group is switched from running
-as a validator (the default) to running as a tracking peer. The [`Peer`
-class](./Peer.h) has a variety of configurable parameters that control how it
-behaves during the simulation.
+Lastly, the single `Peer` in the size 1 `center` group is switched from running as a validator (the default) to running as a tracking peer. The [`Peer` class](./Peer.h) has a variety of configurable parameters that control how it behaves during the simulation.
## `trust` and `connect`
@@ -124,18 +82,9 @@ SimDuration delay = 200ms;
validators.connect(center, delay);
```
-Although the `sim` object has accessible instances of
-[TrustGraph](./TrustGraph.h) and [BasicNetwork](./BasicNetwork.h), it is more
-convenient to manage the graphs via the `PeerGroup`s. The first two lines
-create a trust topology in which all `Peer`s trust the 5 validating `Peer`s. Or
-in the UNL perspective, all `Peer`s are configured with the same UNL listing the
-5 validating `Peer`s. The two lines could've been rewritten as
-`network.trust(validators)`.
+Although the `sim` object has accessible instances of [TrustGraph](./TrustGraph.h) and [BasicNetwork](./BasicNetwork.h), it is more convenient to manage the graphs via the `PeerGroup`s. The first two lines create a trust topology in which all `Peer`s trust the 5 validating `Peer`s. Or in the UNL perspective, all `Peer`s are configured with the same UNL listing the 5 validating `Peer`s. The two lines could've been rewritten as `network.trust(validators)`.
-The next lines create the network communication topology. Each of the validating
-`Peer`s connects to the central hub `Peer` with a fixed delay of 200ms. Note
-that the network connections are really undirected, but are represented
-internally in a directed graph using edge pairs of inbound and outbound connections.
+The next lines create the network communication topology. Each of the validating `Peer`s connects to the central hub `Peer` with a fixed delay of 200ms. Note that the network connections are really undirected, but are represented internally in a directed graph using edge pairs of inbound and outbound connections.
## Collectors
@@ -144,20 +93,9 @@ SimDurationCollector simDur;
sim.collectors.add(simDur);
```
-The next lines add a single collector to the simulation. The
-`SimDurationCollector` is a simple example collector which tracks the total
-duration of the simulation. More generally, a collector is any class that
-implements `void on(NodeID, SimTime, Event)` for all [Events](./events.h)
-emitted by a Peer. Events are arbitrary types used to indicate some action or
-change of state of a `Peer`. Other [existing collectors](./collectors.h) measure
-latencies of transaction submission to validation or the rate of ledger closing
-and monitor any jumps in ledger history.
+The next lines add a single collector to the simulation. The `SimDurationCollector` is a simple example collector which tracks the total duration of the simulation. More generally, a collector is any class that implements `void on(NodeID, SimTime, Event)` for all [Events](./events.h) emitted by a Peer. Events are arbitrary types used to indicate some action or change of state of a `Peer`. Other [existing collectors](./collectors.h) measure latencies of transaction submission to validation or the rate of ledger closing and monitor any jumps in ledger history.
-Note that the collector lifetime is independent of the simulation and is added
-to the simulation by reference. This is intentional, since collectors might be
-used across several simulations to collect more complex combinations of data. At
-the end of the simulation, we print out the total duration by subtracting
-`simDur` members.
+Note that the collector lifetime is independent of the simulation and is added to the simulation by reference. This is intentional, since collectors might be used across several simulations to collect more complex combinations of data. At the end of the simulation, we print out the total duration by subtracting `simDur` members.
```c++
std::cout << (simDur.stop - simDur.start).count() << std::endl;
@@ -171,22 +109,10 @@ for (Peer * p : validators)
p->submit(Tx(static_cast(p->id)));
```
-In this basic example, we explicitly submit a single transaction to each
-validator. For larger simulations, clients can use a [Submitter](./submitters.h)
-to send transactions in at fixed or random intervals to fixed or random `Peer`s.
+In this basic example, we explicitly submit a single transaction to each validator. For larger simulations, clients can use a [Submitter](./submitters.h) to send transactions in at fixed or random intervals to fixed or random `Peer`s.
## Run
-The example has two calls to `sim.run(1)`. This call runs the simulation until
-each `Peer` has closed one additional ledger. After closing the additional
-ledger, the `Peer` stops participating in consensus. The first call is used to
-ensure a more useful prior state of all `Peer`s. After the transaction
-submission, the second call to `run` results in one additional ledger that
-accepts those transactions.
+The example has two calls to `sim.run(1)`. This call runs the simulation until each `Peer` has closed one additional ledger. After closing the additional ledger, the `Peer` stops participating in consensus. The first call is used to ensure a more useful prior state of all `Peer`s. After the transaction submission, the second call to `run` results in one additional ledger that accepts those transactions.
-Alternatively, you can specify a duration to run the simulation, e.g.
-`sim.run(10s)` which would have `Peer`s continuously run consensus until the
-scheduler has elapsed 10 additional seconds. The `sim.scheduler.in` or
-`sim.scheduler.at` methods can schedule arbitrary code to execute at a later
-time in the simulation, for example removing a network connection or modifying
-the trust graph.
+Alternatively, you can specify a duration to run the simulation, e.g. `sim.run(10s)` which would have `Peer`s continuously run consensus until the scheduler has elapsed 10 additional seconds. The `sim.scheduler.in` or `sim.scheduler.at` methods can schedule arbitrary code to execute at a later time in the simulation, for example removing a network connection or modifying the trust graph.
diff --git a/src/xrpld/app/consensus/README.md b/src/xrpld/app/consensus/README.md
index 44a4dc8ae7..ed63ff10eb 100644
--- a/src/xrpld/app/consensus/README.md
+++ b/src/xrpld/app/consensus/README.md
@@ -1,12 +1,8 @@
# RCL Consensus
-This directory holds the types and classes needed
-to connect the generic consensus algorithm to the
-xrpld-specific instance of consensus.
+This directory holds the types and classes needed to connect the generic consensus algorithm to the xrpld-specific instance of consensus.
- `RCLCxTx` adapts a `SHAMapItem` transaction.
- `RCLCxTxSet` adapts a `SHAMap` to represent a set of transactions.
- `RCLCxLedger` adapts a `Ledger`.
-- `RCLConsensus` is implements the requirements of the generic
- `Consensus` class by connecting to the rest of the `xrpld`
- application.
+- `RCLConsensus` is implements the requirements of the generic `Consensus` class by connecting to the rest of the `xrpld` application.
diff --git a/src/xrpld/app/ledger/README.md b/src/xrpld/app/ledger/README.md
index 7dc38ce9fa..729d2f2ed3 100644
--- a/src/xrpld/app/ledger/README.md
+++ b/src/xrpld/app/ledger/README.md
@@ -4,36 +4,15 @@
## Life Cycle
-Every server always has an open ledger. All received new transactions are
-applied to the open ledger. The open ledger can't close until we reach
-a consensus on the previous ledger, and either: there is at least one
-transaction in the open ledger, or the ledger's close time has been reached.
+Every server always has an open ledger. All received new transactions are applied to the open ledger. The open ledger can't close until we reach a consensus on the previous ledger, and either: there is at least one transaction in the open ledger, or the ledger's close time has been reached.
-When the open ledger is closed the transactions in the open ledger become
-the initial proposal. Validators will send the proposal (non-validators will
-simply not send the proposal). The open ledger contains the set of transactions
-the server thinks should go into the next ledger.
+When the open ledger is closed the transactions in the open ledger become the initial proposal. Validators will send the proposal (non-validators will simply not send the proposal). The open ledger contains the set of transactions the server thinks should go into the next ledger.
-Once the ledger is closed, servers avalanche to consensus on the candidate
-transaction set and the close time. When consensus is reached, servers build
-a new last closed ledger by starting with the previous last closed ledger and
-applying the consensus transaction set. In the normal case, servers will all
-agree on both the last closed ledger and the consensus transaction set. The
-goal is to give the network the highest chances of arriving at the same
-conclusion on all servers.
+Once the ledger is closed, servers avalanche to consensus on the candidate transaction set and the close time. When consensus is reached, servers build a new last closed ledger by starting with the previous last closed ledger and applying the consensus transaction set. In the normal case, servers will all agree on both the last closed ledger and the consensus transaction set. The goal is to give the network the highest chances of arriving at the same conclusion on all servers.
-At all times during the consensus process the open ledger remains open with the
-same transaction set, and has new transactions applied. It will likely have
-transactions that are also in the new last closed ledger. Valid transactions
-received during the consensus process will only be in the open ledger.
+At all times during the consensus process the open ledger remains open with the same transaction set, and has new transactions applied. It will likely have transactions that are also in the new last closed ledger. Valid transactions received during the consensus process will only be in the open ledger.
-Validators now publish validations of the new last closed ledger. Servers now
-build a new open ledger from the last closed ledger. First, all transactions
-that were candidates in the previous consensus round but didn't make it into
-the consensus set are applied. Next, transactions in the current open ledger
-are applied. This covers transactions received during the previous consensus
-round. This is a "rebase": now that we know the real history, the current open
-ledger is rebased against the last closed ledger.
+Validators now publish validations of the new last closed ledger. Servers now build a new open ledger from the last closed ledger. First, all transactions that were candidates in the previous consensus round but didn't make it into the consensus set are applied. Next, transactions in the current open ledger are applied. This covers transactions received during the previous consensus round. This is a "rebase": now that we know the real history, the current open ledger is rebased against the last closed ledger.
The purpose of the open ledger is as follows:
@@ -42,20 +21,13 @@ The purpose of the open ledger is as follows:
## Byzantine Failures
-Byzantine failures are resolved as follows. If there is a supermajority ledger,
-then a minority of validators will discover that the consensus round is
-proceeding on a different ledger than they thought. These validators will
-become desynced, and switch to a strategy of trying to acquire the consensus
-ledger.
+Byzantine failures are resolved as follows. If there is a supermajority ledger, then a minority of validators will discover that the consensus round is proceeding on a different ledger than they thought. These validators will become desynced, and switch to a strategy of trying to acquire the consensus ledger.
-If there is no majority ledger, then starting on the next consensus round there
-will not be a consensus on the last closed ledger. Another avalanche process
-is started.
+If there is no majority ledger, then starting on the next consensus round there will not be a consensus on the last closed ledger. Another avalanche process is started.
## Validators
-The only meaningful difference between a validator and a 'regular' server is
-that the validator sends its proposals and validations to the network.
+The only meaningful difference between a validator and a 'regular' server is that the validator sends its proposals and validations to the network.
---
@@ -68,65 +40,31 @@ There are two ledgers that are the most important for an xrpld server to have:
- The consensus ledger and
- The last validated ledger.
-If we need either of those two ledgers they are fetched with the highest
-priority. Also, when they arrive, they replace their earlier counterparts
-(if they exist).
+If we need either of those two ledgers they are fetched with the highest priority. Also, when they arrive, they replace their earlier counterparts (if they exist).
The `LedgerMaster` object tracks
- the last published ledger,
- the last validated ledger, and
-- ledger history.
- So the `LedgerMaster` is at the center of fetching historical ledger data.
+- ledger history. So the `LedgerMaster` is at the center of fetching historical ledger data.
-In specific, the `LedgerMaster::doAdvance()` method triggers the code that
-fetches historical data and controls the state machine for ledger acquisition.
+In specific, the `LedgerMaster::doAdvance()` method triggers the code that fetches historical data and controls the state machine for ledger acquisition.
-The server tries to publish an on-going stream of consecutive ledgers to its
-clients. After the server has started and caught up with network
-activity, say when ledger 500 is being settled, then the server puts its best
-effort into publishing validated ledger 500 followed by validated ledger 501
-and then 502. This effort continues until the server is shut down.
+The server tries to publish an on-going stream of consecutive ledgers to its clients. After the server has started and caught up with network activity, say when ledger 500 is being settled, then the server puts its best effort into publishing validated ledger 500 followed by validated ledger 501 and then 502. This effort continues until the server is shut down.
-But loading or network connectivity may sometimes interfere with that ledger
-stream. So suppose the server publishes validated ledger 600 and then
-receives validated ledger 603. Then the server wants to back fill its ledger
-history with ledgers 601 and 602.
+But loading or network connectivity may sometimes interfere with that ledger stream. So suppose the server publishes validated ledger 600 and then receives validated ledger 603. Then the server wants to back fill its ledger history with ledgers 601 and 602.
-The server prioritizes keeping up with current ledgers. But if it is caught
-up on the current ledger, and there are no higher priority demands on the
-server, then it will attempt to back fill its historical ledgers. It fills
-in the historical ledger data first by attempting to retrieve it from the
-local database. If the local database does not have all of the necessary data
-then the server requests the remaining information from network peers.
+The server prioritizes keeping up with current ledgers. But if it is caught up on the current ledger, and there are no higher priority demands on the server, then it will attempt to back fill its historical ledgers. It fills in the historical ledger data first by attempting to retrieve it from the local database. If the local database does not have all of the necessary data then the server requests the remaining information from network peers.
-Suppose the server is missing multiple historical ledgers. Take the previous
-example where we have ledgers 603 and 600, but we're missing 601 and 602. In
-that case the server requests information for ledger 602 first, before
-back-filling ledger 601. We want to expand the contiguous range of
-most-recent ledgers that the server has locally. There's also a limit to
-how much historical ledger data is useful. So if we're on ledger 603, but
-we're missing ledger 4 we may not bother asking for ledger 4.
+Suppose the server is missing multiple historical ledgers. Take the previous example where we have ledgers 603 and 600, but we're missing 601 and 602. In that case the server requests information for ledger 602 first, before back-filling ledger 601. We want to expand the contiguous range of most-recent ledgers that the server has locally. There's also a limit to how much historical ledger data is useful. So if we're on ledger 603, but we're missing ledger 4 we may not bother asking for ledger 4.
## Assembling a Ledger
-When data for a ledger arrives from a peer, it may take a while before the
-server can apply that data. So when ledger data arrives we schedule a job
-thread to apply that data. If more data arrives before the job starts we add
-that data to the job. We defer requesting more ledger data until all of the
-data we have for that ledger has been processed. Once all of that data is
-processed we can intelligently request only the additional data that we need
-to fill in the ledger. This reduces network traffic and minimizes the load
-on peers supplying the data.
+When data for a ledger arrives from a peer, it may take a while before the server can apply that data. So when ledger data arrives we schedule a job thread to apply that data. If more data arrives before the job starts we add that data to the job. We defer requesting more ledger data until all of the data we have for that ledger has been processed. Once all of that data is processed we can intelligently request only the additional data that we need to fill in the ledger. This reduces network traffic and minimizes the load on peers supplying the data.
-If we receive data for a ledger that is not currently under construction,
-we don't just throw the data away. In particular the AccountStateNodes
-may be useful, since they can be re-used across ledgers. This data is
-stashed in memory (not the database) where the acquire process can find
-it.
+If we receive data for a ledger that is not currently under construction, we don't just throw the data away. In particular the AccountStateNodes may be useful, since they can be re-used across ledgers. This data is stashed in memory (not the database) where the acquire process can find it.
-Peers deliver ledger data in the order in which the data can be validated.
-Data arrives in the following order:
+Peers deliver ledger data in the order in which the data can be validated. Data arrives in the following order:
1. The hash of the ledger header
2. The ledger header
@@ -134,63 +72,29 @@ Data arrives in the following order:
4. The lower (non-root) nodes of the state tree
5. The lower (non-root) nodes of the transaction tree
-Inner-most nodes are supplied before outer nodes. This allows the
-requesting server to hook things up (and validate) in the order in which
-data arrives.
+Inner-most nodes are supplied before outer nodes. This allows the requesting server to hook things up (and validate) in the order in which data arrives.
-If this process fails, then a server can also ask for ledger data by hash,
-rather than by asking for specific nodes in a ledger. Asking for information
-by hash is less efficient, but it allows a peer to return the information
-even if the information is not assembled into a tree. All the peer needs is
-the raw data.
+If this process fails, then a server can also ask for ledger data by hash, rather than by asking for specific nodes in a ledger. Asking for information by hash is less efficient, but it allows a peer to return the information even if the information is not assembled into a tree. All the peer needs is the raw data.
## Which Peer To Ask
-Peers go though state transitions as the network goes through its state
-transitions. Peer's provide their state to their directly connected peers.
-By monitoring the state of each connected peer a server can tell which of
-its peers has the information that it needs.
+Peers go though state transitions as the network goes through its state transitions. Peer's provide their state to their directly connected peers. By monitoring the state of each connected peer a server can tell which of its peers has the information that it needs.
-Therefore if a server suffers a byzantine failure the server can tell which
-of its peers did not suffer that same failure. So the server knows which
-peer(s) to ask for the missing information.
+Therefore if a server suffers a byzantine failure the server can tell which of its peers did not suffer that same failure. So the server knows which peer(s) to ask for the missing information.
-Peers also report their contiguous range of ledgers. This is another way that
-a server can determine which peer to ask for a particular ledger or piece of
-a ledger.
+Peers also report their contiguous range of ledgers. This is another way that a server can determine which peer to ask for a particular ledger or piece of a ledger.
-There are also indirect peer queries. If there have been timeouts while
-acquiring ledger data then a server may issue indirect queries. In that
-case the server receiving the indirect query passes the query along to any
-of its peers that may have the requested data. This is important if the
-network has a byzantine failure. It also helps protect the validation
-network. A validator may need to get a peer set from one of the other
-validators, and indirect queries improve the likelihood of success with
-that.
+There are also indirect peer queries. If there have been timeouts while acquiring ledger data then a server may issue indirect queries. In that case the server receiving the indirect query passes the query along to any of its peers that may have the requested data. This is important if the network has a byzantine failure. It also helps protect the validation network. A validator may need to get a peer set from one of the other validators, and indirect queries improve the likelihood of success with that.
## Kinds of Fetch Packs
-A FetchPack is the way that peers send partial ledger data to other peers
-so the receiving peer can reconstruct a ledger.
+A FetchPack is the way that peers send partial ledger data to other peers so the receiving peer can reconstruct a ledger.
-A 'normal' FetchPack is a bucket of nodes indexed by hash. The server
-building the FetchPack puts information into the FetchPack that the
-destination server is likely to need. Normally they contain all of the
-missing nodes needed to fill in a ledger.
+A 'normal' FetchPack is a bucket of nodes indexed by hash. The server building the FetchPack puts information into the FetchPack that the destination server is likely to need. Normally they contain all of the missing nodes needed to fill in a ledger.
-A 'compact' FetchPack, on the other hand, contains only leaf nodes, no
-inner nodes. Because there are no inner nodes, the ledger information that
-it contains cannot be validated as the ledger is assembled. We have to,
-initially, take the accuracy of the FetchPack for granted and assemble the
-ledger. Once the entire ledger is assembled the entire ledger can be
-validated. But if the ledger does not validate then there's nothing to be
-done but throw the entire FetchPack away; there's no way to save a portion
-of the FetchPack.
+A 'compact' FetchPack, on the other hand, contains only leaf nodes, no inner nodes. Because there are no inner nodes, the ledger information that it contains cannot be validated as the ledger is assembled. We have to, initially, take the accuracy of the FetchPack for granted and assemble the ledger. Once the entire ledger is assembled the entire ledger can be validated. But if the ledger does not validate then there's nothing to be done but throw the entire FetchPack away; there's no way to save a portion of the FetchPack.
-The FetchPacks just described could be termed 'reverse FetchPacks.' They
-only provide historical data. There may be a use for what could be called a
-'forward FetchPack.' A forward FetchPack would contain the information that
-is needed to build a new ledger out of the preceding ledger.
+The FetchPacks just described could be termed 'reverse FetchPacks.' They only provide historical data. There may be a use for what could be called a 'forward FetchPack.' A forward FetchPack would contain the information that is needed to build a new ledger out of the preceding ledger.
A forward compact FetchPack would need to contain:
@@ -206,50 +110,35 @@ A forward compact FetchPack would need to contain:
## Open Ledger
-The open ledger is the ledger that the server applies all new incoming
-transactions to.
+The open ledger is the ledger that the server applies all new incoming transactions to.
## Last Validated Ledger
-The most recent ledger that the server is certain will always remain part
-of the permanent, public history.
+The most recent ledger that the server is certain will always remain part of the permanent, public history.
## Last Closed Ledger
-The most recent ledger that the server believes the network reached consensus
-on. Different servers can arrive at a different conclusion about the last
-closed ledger. This is a consequence of Byzantanine failure. The purpose of
-validations is to resolve the differences between servers and come to a common
-conclusion about which last closed ledger is authoritative.
+The most recent ledger that the server believes the network reached consensus on. Different servers can arrive at a different conclusion about the last closed ledger. This is a consequence of Byzantanine failure. The purpose of validations is to resolve the differences between servers and come to a common conclusion about which last closed ledger is authoritative.
## Consensus
-A distributed agreement protocol. XRPL uses the consensus process to solve
-the problem of double-spending.
+A distributed agreement protocol. XRPL uses the consensus process to solve the problem of double-spending.
## Validation
-A signed statement indicating that it built a particular ledger as a result
-of the consensus process.
+A signed statement indicating that it built a particular ledger as a result of the consensus process.
## Proposal
-A signed statement of which transactions it believes should be included in
-the next consensus ledger.
+A signed statement of which transactions it believes should be included in the next consensus ledger.
## Ledger Header
-The "ledger header" is the chunk of data that hashes to the
-ledger's hash. It contains the sequence number, parent hash,
-hash of the previous ledger, hash of the root node of the
-state tree, and so on.
+The "ledger header" is the chunk of data that hashes to the ledger's hash. It contains the sequence number, parent hash, hash of the previous ledger, hash of the root node of the state tree, and so on.
## Ledger Base
-The term "ledger base" refers to a particular type of query
-and response used in the ledger fetch process that includes
-the ledger header but may also contain other information
-such as the root node of the state tree.
+The term "ledger base" refers to a particular type of query and response used in the ledger fetch process that includes the ledger header but may also contain other information such as the root node of the state tree.
---
@@ -265,32 +154,19 @@ such as the root node of the state tree.
**LedgerEntryType:** "AccountRoot"
-**OwnerCount:** The number of items the account owns that are charged to the
-account. Offers are charged to the account. Trust lines may be charged to
-the account (but not necessarily). The OwnerCount determines the reserve on
-the account.
+**OwnerCount:** The number of items the account owns that are charged to the account. Offers are charged to the account. Trust lines may be charged to the account (but not necessarily). The OwnerCount determines the reserve on the account.
**PreviousTxnID:** 256-bit index of the previous transaction on this account.
-**PreviousTxnLgrSeq:** Ledger number sequence number of the previous
-transaction on this account.
+**PreviousTxnLgrSeq:** Ledger number sequence number of the previous transaction on this account.
-**Sequence:** Must be a value of 1 for the account to process a valid
-transaction. The value initially matches the sequence number of the state
-tree of the account that signed the transaction. The process of executing
-the transaction increments the sequence number. This is how ripple prevents
-a transaction from executing more than once.
+**Sequence:** Must be a value of 1 for the account to process a valid transaction. The value initially matches the sequence number of the state tree of the account that signed the transaction. The process of executing the transaction increments the sequence number. This is how ripple prevents a transaction from executing more than once.
**index:** 256-bit hash of this AccountRoot.
## Trust Line
-The trust line acts as an edge connecting two accounts: the accounts
-represented by the HighNode and the LowNode. Which account is "high" and
-"low" is determined by the values of the two 160-bit account IDs. The
-account with the smaller 160-bit ID is always the low account. This
-ordering makes the hash of a trust line between accounts A and B have the
-same value as a trust line between accounts B and A.
+The trust line acts as an edge connecting two accounts: the accounts represented by the HighNode and the LowNode. Which account is "high" and "low" is determined by the values of the two 160-bit account IDs. The account with the smaller 160-bit ID is always the low account. This ordering makes the hash of a trust line between accounts A and B have the same value as a trust line between accounts B and A.
**Balance:**
@@ -320,8 +196,7 @@ same value as a trust line between accounts B and A.
**PreviousTxnID:** 256-bit hash of the previous transaction on this account.
-**PreviousTxnLgrSeq:** Ledger number sequence number of the previous
-transaction on this account.
+**PreviousTxnLgrSeq:** Ledger number sequence number of the previous transaction on this account.
**index:** 256-bit hash of this RippleState.
@@ -357,28 +232,17 @@ Lists all of the offers and trust lines that are associated with an account.
Lists one or more offers that have the same quality.
-If a pair of Currency and Issuer fields are all zeros, then that pair is
-dealing in XRP.
+If a pair of Currency and Issuer fields are all zeros, then that pair is dealing in XRP.
-The code, at the moment, does not recognize that the Currency and Issuer
-fields are currencies and issuers. So those values are presented in hex,
-rather than as accounts and currencies. That's a bug and should be fixed
-at some point.
+The code, at the moment, does not recognize that the Currency and Issuer fields are currencies and issuers. So those values are presented in hex, rather than as accounts and currencies. That's a bug and should be fixed at some point.
-**ExchangeRate:** A 64-bit value. The first 8-bits is the exponent and the
-remaining bits are the mantissa. The format is such that a bigger 64-bit
-value always represents a higher exchange rate.
+**ExchangeRate:** A 64-bit value. The first 8-bits is the exponent and the remaining bits are the mantissa. The format is such that a bigger 64-bit value always represents a higher exchange rate.
-Each type can compute its own hash. The hash of a book directory contains,
-as its lowest 64 bits, the exchange rate. This means that if there are
-multiple _almost_ identical book directories, but with different exchange
-rates, then these book directories will sit together in the ledger. The best
-exchange rate will be the first in the sequence of Book Directories.
+Each type can compute its own hash. The hash of a book directory contains, as its lowest 64 bits, the exchange rate. This means that if there are multiple _almost_ identical book directories, but with different exchange rates, then these book directories will sit together in the ledger. The best exchange rate will be the first in the sequence of Book Directories.
**Flags:** ???
-**Indexes:** 256-bit hashes of offers that match the exchange rate and
-currencies described by this BookDirectory.
+**Indexes:** 256-bit hashes of offers that match the exchange rate and currencies described by this BookDirectory.
**LedgerEntryType:** "DirectoryNode".
@@ -392,9 +256,7 @@ currencies described by this BookDirectory.
**TakerPaysIssuer:** Issuer of the PaysCurrency.
-**index:** A 256-bit hash computed using the TakerGetsCurrency, TakerGetsIssuer,
-TakerPaysCurrency, and TakerPaysIssuer in the top 192 bits. The lower 64-bits
-are occupied by the exchange rate.
+**index:** A 256-bit hash computed using the TakerGetsCurrency, TakerGetsIssuer, TakerPaysCurrency, and TakerPaysIssuer in the top 192 bits. The lower 64-bits are occupied by the exchange rate.
---
@@ -402,32 +264,19 @@ are occupied by the exchange rate.
## Overview
-The XRPL server permits clients to subscribe to a continuous stream of
-fully-validated ledgers. The publication code maintains this stream.
+The XRPL server permits clients to subscribe to a continuous stream of fully-validated ledgers. The publication code maintains this stream.
-The server attempts to maintain this continuous stream unless it falls
-too far behind, in which case it jumps to the current fully-validated
-ledger and then attempts to resume a continuous stream.
+The server attempts to maintain this continuous stream unless it falls too far behind, in which case it jumps to the current fully-validated ledger and then attempts to resume a continuous stream.
## Implementation
-`LedgerMaster::doAdvance` is invoked when work may need to be done to
-publish ledgers to clients. This code loops until it cannot make further
-progress.
+`LedgerMaster::doAdvance` is invoked when work may need to be done to publish ledgers to clients. This code loops until it cannot make further progress.
-`LedgerMaster::findNewLedgersToPublish` is called first. If the last
-fully-valid ledger's sequence number is greater than the last published
-ledger's sequence number, it attempts to publish those ledgers, retrieving
-them if needed.
+`LedgerMaster::findNewLedgersToPublish` is called first. If the last fully-valid ledger's sequence number is greater than the last published ledger's sequence number, it attempts to publish those ledgers, retrieving them if needed.
-If there are no new ledgers to publish, `doAdvance` determines if it can
-backfill history. If the publication is not caught up, backfilling is not
-attempted to conserve resources.
+If there are no new ledgers to publish, `doAdvance` determines if it can backfill history. If the publication is not caught up, backfilling is not attempted to conserve resources.
-If history can be backfilled, the missing ledger with the highest
-sequence number is retrieved first. If a historical ledger is retrieved,
-and its predecessor is in the database, `tryFill` is invoked to update
-the list of resident ledgers.
+If history can be backfilled, the missing ledger with the highest sequence number is retrieved first. If a historical ledger is retrieved, and its predecessor is in the database, `tryFill` is invoked to update the list of resident ledgers.
---
@@ -435,41 +284,23 @@ the list of resident ledgers.
## Overview
-The ledger cleaner checks and, if necessary, repairs the SQLite ledger and
-transaction databases. It can also check for pieces of a ledger that should
-be in the node back end but are missing. If it detects this case, it
-triggers a fetch of the ledger. The ledger cleaner only operates by manual
-request. It is never started automatically.
+The ledger cleaner checks and, if necessary, repairs the SQLite ledger and transaction databases. It can also check for pieces of a ledger that should be in the node back end but are missing. If it detects this case, it triggers a fetch of the ledger. The ledger cleaner only operates by manual request. It is never started automatically.
## Operations
-The ledger cleaner can operate on a single ledger or a range of ledgers. It
-always validates the ledger chain itself, ensuring that the SQLite database
-contains a consistent chain of ledgers from the last validated ledger as far
-back as the database goes.
+The ledger cleaner can operate on a single ledger or a range of ledgers. It always validates the ledger chain itself, ensuring that the SQLite database contains a consistent chain of ledgers from the last validated ledger as far back as the database goes.
-If requested, it can additionally repair the SQLite entries for transactions
-in each checked ledger. This was primarily intended to repair incorrect
-entries created by a bug (since fixed) that could cause transactions from a
-ledger other than the fully-validated ledger to appear in the SQLite
-databases in addition to the transactions from the correct ledger.
+If requested, it can additionally repair the SQLite entries for transactions in each checked ledger. This was primarily intended to repair incorrect entries created by a bug (since fixed) that could cause transactions from a ledger other than the fully-validated ledger to appear in the SQLite databases in addition to the transactions from the correct ledger.
-If requested, it can additionally check the ledger for missing entries
-in the account state and transaction trees.
+If requested, it can additionally check the ledger for missing entries in the account state and transaction trees.
-To prevent the ledger cleaner from saturating the available I/O bandwidth
-and excessively polluting caches with ancient information, the ledger
-cleaner paces itself and does not attempt to get its work done quickly.
+To prevent the ledger cleaner from saturating the available I/O bandwidth and excessively polluting caches with ancient information, the ledger cleaner paces itself and does not attempt to get its work done quickly.
## Commands
-The ledger cleaner can be controlled and monitored with the **ledger_cleaner**
-RPC command. With no parameters, this command reports on the status of the
-ledger cleaner. This includes the range of ledgers it has been asked to process,
-the checks it is doing, and the number of errors it has found.
+The ledger cleaner can be controlled and monitored with the **ledger_cleaner** RPC command. With no parameters, this command reports on the status of the ledger cleaner. This includes the range of ledgers it has been asked to process, the checks it is doing, and the number of errors it has found.
-The ledger cleaner can be started, stopped, or have its behavior changed by
-the following RPC parameters:
+The ledger cleaner can be started, stopped, or have its behavior changed by the following RPC parameters:
**stop**: Stops the ledger cleaner gracefully
@@ -479,11 +310,9 @@ the following RPC parameters:
**full**: Requests all operations to be done on the specified ledger(s)
-**fix_txns**: A boolean indicating whether to replace the SQLite transaction
-entries unconditionally
+**fix_txns**: A boolean indicating whether to replace the SQLite transaction entries unconditionally
-**check_nodes**: A boolean indicating whether to check the specified
-ledger(s) for missing nodes in the back end node store
+**check_nodes**: A boolean indicating whether to check the specified ledger(s) for missing nodes in the back end node store
---
diff --git a/src/xrpld/app/misc/FeeEscalation.md b/src/xrpld/app/misc/FeeEscalation.md
index 5a3edbe95a..1cd9e7a592 100644
--- a/src/xrpld/app/misc/FeeEscalation.md
+++ b/src/xrpld/app/misc/FeeEscalation.md
@@ -7,180 +7,70 @@ Xrpld's fee mechanism consists of several interrelated processes:
## Fee Escalation
-The guiding principal of fee escalation is that when things are going
-smoothly, fees stay low, but as soon as high levels of traffic appear
-on the network, fees will grow quickly to extreme levels. This should
-dissuade malicious users from abusing the system, while giving
-legitimate users the ability to pay a higher fee to get high-priority
-transactions into the open ledger, even during unfavorable conditions.
+The guiding principal of fee escalation is that when things are going smoothly, fees stay low, but as soon as high levels of traffic appear on the network, fees will grow quickly to extreme levels. This should dissuade malicious users from abusing the system, while giving legitimate users the ability to pay a higher fee to get high-priority transactions into the open ledger, even during unfavorable conditions.
How fees escalate:
-1. There is a base [fee level](#fee-level) of 256,
- which is the minimum that a typical transaction
- is required to pay. For a [reference
- transaction](#reference-transaction), that corresponds to the
- network base fee, which is currently 10 drops.
-2. However, there is a limit on the number of transactions that
- can get into an open ledger for that base fee level. The limit
- will vary based on the [health](#consensus-health) of the
- consensus process, but will be at least [5](#other-constants).
+1. There is a base [fee level](#fee-level) of 256, which is the minimum that a typical transaction is required to pay. For a [reference transaction](#reference-transaction), that corresponds to the network base fee, which is currently 10 drops.
+2. However, there is a limit on the number of transactions that can get into an open ledger for that base fee level. The limit will vary based on the [health](#consensus-health) of the consensus process, but will be at least [5](#other-constants).
-- If consensus stays [healthy](#consensus-health), the limit will
- be the max of the number of transactions in the validated ledger
- plus [20%](#other-constants) or the current limit until it gets
- to [50](#other-constants), at which point, the limit will be the
- largest number of transactions plus [20%](#other-constants)
- in the last [20](#other-constants) validated ledgers which had
- more than [50](#other-constants) transactions. Any time the limit
- decreases (i.e. a large ledger is no longer recent), the limit will
- decrease to the new largest value by 10% each time the ledger has
- more than 50 transactions.
-- If consensus does not stay [healthy](#consensus-health),
- the limit will clamp down to the smaller of the number of
- transactions in the validated ledger minus [50%](#other-constants)
- or the previous limit minus [50%](#other-constants).
-- The intended effect of these mechanisms is to allow as many base fee
- level transactions to get into the ledger as possible while the
- network is [healthy](#consensus-health), but to respond quickly to
- any condition that makes it [unhealthy](#consensus-health), including,
- but not limited to, malicious attacks.
+- If consensus stays [healthy](#consensus-health), the limit will be the max of the number of transactions in the validated ledger plus [20%](#other-constants) or the current limit until it gets to [50](#other-constants), at which point, the limit will be the largest number of transactions plus [20%](#other-constants) in the last [20](#other-constants) validated ledgers which had more than [50](#other-constants) transactions. Any time the limit decreases (i.e. a large ledger is no longer recent), the limit will decrease to the new largest value by 10% each time the ledger has more than 50 transactions.
+- If consensus does not stay [healthy](#consensus-health), the limit will clamp down to the smaller of the number of transactions in the validated ledger minus [50%](#other-constants) or the previous limit minus [50%](#other-constants).
+- The intended effect of these mechanisms is to allow as many base fee level transactions to get into the ledger as possible while the network is [healthy](#consensus-health), but to respond quickly to any condition that makes it [unhealthy](#consensus-health), including, but not limited to, malicious attacks.
-3. Once there are more transactions in the open ledger than indicated
- by the limit, the required fee level jumps drastically.
+3. Once there are more transactions in the open ledger than indicated by the limit, the required fee level jumps drastically.
-- The formula is `( lastLedgerMedianFeeLevel *
-TransactionsInOpenLedger^2 / limit^2 )`,
- and returns a [fee level](#fee-level).
+- The formula is `( lastLedgerMedianFeeLevel * TransactionsInOpenLedger^2 / limit^2 )`, and returns a [fee level](#fee-level).
-4. That may still be pretty small, but as more transactions get
- into the ledger, the fee level increases exponentially.
+4. That may still be pretty small, but as more transactions get into the ledger, the fee level increases exponentially.
-- For example, if the limit is 6, and the median fee is minimal,
- and assuming all [reference transactions](#reference-transaction),
- the 8th transaction only requires a [level](#fee-level) of about 174,000
- or about 6800 drops,
- but the 20th transaction requires a [level](#fee-level) of about
- 1,283,000 or about 50,000 drops.
+- For example, if the limit is 6, and the median fee is minimal, and assuming all [reference transactions](#reference-transaction), the 8th transaction only requires a [level](#fee-level) of about 174,000 or about 6800 drops, but the 20th transaction requires a [level](#fee-level) of about 1,283,000 or about 50,000 drops.
-5. Finally, as each ledger closes, the median fee level of that ledger is
- computed and used as `lastLedgerMedianFeeLevel` (with a
- [minimum value of 128,000](#other-constants))
- in the fee escalation formula for the next open ledger.
+5. Finally, as each ledger closes, the median fee level of that ledger is computed and used as `lastLedgerMedianFeeLevel` (with a [minimum value of 128,000](#other-constants)) in the fee escalation formula for the next open ledger.
-- Continuing the example above, if ledger consensus completes with
- only those 20 transactions, and all of those transactions paid the
- minimum required fee at each step, the limit will be adjusted from
- 6 to 24, and the `lastLedgerMedianFeeLevel` will be about 322,000,
- which is 12,600 drops for a
- [reference transaction](#reference-transaction).
-- This will only require 10 drops for the first 25 transactions,
- but the 26th transaction will require a level of about 349,150
- or about 13,649 drops.
+- Continuing the example above, if ledger consensus completes with only those 20 transactions, and all of those transactions paid the minimum required fee at each step, the limit will be adjusted from 6 to 24, and the `lastLedgerMedianFeeLevel` will be about 322,000, which is 12,600 drops for a [reference transaction](#reference-transaction).
+- This will only require 10 drops for the first 25 transactions, but the 26th transaction will require a level of about 349,150 or about 13,649 drops.
-- This example assumes a cold-start scenario, with a single, possibly
- malicious, user willing to pay arbitrary amounts to get transactions
- into the open ledger. It ignores the effects of the [Transaction
- Queue](#transaction-queue). Any lower fee level transactions submitted
- by other users at the same time as this user's transactions will go into
- the transaction queue, and will have the first opportunity to be applied
- to the _next_ open ledger. The next section describes how that works in
- more detail.
+- This example assumes a cold-start scenario, with a single, possibly malicious, user willing to pay arbitrary amounts to get transactions into the open ledger. It ignores the effects of the [Transaction Queue](#transaction-queue). Any lower fee level transactions submitted by other users at the same time as this user's transactions will go into the transaction queue, and will have the first opportunity to be applied to the _next_ open ledger. The next section describes how that works in more detail.
## Transaction Queue
-An integral part of making fee escalation work for users of the network
-is the transaction queue. The queue allows legitimate transactions to be
-considered by the network for future ledgers if the escalated open
-ledger fee gets too high. This allows users to submit low priority
-transactions with a low fee, and wait for high fees to drop. It also
-allows legitimate users to continue submitting transactions during high
-traffic periods, and give those transactions a much better chance to
-succeed.
+An integral part of making fee escalation work for users of the network is the transaction queue. The queue allows legitimate transactions to be considered by the network for future ledgers if the escalated open ledger fee gets too high. This allows users to submit low priority transactions with a low fee, and wait for high fees to drop. It also allows legitimate users to continue submitting transactions during high traffic periods, and give those transactions a much better chance to succeed.
-1. If an incoming transaction meets both the base [fee
- level](#fee-level) and the [load fee](#load-fee) minimum, but does not have a high
- enough [fee level](#fee-level) to immediately go into the open ledger,
- it is instead put into the queue and broadcast to peers. Each peer will
- then make an independent decision about whether to put the transaction
- into its open ledger or the queue. In principle, peers with identical
- open ledgers will come to identical decisions. Any discrepancies will be
- resolved as usual during consensus.
-2. When consensus completes, the open ledger limit is adjusted, and
- the required [fee level](#fee-level) drops back to the base
- [fee level](#fee-level). Before the ledger is made available to
- external transactions, transactions are applied from the queue to the
- ledger from highest [fee level](#fee-level) to lowest. These transactions
- count against the open ledger limit, so the required [fee level](#fee-level)
- may start rising during this process.
-3. Once the queue is empty, or the required [fee level](#fee-level)
- rises too high for the remaining transactions in the queue, the ledger
- is opened up for normal transaction processing.
-4. A transaction in the queue can stay there indefinitely in principle,
- but in practice, either
+1. If an incoming transaction meets both the base [fee level](#fee-level) and the [load fee](#load-fee) minimum, but does not have a high enough [fee level](#fee-level) to immediately go into the open ledger, it is instead put into the queue and broadcast to peers. Each peer will then make an independent decision about whether to put the transaction into its open ledger or the queue. In principle, peers with identical open ledgers will come to identical decisions. Any discrepancies will be resolved as usual during consensus.
+2. When consensus completes, the open ledger limit is adjusted, and the required [fee level](#fee-level) drops back to the base [fee level](#fee-level). Before the ledger is made available to external transactions, transactions are applied from the queue to the ledger from highest [fee level](#fee-level) to lowest. These transactions count against the open ledger limit, so the required [fee level](#fee-level) may start rising during this process.
+3. Once the queue is empty, or the required [fee level](#fee-level) rises too high for the remaining transactions in the queue, the ledger is opened up for normal transaction processing.
+4. A transaction in the queue can stay there indefinitely in principle, but in practice, either
- it will eventually get applied to the ledger,
- it will attempt to apply to the ledger and fail,
-- it will attempt to apply to the ledger and retry [10
- times](#other-constants),
+- it will attempt to apply to the ledger and retry [10 times](#other-constants),
- its last ledger sequence number will expire,
-- the user will replace it by submitting another transaction with the same
- sequence number and at least a [25% higher fee](#other-constants), or
-- it will get dropped when the queue fills up with more valuable transactions.
- The size limit is computed dynamically, and can hold transactions for
- the next [20 ledgers](#other-constants) (restricted to a minimum of
- [2000 transactions](#other-constants)). The lower the transaction's
- fee, the more likely that it will get dropped if the network is busy.
+- the user will replace it by submitting another transaction with the same sequence number and at least a [25% higher fee](#other-constants), or
+- it will get dropped when the queue fills up with more valuable transactions. The size limit is computed dynamically, and can hold transactions for the next [20 ledgers](#other-constants) (restricted to a minimum of [2000 transactions](#other-constants)). The lower the transaction's fee, the more likely that it will get dropped if the network is busy.
-If a transaction is submitted for an account with one or more transactions
-already in the queue, and a sequence number that is sequential with the other
-transactions in the queue for that account, it will be considered
-for the queue if it meets these additional criteria:
+If a transaction is submitted for an account with one or more transactions already in the queue, and a sequence number that is sequential with the other transactions in the queue for that account, it will be considered for the queue if it meets these additional criteria:
-- the account has fewer than [10](#other-constants) transactions
- already in the queue.
-- all other queued transactions for that account, in the case where
- they spend the maximum possible XRP, leave enough XRP balance to pay
- the fee,
-- the total fees for the other queued transactions are less than both
- the network's minimum reserve and the account's XRP balance, and
-- none of the prior queued transactions affect the ability of subsequent
- transactions to claim a fee.
+- the account has fewer than [10](#other-constants) transactions already in the queue.
+- all other queued transactions for that account, in the case where they spend the maximum possible XRP, leave enough XRP balance to pay the fee,
+- the total fees for the other queued transactions are less than both the network's minimum reserve and the account's XRP balance, and
+- none of the prior queued transactions affect the ability of subsequent transactions to claim a fee.
-Currently, there is an additional restriction that the queue cannot work with
-transactions using the `sfPreviousTxnID` or `sfAccountTxnID` fields.
-`sfPreviousTxnID` is deprecated and shouldn't be used anyway. Future
-development will make the queue aware of `sfAccountTxnID` mechanisms.
+Currently, there is an additional restriction that the queue cannot work with transactions using the `sfPreviousTxnID` or `sfAccountTxnID` fields. `sfPreviousTxnID` is deprecated and shouldn't be used anyway. Future development will make the queue aware of `sfAccountTxnID` mechanisms.
## Technical Details
### Fee Level
-"Fee level" is used to allow the cost of different types of transactions
-to be compared directly. For a [reference
-transaction](#reference-transaction), the base fee
-level is 256. If a transaction is submitted with a higher `Fee` field,
-the fee level is scaled appropriately.
+"Fee level" is used to allow the cost of different types of transactions to be compared directly. For a [reference transaction](#reference-transaction), the base fee level is 256. If a transaction is submitted with a higher `Fee` field, the fee level is scaled appropriately.
-Examples, assuming a [reference transaction](#reference-transaction)
-base fee of 10 drops:
+Examples, assuming a [reference transaction](#reference-transaction) base fee of 10 drops:
-1. A single-signed [reference transaction](#reference-transaction)
- with `Fee=20` will have a fee level of
- `20 drop fee * 256 fee level / 10 drop base fee = 512 fee level`.
-2. A multi-signed [reference transaction](#reference-transaction) with
- 3 signatures (base fee = 40 drops) and `Fee=60` will have a fee level of
- `60 drop fee * 256 fee level / ((1tx + 3sigs) * 10 drop base fee) = 384
-fee level`.
-3. A hypothetical future non-reference transaction with a base
- fee of 15 drops multi-signed with 5 signatures and `Fee=90` will
- have a fee level of
- `90 drop fee * 256 fee level / ((1tx + 5sigs) * 15 drop base fee) = 256
-fee level`.
+1. A single-signed [reference transaction](#reference-transaction) with `Fee=20` will have a fee level of `20 drop fee * 256 fee level / 10 drop base fee = 512 fee level`.
+2. A multi-signed [reference transaction](#reference-transaction) with 3 signatures (base fee = 40 drops) and `Fee=60` will have a fee level of `60 drop fee * 256 fee level / ((1tx + 3sigs) * 10 drop base fee) = 384 fee level`.
+3. A hypothetical future non-reference transaction with a base fee of 15 drops multi-signed with 5 signatures and `Fee=90` will have a fee level of `90 drop fee * 256 fee level / ((1tx + 5sigs) * 15 drop base fee) = 256 fee level`.
-This demonstrates that a simpler transaction paying less XRP can be more
-likely to get into the open ledger, or be sorted earlier in the queue
-than a more complex transaction paying more XRP.
+This demonstrates that a simpler transaction paying less XRP can be more likely to get into the open ledger, or be sorted earlier in the queue than a more complex transaction paying more XRP.
### Load Fee
@@ -188,112 +78,34 @@ Each xrpld server maintains a minimum cost threshold based on its current load.
### Reference Transaction
-In this document, a "Reference Transaction" is any currently implemented
-single-signed transaction (eg. Payment, Account Set, Offer Create, etc)
-that requires a fee.
+In this document, a "Reference Transaction" is any currently implemented single-signed transaction (eg. Payment, Account Set, Offer Create, etc) that requires a fee.
-In the future, there may be other transaction types that require
-more (or less) work for xrpld to process. Those transactions may have
-a higher (or lower) base fee, requiring a correspondingly higher (or
-lower) fee to get into the same position as a reference transaction.
+In the future, there may be other transaction types that require more (or less) work for xrpld to process. Those transactions may have a higher (or lower) base fee, requiring a correspondingly higher (or lower) fee to get into the same position as a reference transaction.
### Consensus Health
-For consensus to be considered healthy, the peers on the network
-should largely remain in sync with one another. It is particularly
-important for the validators to remain in sync, because that is required
-for participation in consensus. However, the network tolerates some
-validators being out of sync. Fundamentally, network health is a
-function of validators reaching consensus on sets of recently submitted
-transactions.
+For consensus to be considered healthy, the peers on the network should largely remain in sync with one another. It is particularly important for the validators to remain in sync, because that is required for participation in consensus. However, the network tolerates some validators being out of sync. Fundamentally, network health is a function of validators reaching consensus on sets of recently submitted transactions.
-Another factor to consider is
-the duration of the consensus process itself. This generally takes
-under 5 seconds on the main network under low volume. This is based on
-historical observations. However factors such as transaction volume
-can increase consensus duration. This is because xrpld performs
-more work as transaction volume increases. Under sufficient load this
-tends to increase consensus duration. It's possible that relatively high
-consensus duration indicates a problem, but it is not appropriate to
-conclude so without investigation. The upper limit for consensus
-duration should be roughly 20 seconds. That is far above the normal.
-If the network takes this long to close ledgers, then it is almost
-certain that there is a problem with the network. This circumstance
-often coincides with new ledgers with zero transactions.
+Another factor to consider is the duration of the consensus process itself. This generally takes under 5 seconds on the main network under low volume. This is based on historical observations. However factors such as transaction volume can increase consensus duration. This is because xrpld performs more work as transaction volume increases. Under sufficient load this tends to increase consensus duration. It's possible that relatively high consensus duration indicates a problem, but it is not appropriate to conclude so without investigation. The upper limit for consensus duration should be roughly 20 seconds. That is far above the normal. If the network takes this long to close ledgers, then it is almost certain that there is a problem with the network. This circumstance often coincides with new ledgers with zero transactions.
### Other Constants
-- _Base fee transaction limit per ledger_. The minimum value of 5 was
- chosen to ensure the limit never gets so small that the ledger becomes
- unusable. The "target" value of 50 was chosen so the limit never gets large
- enough to invite abuse, but keeps up if the network stays healthy and
- active. These exact values were chosen experimentally, and can easily
- change in the future.
-- _Expected ledger size growth and reduction percentages_. The growth
- value of 20% was chosen to allow the limit to grow quickly as load
- increases, but not so quickly as to allow bad actors to run unrestricted.
- The reduction value of 50% was chosen to cause the limit to drop
- significantly, but not so drastically that the limit cannot quickly
- recover if the problem is temporary. These exact values were chosen
- experimentally, and can easily change in the future.
-- _Minimum `lastLedgerMedianFeeLevel`_. The value of 500 was chosen to
- ensure that the first escalated fee was more significant and noticeable
- than what the default would allow. This exact value was chosen
- experimentally, and can easily change in the future.
-- _Transaction queue size limit_. The limit is computed based on the
- base fee transaction limit per ledger, so that the queue can grow
- automatically as the network's performance improves, allowing
- more transactions per second, and thus more transactions per ledger
- to process successfully. The limit of 20 ledgers was used to provide
- a balance between resource (specifically memory) usage, and giving
- transactions a realistic chance to be processed. The minimum size of
- 2000 transactions was chosen to allow a decent functional backlog during
- network congestion conditions. These exact values were
- chosen experimentally, and can easily change in the future.
-- _Maximum retries_. A transaction in the queue can attempt to apply
- to the open ledger, but get a retry (`ter`) code up to 10 times, at
- which point, it will be removed from the queue and dropped. The
- value was chosen to be large enough to allow temporary failures to clear
- up, but small enough that the queue doesn't fill up with stale
- transactions which prevent lower fee level, but more likely to succeed,
- transactions from queuing.
-- _Maximum transactions per account_. A single account can have up to 10
- transactions in the queue at any given time. This is primarily to
- mitigate the lost cost of broadcasting multiple transactions if one of
- the earlier ones fails or is otherwise removed from the queue without
- being applied to the open ledger. The value was chosen arbitrarily, and
- can easily change in the future.
-- _Minimum last ledger sequence buffer_. If a transaction has a
- `LastLedgerSequence` value, and cannot be processed into the open
- ledger, that `LastLedgerSequence` must be at least 2 more than the
- sequence number of the open ledger to be considered for the queue. The
- value was chosen to provide a balance between letting the user control
- the lifespan of the transaction, and giving a queued transaction a
- chance to get processed out of the queue before getting discarded,
- particularly since it may have dependent transactions also in the queue,
- which will never succeed if this one is discarded.
-- _Replaced transaction fee increase_. Any transaction in the queue can be
- replaced by another transaction with the same sequence number and at
- least a 25% higher fee level. The 25% increase is intended to cover the
- resource cost incurred by broadcasting the original transaction to the
- network. This value was chosen experimentally, and can easily change in
- the future.
+- _Base fee transaction limit per ledger_. The minimum value of 5 was chosen to ensure the limit never gets so small that the ledger becomes unusable. The "target" value of 50 was chosen so the limit never gets large enough to invite abuse, but keeps up if the network stays healthy and active. These exact values were chosen experimentally, and can easily change in the future.
+- _Expected ledger size growth and reduction percentages_. The growth value of 20% was chosen to allow the limit to grow quickly as load increases, but not so quickly as to allow bad actors to run unrestricted. The reduction value of 50% was chosen to cause the limit to drop significantly, but not so drastically that the limit cannot quickly recover if the problem is temporary. These exact values were chosen experimentally, and can easily change in the future.
+- _Minimum `lastLedgerMedianFeeLevel`_. The value of 500 was chosen to ensure that the first escalated fee was more significant and noticeable than what the default would allow. This exact value was chosen experimentally, and can easily change in the future.
+- _Transaction queue size limit_. The limit is computed based on the base fee transaction limit per ledger, so that the queue can grow automatically as the network's performance improves, allowing more transactions per second, and thus more transactions per ledger to process successfully. The limit of 20 ledgers was used to provide a balance between resource (specifically memory) usage, and giving transactions a realistic chance to be processed. The minimum size of 2000 transactions was chosen to allow a decent functional backlog during network congestion conditions. These exact values were chosen experimentally, and can easily change in the future.
+- _Maximum retries_. A transaction in the queue can attempt to apply to the open ledger, but get a retry (`ter`) code up to 10 times, at which point, it will be removed from the queue and dropped. The value was chosen to be large enough to allow temporary failures to clear up, but small enough that the queue doesn't fill up with stale transactions which prevent lower fee level, but more likely to succeed, transactions from queuing.
+- _Maximum transactions per account_. A single account can have up to 10 transactions in the queue at any given time. This is primarily to mitigate the lost cost of broadcasting multiple transactions if one of the earlier ones fails or is otherwise removed from the queue without being applied to the open ledger. The value was chosen arbitrarily, and can easily change in the future.
+- _Minimum last ledger sequence buffer_. If a transaction has a `LastLedgerSequence` value, and cannot be processed into the open ledger, that `LastLedgerSequence` must be at least 2 more than the sequence number of the open ledger to be considered for the queue. The value was chosen to provide a balance between letting the user control the lifespan of the transaction, and giving a queued transaction a chance to get processed out of the queue before getting discarded, particularly since it may have dependent transactions also in the queue, which will never succeed if this one is discarded.
+- _Replaced transaction fee increase_. Any transaction in the queue can be replaced by another transaction with the same sequence number and at least a 25% higher fee level. The 25% increase is intended to cover the resource cost incurred by broadcasting the original transaction to the network. This value was chosen experimentally, and can easily change in the future.
### `fee` command
-**The `fee` RPC and WebSocket command is still experimental, and may
-change without warning.**
+**The `fee` RPC and WebSocket command is still experimental, and may change without warning.**
-`fee` takes no parameters, and returns information about the current local
-[fee escalation](#fee-escalation) and [transaction queue](#transaction-queue)
-state as both fee levels and drops. The drop values assume a
-single-singed reference transaction. It is up to the user to compute the
-necessary fees for other types of transactions. (E.g. multiply all drop
-values by 5 for a multi-signed transaction with 4 signatures.)
+`fee` takes no parameters, and returns information about the current local [fee escalation](#fee-escalation) and [transaction queue](#transaction-queue) state as both fee levels and drops. The drop values assume a single-singed reference transaction. It is up to the user to compute the necessary fees for other types of transactions. (E.g. multiply all drop values by 5 for a multi-signed transaction with 4 signatures.)
-The `fee` result is always instantaneous, and relates to the open
-ledger. It includes the sequence number of the current open ledger,
-but may not make sense if xrpld is not synced to the network.
+The `fee` result is always instantaneous, and relates to the open ledger. It includes the sequence number of the current open ledger, but may not make sense if xrpld is not synced to the network.
Result format:
@@ -323,49 +135,23 @@ Result format:
### [`server_info`](https://xrpl.org/server_info.html) command
-**The fields listed here are still experimental, and may change
-without warning.**
+**The fields listed here are still experimental, and may change without warning.**
Up to two fields in `server_info` output are related to fee escalation.
-1. `load_factor_fee_escalation`: The factor on base transaction cost
- that a transaction must pay to get into the open ledger. This value can
- change quickly as transactions are processed from the network and
- ledgers are closed. If not escalated, the value is 1, so will not be
- returned.
-2. `load_factor_fee_queue`: If the queue is full, this is the factor on
- base transaction cost that a transaction must pay to get into the queue.
- If not full, the value is 1, so will not be returned.
+1. `load_factor_fee_escalation`: The factor on base transaction cost that a transaction must pay to get into the open ledger. This value can change quickly as transactions are processed from the network and ledgers are closed. If not escalated, the value is 1, so will not be returned.
+2. `load_factor_fee_queue`: If the queue is full, this is the factor on base transaction cost that a transaction must pay to get into the queue. If not full, the value is 1, so will not be returned.
-In all cases, the transaction fee must be high enough to overcome both
-`load_factor_fee_queue` and `load_factor` to be considered. It does not
-need to overcome `load_factor_fee_escalation`, though if it does not, it
-is more likely to be queued than immediately processed into the open
-ledger.
+In all cases, the transaction fee must be high enough to overcome both `load_factor_fee_queue` and `load_factor` to be considered. It does not need to overcome `load_factor_fee_escalation`, though if it does not, it is more likely to be queued than immediately processed into the open ledger.
### [`server_state`](https://xrpl.org/server_state.html) command
-**The fields listed here are still experimental, and may change
-without warning.**
+**The fields listed here are still experimental, and may change without warning.**
Three fields in `server_state` output are related to fee escalation.
-1. `load_factor_fee_escalation`: The factor on base transaction cost
- that a transaction must pay to get into the open ledger. This value can
- change quickly as transactions are processed from the network and
- ledgers are closed. The ratio between this value and
- `load_factor_fee_reference` determines the multiplier for transaction
- fees to get into the current open ledger.
-2. `load_factor_fee_queue`: This is the factor on base transaction cost
- that a transaction must pay to get into the queue. The ratio between
- this value and `load_factor_fee_reference` determines the multiplier for
- transaction fees to get into the transaction queue to be considered for
- a later ledger.
-3. `load_factor_fee_reference`: Like `load_base`, this is the baseline
- that is used to scale fee escalation computations.
+1. `load_factor_fee_escalation`: The factor on base transaction cost that a transaction must pay to get into the open ledger. This value can change quickly as transactions are processed from the network and ledgers are closed. The ratio between this value and `load_factor_fee_reference` determines the multiplier for transaction fees to get into the current open ledger.
+2. `load_factor_fee_queue`: This is the factor on base transaction cost that a transaction must pay to get into the queue. The ratio between this value and `load_factor_fee_reference` determines the multiplier for transaction fees to get into the transaction queue to be considered for a later ledger.
+3. `load_factor_fee_reference`: Like `load_base`, this is the baseline that is used to scale fee escalation computations.
-In all cases, the transaction fee must be high enough to overcome both
-`load_factor_fee_queue` and `load_factor` to be considered. It does not
-need to overcome `load_factor_fee_escalation`, though if it does not, it
-is more likely to be queued than immediately processed into the open
-ledger.
+In all cases, the transaction fee must be high enough to overcome both `load_factor_fee_queue` and `load_factor` to be considered. It does not need to overcome `load_factor_fee_escalation`, though if it does not, it is more likely to be queued than immediately processed into the open ledger.
diff --git a/src/xrpld/app/misc/README.md b/src/xrpld/app/misc/README.md
index 359f58578d..fe501544ef 100644
--- a/src/xrpld/app/misc/README.md
+++ b/src/xrpld/app/misc/README.md
@@ -1,155 +1,73 @@
# Fee Voting
-The XRPL payment protocol enforces a fee schedule expressed in units of the
-native currency, XRP. Fees for transactions are paid directly from the account
-owner. There are also reserve requirements for each item that occupies storage
-in the ledger. The reserve fee schedule contains both a per-account reserve,
-and a per-owned-item reserve. The items an account may own include active
-offers, trust lines, and tickets.
+The XRPL payment protocol enforces a fee schedule expressed in units of the native currency, XRP. Fees for transactions are paid directly from the account owner. There are also reserve requirements for each item that occupies storage in the ledger. The reserve fee schedule contains both a per-account reserve, and a per-owned-item reserve. The items an account may own include active offers, trust lines, and tickets.
-Validators may vote to increase fees if they feel that the network is charging
-too little. They may also vote to decrease fees if the fees are too costly
-relative to the value the network provides. One common case where a validator
-may want to change fees is when the value of the native currency XRP fluctuates
-relative to other currencies.
+Validators may vote to increase fees if they feel that the network is charging too little. They may also vote to decrease fees if the fees are too costly relative to the value the network provides. One common case where a validator may want to change fees is when the value of the native currency XRP fluctuates relative to other currencies.
-The fee voting mechanism takes place every 256 ledgers ("voting ledgers"). In
-a voting ledger, each validator takes a position on what they think the fees
-should be. The consensus process converges on the majority position, and in
-subsequent ledgers a new fee schedule is enacted.
+The fee voting mechanism takes place every 256 ledgers ("voting ledgers"). In a voting ledger, each validator takes a position on what they think the fees should be. The consensus process converges on the majority position, and in subsequent ledgers a new fee schedule is enacted.
## Consensus
-The XRPL consensus algorithm allows distributed participants to arrive at
-the same answer for yes/no questions. The canonical case for consensus is
-whether or not a particular transaction is included in the ledger. Fees
-present a more difficult challenge, since the decision on the new fee is not
-a yes or no question.
+The XRPL consensus algorithm allows distributed participants to arrive at the same answer for yes/no questions. The canonical case for consensus is whether or not a particular transaction is included in the ledger. Fees present a more difficult challenge, since the decision on the new fee is not a yes or no question.
-To convert validators' positions on fees into a yes or no question that can
-be converged in the consensus process, the following algorithm is used:
+To convert validators' positions on fees into a yes or no question that can be converged in the consensus process, the following algorithm is used:
-- In the ledger before a voting ledger, validators send proposals which also
- include the values they think the network should use for the new fee schedule.
+- In the ledger before a voting ledger, validators send proposals which also include the values they think the network should use for the new fee schedule.
-- In the voting ledger, validators examine the proposals from other validators
- and choose a new fee schedule which moves the fees in a direction closer to
- the validator's ideal fee schedule and is also likely to be accepted. A fee
- amount is likely to be accepted if a majority of validators agree on the
- number.
+- In the voting ledger, validators examine the proposals from other validators and choose a new fee schedule which moves the fees in a direction closer to the validator's ideal fee schedule and is also likely to be accepted. A fee amount is likely to be accepted if a majority of validators agree on the number.
-- Each validator injects a "pseudo transaction" into their proposed ledger
- which sets the fees to the chosen schedule.
+- Each validator injects a "pseudo transaction" into their proposed ledger which sets the fees to the chosen schedule.
-- The consensus process is applied to these fee-setting transactions as normal.
- Each transaction is either included in the ledger or not. In most cases, one
- fee setting transaction will make it in while the others are rejected. In
- some rare cases more than one fee setting transaction will make it in. The
- last one to be applied will take effect. This is harmless since a majority
- of validators still agreed on it.
+- The consensus process is applied to these fee-setting transactions as normal. Each transaction is either included in the ledger or not. In most cases, one fee setting transaction will make it in while the others are rejected. In some rare cases more than one fee setting transaction will make it in. The last one to be applied will take effect. This is harmless since a majority of validators still agreed on it.
-- After the voting ledger has been validated, future pseudo transactions
- before the next voting ledger are rejected as fee setting transactions may
- only appear in voting ledgers.
+- After the voting ledger has been validated, future pseudo transactions before the next voting ledger are rejected as fee setting transactions may only appear in voting ledgers.
## Configuration
-A validating instance of xrpld uses information in the configuration file
-to determine how it wants to vote on the fee schedule. It is the responsibility
-of the administrator to set these values.
+A validating instance of xrpld uses information in the configuration file to determine how it wants to vote on the fee schedule. It is the responsibility of the administrator to set these values.
---
# Amendment
-An Amendment is a new or proposed change to a ledger rule. Ledger rules affect
-transaction processing and consensus; peers must use the same set of rules for
-consensus to succeed, otherwise different instances of xrpld will get
-different results. Amendments can be almost anything but they must be accepted
-by a network majority through a consensus process before they are utilized. An
-Amendment must receive at least an 80% approval rate from validating nodes for
-a period of two weeks before being accepted. The following example outlines the
-process of an Amendment from its conception to approval and usage.
+An Amendment is a new or proposed change to a ledger rule. Ledger rules affect transaction processing and consensus; peers must use the same set of rules for consensus to succeed, otherwise different instances of xrpld will get different results. Amendments can be almost anything but they must be accepted by a network majority through a consensus process before they are utilized. An Amendment must receive at least an 80% approval rate from validating nodes for a period of two weeks before being accepted. The following example outlines the process of an Amendment from its conception to approval and usage.
-- A community member proposes to change transaction processing in some way.
- The proposal is discussed amongst the community and receives its support
- creating a community or human consensus.
+- A community member proposes to change transaction processing in some way. The proposal is discussed amongst the community and receives its support creating a community or human consensus.
- Some members contribute their time and work to develop the Amendment.
-- A pull request is created and the new code is folded into an xrpld build
- and made available for use.
+- A pull request is created and the new code is folded into an xrpld build and made available for use.
- The consensus process begins with the validating nodes.
-- If the Amendment holds an 80% majority for a two week period, nodes will begin
- including the transaction to enable it in their initial sets.
+- If the Amendment holds an 80% majority for a two week period, nodes will begin including the transaction to enable it in their initial sets.
-Nodes may veto Amendments they consider undesirable by never announcing their
-support for those Amendments. Just a few nodes vetoing an Amendment will normally
-keep it from being accepted. Nodes could also vote yes on an Amendments even
-before it obtains a super-majority. This might make sense for a critical bug fix.
+Nodes may veto Amendments they consider undesirable by never announcing their support for those Amendments. Just a few nodes vetoing an Amendment will normally keep it from being accepted. Nodes could also vote yes on an Amendments even before it obtains a super-majority. This might make sense for a critical bug fix.
-Validators that support an amendment that is not yet enabled announce their
-support in their validations. If 80% support is achieved, they will introduce
-a pseudo-transaction to track the amendment's majority status in the ledger.
+Validators that support an amendment that is not yet enabled announce their support in their validations. If 80% support is achieved, they will introduce a pseudo-transaction to track the amendment's majority status in the ledger.
-If an amendment whose majority status is reported in a ledger loses that
-majority status, validators will introduce pseudo-transactions to remove
-the majority status from the ledger.
+If an amendment whose majority status is reported in a ledger loses that majority status, validators will introduce pseudo-transactions to remove the majority status from the ledger.
-If an amendment holds majority status for two weeks, validators will
-introduce a pseudo-transaction to enable the amendment.
+If an amendment holds majority status for two weeks, validators will introduce a pseudo-transaction to enable the amendment.
-All amendments are assumed to be critical and irreversible. Thus there
-is no mechanism to disable or revoke an amendment, nor is there a way
-for a server to operate while an amendment it does not understand is
-enabled.
+All amendments are assumed to be critical and irreversible. Thus there is no mechanism to disable or revoke an amendment, nor is there a way for a server to operate while an amendment it does not understand is enabled.
---
# SHAMapStore: Online Delete
-Optional online deletion happens through the SHAMapStore. Records are deleted
-from disk based on ledger sequence number. These records reside in the
-key-value database as well as in the SQLite ledger and transaction databases.
-Without online deletion storage usage grows without bounds. It can only
-be pruned by stopping, manually deleting data, and restarting the server.
-Online deletion requires less operator intervention to manage the server.
+Optional online deletion happens through the SHAMapStore. Records are deleted from disk based on ledger sequence number. These records reside in the key-value database as well as in the SQLite ledger and transaction databases. Without online deletion storage usage grows without bounds. It can only be pruned by stopping, manually deleting data, and restarting the server. Online deletion requires less operator intervention to manage the server.
-The main mechanism to delete data from the key-value database is to keep two
-databases open at all times. One database has all writes directed to it. The
-other database has recent archival data from just prior to that from the current
-writable database.
-Upon rotation, the archival database is deleted. The writable database becomes
-archival, and a brand new database becomes writable. To ensure that no
-necessary data for transaction processing is lost, a variety of steps occur,
-including copying the contents of an entire ledger's account state map,
-clearing caches, and copying the contents of (freshening) other caches.
+The main mechanism to delete data from the key-value database is to keep two databases open at all times. One database has all writes directed to it. The other database has recent archival data from just prior to that from the current writable database. Upon rotation, the archival database is deleted. The writable database becomes archival, and a brand new database becomes writable. To ensure that no necessary data for transaction processing is lost, a variety of steps occur, including copying the contents of an entire ledger's account state map, clearing caches, and copying the contents of (freshening) other caches.
-Deleting from SQLite involves more straight-forward SQL DELETE queries from
-the respective tables, with a rudimentary back-off algorithm to do portions
-of the deletions at a time. This back-off is in place so that the database
-lock is not held excessively. The SQLite database is not configured to
-delete on-disk storage, so it will grow over time. However, with online delete
-enabled, it grows at a very small rate compared with the key-value store.
+Deleting from SQLite involves more straight-forward SQL DELETE queries from the respective tables, with a rudimentary back-off algorithm to do portions of the deletions at a time. This back-off is in place so that the database lock is not held excessively. The SQLite database is not configured to delete on-disk storage, so it will grow over time. However, with online delete enabled, it grows at a very small rate compared with the key-value store.
-The online delete routine aborts its current activities if it fails periodic
-server health checks. This minimizes impact of I/O and locking of critical
-objects. If interrupted, the routine will start again at the next validated
-ledger close. Likewise, the routine will continue in a similar fashion if the
-server restarts.
+The online delete routine aborts its current activities if it fails periodic server health checks. This minimizes impact of I/O and locking of critical objects. If interrupted, the routine will start again at the next validated ledger close. Likewise, the routine will continue in a similar fashion if the server restarts.
Configuration:
-- In the [node_db] configuration section, an optional online_delete parameter is
- set. If not set or if set to 0, online delete is disabled. Otherwise, the
- setting defines number of ledgers between deletion cycles.
-- Another optional parameter in [node_db] is that for advisory_delete. It is
- disabled by default. If set to non-zero, requires an RPC call to activate the
- deletion routine.
+- In the [node_db] configuration section, an optional online_delete parameter is set. If not set or if set to 0, online delete is disabled. Otherwise, the setting defines number of ledgers between deletion cycles.
+- Another optional parameter in [node_db] is that for advisory_delete. It is disabled by default. If set to non-zero, requires an RPC call to activate the deletion routine.
- online_delete must not be greater than the [ledger_history] parameter.
-- [fetch_depth] will be silently set to equal the online_delete setting if
- online_delete is greater than fetch_depth.
-- In the [node_db] section, there is a performance tuning option, delete_batch,
- which sets the maximum size in ledgers for each SQL DELETE query.
+- [fetch_depth] will be silently set to equal the online_delete setting if online_delete is greater than fetch_depth.
+- In the [node_db] section, there is a performance tuning option, delete_batch, which sets the maximum size in ledgers for each SQL DELETE query.
diff --git a/src/xrpld/app/rdb/README.md b/src/xrpld/app/rdb/README.md
index 53e6b0c6fa..0ff006dc51 100644
--- a/src/xrpld/app/rdb/README.md
+++ b/src/xrpld/app/rdb/README.md
@@ -46,16 +46,16 @@ src/xrpld/app/rdb/
### File Contents
-| File | Contents |
-| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `Node.[h\|cpp]` | Defines/Implements methods used by `SQLiteDatabase` for interacting with SQLite node databases |
+| File | Contents |
+| --- | --- |
+| `Node.[h\|cpp]` | Defines/Implements methods used by `SQLiteDatabase` for interacting with SQLite node databases |
| `SQLiteDatabase.[h\|cpp]` | Defines/Implements the class `SQLiteDatabase`/`SQLiteDatabaseImp` which inherits from `RelationalDatabase` and is used to operate on the main stores |
-| `PeerFinder.[h\|cpp]` | Defines/Implements methods for interacting with the PeerFinder SQLite database |
-| `RelationalDatabase.cpp` | Implements the static method `RelationalDatabase::init` which is used to initialize an instance of `RelationalDatabase` |
-| `RelationalDatabase.h` | Defines the abstract class `RelationalDatabase`, the primary class of the Relational Database Interface |
-| `State.[h\|cpp]` | Defines/Implements methods for interacting with the State SQLite database which concerns ledger deletion and database rotation |
-| `Vacuum.[h\|cpp]` | Defines/Implements a method for performing the `VACUUM` operation on SQLite databases |
-| `Wallet.[h\|cpp]` | Defines/Implements methods for interacting with Wallet SQLite databases |
+| `PeerFinder.[h\|cpp]` | Defines/Implements methods for interacting with the PeerFinder SQLite database |
+| `RelationalDatabase.cpp` | Implements the static method `RelationalDatabase::init` which is used to initialize an instance of `RelationalDatabase` |
+| `RelationalDatabase.h` | Defines the abstract class `RelationalDatabase`, the primary class of the Relational Database Interface |
+| `State.[h\|cpp]` | Defines/Implements methods for interacting with the State SQLite database which concerns ledger deletion and database rotation |
+| `Vacuum.[h\|cpp]` | Defines/Implements a method for performing the `VACUUM` operation on SQLite databases |
+| `Wallet.[h\|cpp]` | Defines/Implements methods for interacting with Wallet SQLite databases |
## Classes
diff --git a/src/xrpld/overlay/README.md b/src/xrpld/overlay/README.md
index bda0027ea7..14093812b6 100644
--- a/src/xrpld/overlay/README.md
+++ b/src/xrpld/overlay/README.md
@@ -2,55 +2,31 @@
## Introduction
-The _XRP Ledger network_ consists of a collection of _peers_ running
-**`xrpld`** or other compatible software. Each peer maintains multiple
-outgoing connections and optional incoming connections to other peers.
-These connections are made over both the public Internet and private local
-area networks. This network defines a connected directed graph of nodes
-where vertices are instances of `xrpld` and edges are persistent TCP/IP
-connections. Peers send and receive messages to other connected peers. This
-peer to peer network, layered on top of the public and private Internet,
-forms an [_overlay network_][overlay_network]. The contents of the messages
-and the behavior of peers in response to the messages, plus the information
-exchanged during the handshaking phase of connection establishment, defines
-the _XRP Ledger peer protocol_ (or _protocol_ in this context).
+The _XRP Ledger network_ consists of a collection of _peers_ running **`xrpld`** or other compatible software. Each peer maintains multiple outgoing connections and optional incoming connections to other peers. These connections are made over both the public Internet and private local area networks. This network defines a connected directed graph of nodes where vertices are instances of `xrpld` and edges are persistent TCP/IP connections. Peers send and receive messages to other connected peers. This peer to peer network, layered on top of the public and private Internet, forms an [_overlay network_][overlay_network]. The contents of the messages and the behavior of peers in response to the messages, plus the information exchanged during the handshaking phase of connection establishment, defines the _XRP Ledger peer protocol_ (or _protocol_ in this context).
## Overview
-Each connection is represented by a _Peer_ object. The Overlay manager
-establishes, receives, and maintains connections to peers. Protocol
-messages are exchanged between peers and serialized using
-[_Google Protocol Buffers_][protocol_buffers].
+Each connection is represented by a _Peer_ object. The Overlay manager establishes, receives, and maintains connections to peers. Protocol messages are exchanged between peers and serialized using [_Google Protocol Buffers_][protocol_buffers].
### Structure
-Each connection between peers is identified by its connection type, which
-affects the behavior of message routing. At present, only a single connection
-type is supported: **Peer**.
+Each connection between peers is identified by its connection type, which affects the behavior of message routing. At present, only a single connection type is supported: **Peer**.
## Handshake
-To establish a protocol connection, a peer makes an outgoing TLS encrypted
-connection to a remote peer, then sends an HTTP request with no message body.
+To establish a protocol connection, a peer makes an outgoing TLS encrypted connection to a remote peer, then sends an HTTP request with no message body.
### HTTP
The HTTP [request](https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html) must:
- Use HTTP version 1.1.
-- Specify a request URI consisting of a single forward slash character ("/")
- indicating the server root. Requests using different URIs are reserved for
- future protocol implementations.
-- Use the [_HTTP/1.1 Upgrade_][upgrade_header] mechanism with additional custom
- fields to communicate protocol specific information related to the upgrade.
+- Specify a request URI consisting of a single forward slash character ("/") indicating the server root. Requests using different URIs are reserved for future protocol implementations.
+- Use the [_HTTP/1.1 Upgrade_][upgrade_header] mechanism with additional custom fields to communicate protocol specific information related to the upgrade.
-HTTP requests which do not conform to this requirements must generate an
-appropriate HTTP error and result in the connection being closed.
+HTTP requests which do not conform to this requirements must generate an appropriate HTTP error and result in the connection being closed.
-Upon receipt of a well-formed HTTP upgrade request, and validation of the
-protocol specific parameters, a peer will either send back a HTTP 101 response
-and switch to the requested protocol, or a message indicating that the request
-failed (e.g. by sending HTTP 400 "Bad Request" or HTTP 503 "Service Unavailable").
+Upon receipt of a well-formed HTTP upgrade request, and validation of the protocol specific parameters, a peer will either send back a HTTP 101 response and switch to the requested protocol, or a message indicating that the request failed (e.g. by sending HTTP 400 "Bad Request" or HTTP 503 "Service Unavailable").
##### Example HTTP Upgrade Request
@@ -105,10 +81,7 @@ Content-Type: application/json
| ------------ | :----------------: | :------: |
| `User-Agent` | :heavy_check_mark: | |
-The `User-Agent` field indicates the version of the software that the
-peer that is making the HTTP request is using. No semantic meaning is
-assigned to the value in this field but it is recommended that implementations
-specify the version of the software that is used.
+The `User-Agent` field indicates the version of the software that the peer that is making the HTTP request is using. No semantic meaning is assigned to the value in this field but it is recommended that implementations specify the version of the software that is used.
See [RFC2616 §14.43](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43).
@@ -116,10 +89,7 @@ See [RFC2616 §14.43](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.htm
| ---------- | :-----: | :----------------: |
| `Server` | | :heavy_check_mark: |
-The `Server` field indicates the version of the software that the
-peer that is processing the HTTP request is using. No semantic meaning is
-assigned to the value in this field but it is recommended that implementations
-specify the version of the software that is used.
+The `Server` field indicates the version of the software that the peer that is processing the HTTP request is using. No semantic meaning is assigned to the value in this field but it is recommended that implementations specify the version of the software that is used.
See [RFC2616 §14.38](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.38).
@@ -127,8 +97,7 @@ See [RFC2616 §14.38](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.htm
| ------------ | :----------------: | :----------------: |
| `Connection` | :heavy_check_mark: | :heavy_check_mark: |
-The `Connection` field should have a value of `Upgrade` to indicate that a
-request to upgrade the connection is being performed.
+The `Connection` field should have a value of `Upgrade` to indicate that a request to upgrade the connection is being performed.
See [RFC2616 §14.10](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.10).
@@ -136,22 +105,13 @@ See [RFC2616 §14.10](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.htm
| ---------- | :----------------: | :----------------: |
| `Upgrade` | :heavy_check_mark: | :heavy_check_mark: |
-The `Upgrade` field is part of the standard connection upgrade mechanism and
-must be present in both requests and responses. It is used to negotiate the
-version of the protocol that will be used after the upgrade request completes.
+The `Upgrade` field is part of the standard connection upgrade mechanism and must be present in both requests and responses. It is used to negotiate the version of the protocol that will be used after the upgrade request completes.
-For requests, it should consist of a comma delimited list of at least one
-element, where each element specifies a protocol version that the requesting
-server is willing to use.
+For requests, it should consist of a comma delimited list of at least one element, where each element specifies a protocol version that the requesting server is willing to use.
-For responses, it should a consist of _single element_ matching one of the
-elements provided in the corresponding request. If the server does not understand
-any of the available protocol versions, the upgrade request should fail with an
-appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response).
+For responses, it should a consist of _single element_ matching one of the elements provided in the corresponding request. If the server does not understand any of the available protocol versions, the upgrade request should fail with an appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response).
-Protocol versions are string of the form `XRPL/` followed by a dotted major
-and minor protocol version number, where the major number is greater than or
-equal to 2 and the minor is greater than or equal to 0.
+Protocol versions are string of the form `XRPL/` followed by a dotted major and minor protocol version number, where the major number is greater than or equal to 2 and the minor is greater than or equal to 0.
See [RFC 2616 §14.42](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.42)
@@ -161,77 +121,56 @@ See [RFC 2616 §14.42](https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.ht
| ------------ | :----------------: | :----------------: |
| `Connect-As` | :heavy_check_mark: | :heavy_check_mark: |
-The mandatory `Connect-As` field is used to specify that type of connection
-that is being requested.
+The mandatory `Connect-As` field is used to specify that type of connection that is being requested.
-For requests the value consists of a comma delimited list of elements, where
-each element describes a possible connection type. Only one connection types
-is supported at present: **`peer`**.
+For requests the value consists of a comma delimited list of elements, where each element describes a possible connection type. Only one connection types is supported at present: **`peer`**.
-For responses, the value must consist of exactly one element from the list of
-elements specified in the request. If a server processing a request does not
-recognize any of the connection types, the request should fail with an
-appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response).
+For responses, the value must consist of exactly one element from the list of elements specified in the request. If a server processing a request does not recognize any of the connection types, the request should fail with an appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response).
| Field Name | Request | Response |
| ----------- | :----------------: | :----------------: |
| `Remote-IP` | :white_check_mark: | :white_check_mark: |
-The optional `Remote-IP` field contains the string representation of the IP
-address of the remote end of the connection as seen from the peer that is
-sending the field.
+The optional `Remote-IP` field contains the string representation of the IP address of the remote end of the connection as seen from the peer that is sending the field.
-By observing values of this field from a sufficient number of different
-servers, a peer making outgoing connections can deduce its own IP address.
+By observing values of this field from a sufficient number of different servers, a peer making outgoing connections can deduce its own IP address.
| Field Name | Request | Response |
| ---------- | :----------------: | :----------------: |
| `Local-IP` | :white_check_mark: | :white_check_mark: |
-The optional `Local-IP` field contains the string representation of the IP
-address that the peer sending the field believes to be its own.
+The optional `Local-IP` field contains the string representation of the IP address that the peer sending the field believes to be its own.
-Servers receiving this field can detect IP address mismatches, which may
-indicate a potential man-in-the-middle attack.
+Servers receiving this field can detect IP address mismatches, which may indicate a potential man-in-the-middle attack.
| Field Name | Request | Response |
| ------------ | :----------------: | :----------------: |
| `Network-ID` | :white_check_mark: | :white_check_mark: |
-The optional `Network-ID` can be used to identify to which of several
-[parallel networks](https://xrpl.org/parallel-networks.html) the server
-sending the field is joined.
+The optional `Network-ID` can be used to identify to which of several [parallel networks](https://xrpl.org/parallel-networks.html) the server sending the field is joined.
-The value, if the field is present, is a 32-bit unsigned integer. The
-following well-known values are in use:
+The value, if the field is present, is a 32-bit unsigned integer. The following well-known values are in use:
- **0**: The "main net"
- **1**: The Ripple-operated [Test Net](https://xrpl.org/xrp-test-net-faucet.html).
-If a server configured to join one network receives a connection request from a
-server configured to join another network, the request should fail with an
-appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response).
+If a server configured to join one network receives a connection request from a server configured to join another network, the request should fail with an appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response).
| Field Name | Request | Response |
| -------------- | :----------------: | :----------------: |
| `Network-Time` | :white_check_mark: | :white_check_mark: |
-The optional `Network-Time` field reports the current [time](https://xrpl.org/basic-data-types.html#specifying-time)
-according to sender's internal clock.
+The optional `Network-Time` field reports the current [time](https://xrpl.org/basic-data-types.html#specifying-time) according to sender's internal clock.
-Servers should fail a connection if their clocks are not within 20 seconds of
-each other with an appropriate HTTP error code (e.g. by sending an HTTP 400
-"Bad Request" response).
+Servers should fail a connection if their clocks are not within 20 seconds of each other with an appropriate HTTP error code (e.g. by sending an HTTP 400 "Bad Request" response).
-It is highly recommended that servers synchronize their clocks using time
-synchronization software. For more on this topic, please visit [ntp.org](http://www.ntp.org/).
+It is highly recommended that servers synchronize their clocks using time synchronization software. For more on this topic, please visit [ntp.org](http://www.ntp.org/).
| Field Name | Request | Response |
| ------------ | :----------------: | :----------------: |
| `Public-Key` | :heavy_check_mark: | :heavy_check_mark: |
-The mandatory `Public-Key` field identifies the sending server's public key,
-encoded in base58 using the standard encoding for node public keys.
+The mandatory `Public-Key` field identifies the sending server's public key, encoded in base58 using the standard encoding for node public keys.
See: https://xrpl.org/base58-encodings.html
@@ -239,15 +178,9 @@ See: https://xrpl.org/base58-encodings.html
| --------------- | :----------------: | :----------------: |
| `Server-Domain` | :white_check_mark: | :white_check_mark: |
-The optional `Server-Domain` field allows a server to report the domain that
-it is operating under. The value is configured by the server administrator in
-the configuration file using the `[server_domain]` key.
+The optional `Server-Domain` field allows a server to report the domain that it is operating under. The value is configured by the server administrator in the configuration file using the `[server_domain]` key.
-The value is advisory and is not used by the code at this time, except for
-reporting purposes. External tools should verify this value prior to using
-it by attempting to locate a [TOML file](https://xrpl.org/xrp-ledger-toml.html)
-under the specified domain and locating the public key of this server under the
-`[NODES]` key.
+The value is advisory and is not used by the code at this time, except for reporting purposes. External tools should verify this value prior to using it by attempting to locate a [TOML file](https://xrpl.org/xrp-ledger-toml.html) under the specified domain and locating the public key of this server under the `[NODES]` key.
Sending a malformed domain will prevent a connection from being established.
@@ -255,11 +188,9 @@ Sending a malformed domain will prevent a connection from being established.
| ------------------- | :----------------: | :----------------: |
| `Session-Signature` | :heavy_check_mark: | :heavy_check_mark: |
-The `Session-Signature` field is mandatory and is used to secure the peer link
-against certain types of attack. For more details see "Session Signature" below.
+The `Session-Signature` field is mandatory and is used to secure the peer link against certain types of attack. For more details see "Session Signature" below.
-The value is presently encoded using **Base64** encoding, but implementations
-should support both **Base64** and **HEX** encoding for this value.
+The value is presently encoded using **Base64** encoding, but implementations should support both **Base64** and **HEX** encoding for this value.
For more details on this field, please see **Session Signature** below.
@@ -267,15 +198,12 @@ For more details on this field, please see **Session Signature** below.
| ---------- | :----------------: | :----------------: |
| `Crawl` | :white_check_mark: | :white_check_mark: |
-The optional `Crawl` field can be used by a server to indicate whether peers
-should include it in crawl reports.
+The optional `Crawl` field can be used by a server to indicate whether peers should include it in crawl reports.
The field can take two values:
-- **`Public`**: The server's IP address and port should be included in crawl
- reports.
-- **`Private`**: The server's IP address and port should not be included in
- crawl reports. _This is the default, if the field is omitted._
+- **`Public`**: The server's IP address and port should be included in crawl reports.
+- **`Private`**: The server's IP address and port should not be included in crawl reports. _This is the default, if the field is omitted._
For more on the Peer Crawler, please visit https://xrpl.org/peer-crawler.html.
@@ -283,106 +211,57 @@ For more on the Peer Crawler, please visit https://xrpl.org/peer-crawler.html.
| --------------- | :----------------: | :----------------: |
| `Closed-Ledger` | :white_check_mark: | :white_check_mark: |
-If present, identifies the hash of the last ledger that the sending server
-considers to be closed.
+If present, identifies the hash of the last ledger that the sending server considers to be closed.
-The value is encoded as **HEX**, but implementations should support both
-**Base64** and **HEX** encoding for this value for legacy purposes.
+The value is encoded as **HEX**, but implementations should support both **Base64** and **HEX** encoding for this value for legacy purposes.
| Field Name | Request | Response |
| ----------------- | :----------------: | :----------------: |
| `Previous-Ledger` | :white_check_mark: | :white_check_mark: |
-If present, identifies the hash of the parent ledger that the sending server
-considers to be closed.
+If present, identifies the hash of the parent ledger that the sending server considers to be closed.
-The value is presently encoded using **Base64** encoding, but implementations
-should support both **Base64** and **HEX** encoding for this value.
+The value is presently encoded using **Base64** encoding, but implementations should support both **Base64** and **HEX** encoding for this value.
#### Additional Headers
-An implementation or operator may specify additional, optional fields
-and values in both requests and responses.
+An implementation or operator may specify additional, optional fields and values in both requests and responses.
-Implementations should not reject requests because of the presence of fields
-that they do not understand.
+Implementations should not reject requests because of the presence of fields that they do not understand.
### Session Signature
-Even for SSL/TLS encrypted connections, it is possible for an attacker to mount
-relatively inexpensive MITM attacks that can be extremely hard to detect and
-may afford the attacker the ability to intelligently tamper with messages
-exchanged between the two endpoints.
+Even for SSL/TLS encrypted connections, it is possible for an attacker to mount relatively inexpensive MITM attacks that can be extremely hard to detect and may afford the attacker the ability to intelligently tamper with messages exchanged between the two endpoints.
-This risk can be mitigated if at least one side has a certificate from a certificate
-authority trusted by the other endpoint, but having a certificate is not always
-possible (or even desirable) in a decentralized and permissionless network.
+This risk can be mitigated if at least one side has a certificate from a certificate authority trusted by the other endpoint, but having a certificate is not always possible (or even desirable) in a decentralized and permissionless network.
-Ultimately, the goal is to ensure that two endpoints A and B know that they are
-talking directly to each other over a single end-to-end SSL/TLS session instead
-of two separate SSL/TLS sessions, with an attacker acting as a proxy.
+Ultimately, the goal is to ensure that two endpoints A and B know that they are talking directly to each other over a single end-to-end SSL/TLS session instead of two separate SSL/TLS sessions, with an attacker acting as a proxy.
-The XRP Ledger protocol prevents this attack by leveraging the fact that the two
-servers each have a node identity, in the form of **`secp256k1`** keypairs, and
-use that to strongly bind the SSL/TLS session to the node identities of each of
-the two servers at the end of the SSL/TLS session.
+The XRP Ledger protocol prevents this attack by leveraging the fact that the two servers each have a node identity, in the form of **`secp256k1`** keypairs, and use that to strongly bind the SSL/TLS session to the node identities of each of the two servers at the end of the SSL/TLS session.
-To do this we "reach into" the SSL/TLS session, and extract the **`finished`**
-messages for the local and remote endpoints, and combine them to generate a unique
-"fingerprint". By design, this fingerprint should be the same for both SSL/TLS
-endpoints.
+To do this we "reach into" the SSL/TLS session, and extract the **`finished`** messages for the local and remote endpoints, and combine them to generate a unique "fingerprint". By design, this fingerprint should be the same for both SSL/TLS endpoints.
-That fingerprint is calculated by each endpoint independently, so the
-fingerprint is never transmitted over the network. Each server then utilizes its
-private key to sign the fingerprint. This is the same keypair that determines
-the server's public `secp256k1` node identity. The signature is transferred over
-the secure SSL/TLS encrypted link during the protocol's initial handshake phase.
+That fingerprint is calculated by each endpoint independently, so the fingerprint is never transmitted over the network. Each server then utilizes its private key to sign the fingerprint. This is the same keypair that determines the server's public `secp256k1` node identity. The signature is transferred over the secure SSL/TLS encrypted link during the protocol's initial handshake phase.
-Each side of the link will verify that the provided signature is from the claimed
-public key against the session's unique fingerprint. If this signature check fails
-then the link **MUST** be dropped.
+Each side of the link will verify that the provided signature is from the claimed public key against the session's unique fingerprint. If this signature check fails then the link **MUST** be dropped.
-If an attacker, Eve, establishes two separate SSL sessions with Alice and Bob, the
-fingerprints of the two sessions will be different, and Eve will not be able to
-sign the fingerprint of her session with Bob with Alice's private key, or the
-fingerprint of her session with Alice with Bob's private key, and so both A and
-B will know that an active MITM attack is in progress and will close their
-connections.
+If an attacker, Eve, establishes two separate SSL sessions with Alice and Bob, the fingerprints of the two sessions will be different, and Eve will not be able to sign the fingerprint of her session with Bob with Alice's private key, or the fingerprint of her session with Alice with Bob's private key, and so both A and B will know that an active MITM attack is in progress and will close their connections.
-If Eve simply proxies the raw bytes, she will be unable to decrypt the data being
-transferred between A and B and will not be able to intelligently tamper with the
-message stream between Alice and Bob, although she may be still be able to inject
-delays or terminate the link.
+If Eve simply proxies the raw bytes, she will be unable to decrypt the data being transferred between A and B and will not be able to intelligently tamper with the message stream between Alice and Bob, although she may be still be able to inject delays or terminate the link.
# XRPL clustering
-A cluster consists of more than one XRPL server under common
-administration that share load information, distribute cryptography
-operations, and provide greater response consistency.
+A cluster consists of more than one XRPL server under common administration that share load information, distribute cryptography operations, and provide greater response consistency.
-Cluster nodes are identified by their public node keys. Cluster nodes
-exchange information about endpoints that are imposing load upon them.
-Cluster nodes share information about their internal load status. Cluster
-nodes do not have to verify the cryptographic signatures on messages
-received from other cluster nodes.
+Cluster nodes are identified by their public node keys. Cluster nodes exchange information about endpoints that are imposing load upon them. Cluster nodes share information about their internal load status. Cluster nodes do not have to verify the cryptographic signatures on messages received from other cluster nodes.
## Configuration
-A server's public key can be determined from the output of the `server_info`
-command. The key is in the `pubkey_node` value, and is a text string
-beginning with the letter `n`. The key is maintained across runs in a
-database.
+A server's public key can be determined from the output of the `server_info` command. The key is in the `pubkey_node` value, and is a text string beginning with the letter `n`. The key is maintained across runs in a database.
-Cluster members are configured in the `xrpld.cfg` file under
-`[cluster_nodes]`. Each member should be configured on a line beginning
-with the node public key, followed optionally by a space and a friendly
-name.
+Cluster members are configured in the `xrpld.cfg` file under `[cluster_nodes]`. Each member should be configured on a line beginning with the node public key, followed optionally by a space and a friendly name.
-Because cluster members can introduce other cluster members, it is not
-necessary to configure every cluster member on every other cluster member.
-If a hub and spoke system is used, it is sufficient to configure every
-cluster member on the hub(s) and only configure the hubs on the spokes.
-That is, each spoke does not need to be configured on every other spoke.
+Because cluster members can introduce other cluster members, it is not necessary to configure every cluster member on every other cluster member. If a hub and spoke system is used, it is sufficient to configure every cluster member on the hub(s) and only configure the hubs on the spokes. That is, each spoke does not need to be configured on every other spoke.
New spokes can be added as follows:
@@ -394,53 +273,27 @@ New spokes can be added as follows:
## Transaction Behavior
-When a transaction is received from a cluster member, several normal checks
-are bypassed:
+When a transaction is received from a cluster member, several normal checks are bypassed:
-Signature checking is bypassed because we trust that a cluster member would
-not relay a transaction with an incorrect signature. Validators may wish to
-disable this feature, preferring the additional load to get the additional
-security of having validators check each transaction.
+Signature checking is bypassed because we trust that a cluster member would not relay a transaction with an incorrect signature. Validators may wish to disable this feature, preferring the additional load to get the additional security of having validators check each transaction.
-Local checks for transaction checking are also bypassed. For example, a
-server will not reject a transaction from a cluster peer because the fee
-does not meet its current relay fee. It is preferable to keep the cluster
-in agreement and permit confirmation from one cluster member to more
-reliably indicate the transaction's acceptance by the cluster.
+Local checks for transaction checking are also bypassed. For example, a server will not reject a transaction from a cluster peer because the fee does not meet its current relay fee. It is preferable to keep the cluster in agreement and permit confirmation from one cluster member to more reliably indicate the transaction's acceptance by the cluster.
## Server Load Information
-Cluster members exchange information on their server's load level. The load
-level is essentially the amount by which the normal fee levels are multiplied
-to get the server's fee for relaying transactions.
+Cluster members exchange information on their server's load level. The load level is essentially the amount by which the normal fee levels are multiplied to get the server's fee for relaying transactions.
-A server's effective load level, and the one it uses to determine its relay
-fee, is the highest of its local load level, the network load level, and the
-cluster load level. The cluster load level is the median load level reported
-by a cluster member.
+A server's effective load level, and the one it uses to determine its relay fee, is the highest of its local load level, the network load level, and the cluster load level. The cluster load level is the median load level reported by a cluster member.
## Gossip
-Gossip is the mechanism by which cluster members share information about
-endpoints (typically IPv4 addresses) that are imposing unusually high load
-on them. The endpoint load manager takes into account gossip to reduce the
-amount of load the endpoint is permitted to impose on the local server
-before it is warned, disconnected, or banned.
+Gossip is the mechanism by which cluster members share information about endpoints (typically IPv4 addresses) that are imposing unusually high load on them. The endpoint load manager takes into account gossip to reduce the amount of load the endpoint is permitted to impose on the local server before it is warned, disconnected, or banned.
-Suppose, for example, that an attacker controls a large number of IP
-addresses, and with these, he can send sufficient requests to overload a
-server. Without gossip, he could use these same addresses to overload all
-the servers in a cluster. With gossip, if he chooses to use the same IP
-address to impose load on more than one server, he will find that the amount
-of load he can impose before getting disconnected is much lower.
+Suppose, for example, that an attacker controls a large number of IP addresses, and with these, he can send sufficient requests to overload a server. Without gossip, he could use these same addresses to overload all the servers in a cluster. With gossip, if he chooses to use the same IP address to impose load on more than one server, he will find that the amount of load he can impose before getting disconnected is much lower.
## Monitoring
-The `peers` command will report on the status of the cluster. The `cluster`
-object will contain one entry for each member of the cluster (either configured
-or introduced by another cluster member). The `age` field is the number of
-seconds since the server was last heard from. If the server is reporting an
-elevated cluster fee, that will be reported as well.
+The `peers` command will report on the status of the cluster. The `cluster` object will contain one entry for each member of the cluster (either configured or introduced by another cluster member). The `age` field is the number of seconds since the server was last heard from. If the server is reporting an elevated cluster fee, that will be reported as well.
In the `peers` object, cluster members will contain a `cluster` field set to `true`.
diff --git a/src/xrpld/peerfinder/README.md b/src/xrpld/peerfinder/README.md
index e6eda747ce..52df3a8ccb 100644
--- a/src/xrpld/peerfinder/README.md
+++ b/src/xrpld/peerfinder/README.md
@@ -2,36 +2,19 @@
## Introduction
-The _XRPL payment network_ consists of a collection of _peers_ running the
-**xrpld software**. Each peer maintains multiple outgoing connections and
-optional incoming connections to other peers. These connections are made over
-both the public Internet and private local area networks. This network defines
-a fully connected directed graph of nodes. Peers send and receive messages to
-other connected peers. This peer to peer network, layered on top of the public
-and private Internet, forms an [_overlay network_][overlay_network].
+The _XRPL payment network_ consists of a collection of _peers_ running the **xrpld software**. Each peer maintains multiple outgoing connections and optional incoming connections to other peers. These connections are made over both the public Internet and private local area networks. This network defines a fully connected directed graph of nodes. Peers send and receive messages to other connected peers. This peer to peer network, layered on top of the public and private Internet, forms an [_overlay network_][overlay_network].
## Bootstrapping
-When a peer comes online it needs a set of IP addresses to connect to in order to
-gain initial entry into the overlay in a process called _bootstrapping_. Once they
-have established an initial set of these outbound peer connections, they need to
-gain additional addresses to establish more outbound peer connections until the
-desired limit is reached. Furthermore, they need a mechanism to advertise their
-IP address to new or existing peers in the overlay so they may receive inbound
-connections up to some desired limit. And finally, they need a mechanism to provide
-inbound connection requests with an alternate set of IP addresses to try when they
-have already reached their desired maximum number of inbound connections.
+When a peer comes online it needs a set of IP addresses to connect to in order to gain initial entry into the overlay in a process called _bootstrapping_. Once they have established an initial set of these outbound peer connections, they need to gain additional addresses to establish more outbound peer connections until the desired limit is reached. Furthermore, they need a mechanism to advertise their IP address to new or existing peers in the overlay so they may receive inbound connections up to some desired limit. And finally, they need a mechanism to provide inbound connection requests with an alternate set of IP addresses to try when they have already reached their desired maximum number of inbound connections.
-PeerFinder is a self contained module that provides these services, along with some
-additional overlay network management services such as _fixed slots_ and _cluster
-slots_.
+PeerFinder is a self contained module that provides these services, along with some additional overlay network management services such as _fixed slots_ and _cluster slots_.
## Features
PeerFinder has these responsibilities
-- Maintain a persistent set of endpoint addresses suitable for bootstrapping
- into the peer to peer overlay, ranked by relative locally observed utility.
+- Maintain a persistent set of endpoint addresses suitable for bootstrapping into the peer to peer overlay, ranked by relative locally observed utility.
- Send and receive protocol messages for discovery of endpoint addresses.
@@ -41,8 +24,7 @@ PeerFinder has these responsibilities
- Impose limits on the various slots consumed by peer connections.
-- Initiate outgoing connection attempts to endpoint addresses to maintain the
- overlay connectivity and fixed peer policies.
+- Initiate outgoing connection attempts to endpoint addresses to maintain the overlay connectivity and fixed peer policies.
- Verify the connectivity of neighbors who advertise inbound connection slots.
@@ -54,29 +36,19 @@ PeerFinder has these responsibilities
## Manager
-The `Manager` is an application singleton which provides the primary interface
-to interaction with the PeerFinder.
+The `Manager` is an application singleton which provides the primary interface to interaction with the PeerFinder.
### Autoconnect
-The Autoconnect feature of PeerFinder automatically establishes outgoing
-connections using addresses learned from various sources including the
-configuration file, the result of domain name lookups, and messages received
-from the overlay itself.
+The Autoconnect feature of PeerFinder automatically establishes outgoing connections using addresses learned from various sources including the configuration file, the result of domain name lookups, and messages received from the overlay itself.
### Callback
-PeerFinder is an isolated code module with few external dependencies. To perform
-socket specific activities such as establishing outgoing connections or sending
-messages to connected peers, the Manager is constructed with an abstract
-interface called the `Callback`. An instance of this interface performs the
-actual required operations, making PeerFinder independent of the calling code.
+PeerFinder is an isolated code module with few external dependencies. To perform socket specific activities such as establishing outgoing connections or sending messages to connected peers, the Manager is constructed with an abstract interface called the `Callback`. An instance of this interface performs the actual required operations, making PeerFinder independent of the calling code.
### Config
-The `Config` structure defines the operational parameters of the PeerFinder.
-Some values come from the configuration file while others are calculated via
-tuned heuristics. The fields are as follows:
+The `Config` structure defines the operational parameters of the PeerFinder. Some values come from the configuration file while others are calculated via tuned heuristics. The fields are as follows:
- `autoConnect`
@@ -84,150 +56,77 @@ tuned heuristics. The fields are as follows:
- `wantIncoming`
- A flag indicating whether or not the peer desires inbound connections. When
- this flag is turned off, a peer will not advertise itself in Endpoint
- messages.
+ A flag indicating whether or not the peer desires inbound connections. When this flag is turned off, a peer will not advertise itself in Endpoint messages.
- `listeningPort`
- The port number to use when creating the listening socket for peer
- connections.
+ The port number to use when creating the listening socket for peer connections.
- `maxPeers`
- The largest number of active peer connections to allow. This includes inbound
- and outbound connections, but excludes fixed and cluster peers. There is an
- implementation defined floor on this value.
+ The largest number of active peer connections to allow. This includes inbound and outbound connections, but excludes fixed and cluster peers. There is an implementation defined floor on this value.
- `outPeers`
- The number of automatic outbound connections that PeerFinder will maintain
- when the Autoconnect feature is enabled. The value is computed with fractional
- precision as an implementation defined percentage of `maxPeers` subject to
- an implementation defined floor. An instance of the PeerFinder rounds the
- fractional part up or down using a uniform random number generated at
- program startup. This allows the out-degree of the overlay network to be
- controlled with fractional precision, ensuring that all inbound network
- connection slots are not consumed (which would make it difficult for new
- participants to enter the network).
+ The number of automatic outbound connections that PeerFinder will maintain when the Autoconnect feature is enabled. The value is computed with fractional precision as an implementation defined percentage of `maxPeers` subject to an implementation defined floor. An instance of the PeerFinder rounds the fractional part up or down using a uniform random number generated at program startup. This allows the out-degree of the overlay network to be controlled with fractional precision, ensuring that all inbound network connection slots are not consumed (which would make it difficult for new participants to enter the network).
-Here's an example of how the network might be structured with a fractional
-value for outPeers:
+Here's an example of how the network might be structured with a fractional value for outPeers:
**(Need example here)**
### Livecache
-The Livecache holds relayed IP addresses that have been received recently in
-the form of Endpoint messages via the peer to peer overlay. A peer periodically
-broadcasts the Endpoint message to its neighbors when it has open inbound
-connection slots. Peers store these messages in the Livecache and periodically
-forward their neighbors a handful of random entries from their Livecache, with
-an incremented hop count for each forwarded entry.
+The Livecache holds relayed IP addresses that have been received recently in the form of Endpoint messages via the peer to peer overlay. A peer periodically broadcasts the Endpoint message to its neighbors when it has open inbound connection slots. Peers store these messages in the Livecache and periodically forward their neighbors a handful of random entries from their Livecache, with an incremented hop count for each forwarded entry.
-The algorithm for sending a neighbor a set of Endpoint messages chooses evenly
-from all available hop counts on each send. This ensures that each peer
-will see some entries with the farthest hops at each iteration. The result is
-to expand a peer's horizon with respect to which overlay endpoints are visible.
-This is designed to force the overlay to become highly connected and reduce
-the network diameter with each connection establishment.
+The algorithm for sending a neighbor a set of Endpoint messages chooses evenly from all available hop counts on each send. This ensures that each peer will see some entries with the farthest hops at each iteration. The result is to expand a peer's horizon with respect to which overlay endpoints are visible. This is designed to force the overlay to become highly connected and reduce the network diameter with each connection establishment.
-When a peer receives an Endpoint message that originates from a neighbor
-(identified by a hop count of zero) for the first time, it performs an incoming
-connection test on that neighbor by initiating an outgoing connection to the
-remote IP address as seen on the connection combined with the port advertised
-in the Endpoint message. If the test fails, then the peer considers its neighbor
-firewalled (intentionally or due to misconfiguration) and not forward neighbor
-endpoint in Endpoint messages. This prevents poor quality un-connectable
-addresses from landing in the caches. If the incoming connection test passes,
-then the peer fills in the Endpoint message with the remote address as seen on
-the connection before storing it in its cache and forwarding it to other peers.
-This relieves the neighbor from the responsibility of knowing its own IP address
-before it can start receiving incoming connections.
+When a peer receives an Endpoint message that originates from a neighbor (identified by a hop count of zero) for the first time, it performs an incoming connection test on that neighbor by initiating an outgoing connection to the remote IP address as seen on the connection combined with the port advertised in the Endpoint message. If the test fails, then the peer considers its neighbor firewalled (intentionally or due to misconfiguration) and not forward neighbor endpoint in Endpoint messages. This prevents poor quality un-connectable addresses from landing in the caches. If the incoming connection test passes, then the peer fills in the Endpoint message with the remote address as seen on the connection before storing it in its cache and forwarding it to other peers. This relieves the neighbor from the responsibility of knowing its own IP address before it can start receiving incoming connections.
-Livecache entries expire quickly. Since a peer stops advertising itself when
-it no longer has available inbound slots, its address will shortly after stop
-being handed out by other peers. Livecache entries are very likely to result
-in both a successful connection establishment and the acquisition of an active
-outbound slot. Compare this with Bootcache addresses, which are very likely to
-be connectable but unlikely to have an open slot.
+Livecache entries expire quickly. Since a peer stops advertising itself when it no longer has available inbound slots, its address will shortly after stop being handed out by other peers. Livecache entries are very likely to result in both a successful connection establishment and the acquisition of an active outbound slot. Compare this with Bootcache addresses, which are very likely to be connectable but unlikely to have an open slot.
-Because entries in the Livecache are ephemeral, they are not persisted across
-launches in the database. The Livecache is continually updated and expired as
-Endpoint messages are received from the overlay over time.
+Because entries in the Livecache are ephemeral, they are not persisted across launches in the database. The Livecache is continually updated and expired as Endpoint messages are received from the overlay over time.
### Bootcache
-The `Bootcache` stores IP addresses useful for gaining initial connections.
-Each address is associated with the following metadata:
+The `Bootcache` stores IP addresses useful for gaining initial connections. Each address is associated with the following metadata:
- **Valence**
- A signed integer which represents the number of successful
- consecutive connection attempts when positive, and the number of
- failed consecutive connection attempts when negative. If an outgoing
- connection attempt to the corresponding IP address fails to complete the
- handshake the valence is reset to negative one. This harsh penalty is
- intended to prevent popular servers from forever remaining top ranked in
- all peer databases.
+ A signed integer which represents the number of successful consecutive connection attempts when positive, and the number of failed consecutive connection attempts when negative. If an outgoing connection attempt to the corresponding IP address fails to complete the handshake the valence is reset to negative one. This harsh penalty is intended to prevent popular servers from forever remaining top ranked in all peer databases.
-When choosing addresses from the boot cache for the purpose of
-establishing outgoing connections, addresses are ranked in decreasing order of
-valence. The Bootcache is persistent. Entries are periodically inserted and
-updated in the corresponding SQLite database during program operation. When
-**xrpld** is launched, the existing Bootcache database data is accessed and
-loaded to accelerate the bootstrap process.
+When choosing addresses from the boot cache for the purpose of establishing outgoing connections, addresses are ranked in decreasing order of valence. The Bootcache is persistent. Entries are periodically inserted and updated in the corresponding SQLite database during program operation. When **xrpld** is launched, the existing Bootcache database data is accessed and loaded to accelerate the bootstrap process.
-Desirable entries in the Bootcache are addresses for servers which are known to
-have high uptimes, and for which connection attempts usually succeed. However,
-these servers do not necessarily have available inbound connection slots.
-However, it is assured that these servers will have a well populated Livecache
-since they will have moved towards the core of the overlay over their high
-uptime. When a connected server is full it will return a handful of new
-addresses from its Livecache and gracefully close the connection. Addresses
-from the Livecache are highly likely to have inbound connection slots and be
-connectable.
+Desirable entries in the Bootcache are addresses for servers which are known to have high uptimes, and for which connection attempts usually succeed. However, these servers do not necessarily have available inbound connection slots. However, it is assured that these servers will have a well populated Livecache since they will have moved towards the core of the overlay over their high uptime. When a connected server is full it will return a handful of new addresses from its Livecache and gracefully close the connection. Addresses from the Livecache are highly likely to have inbound connection slots and be connectable.
-For security, all information that contributes to the ranking of Bootcache
-entries is observed locally. PeerFinder never trusts external sources of information.
+For security, all information that contributes to the ranking of Bootcache entries is observed locally. PeerFinder never trusts external sources of information.
### Slot
-Each TCP/IP socket that can participate in the peer to peer overlay occupies
-a slot. Slots have properties and state associated with them:
+Each TCP/IP socket that can participate in the peer to peer overlay occupies a slot. Slots have properties and state associated with them:
#### State (Slot)
-The slot state represents the current stage of the connection as it passes
-through the business logic for establishing peer connections.
+The slot state represents the current stage of the connection as it passes through the business logic for establishing peer connections.
- `accept`
- The accept state is an initial state resulting from accepting an incoming
- connection request on a listening socket. The remote IP address and port
- are known, and a handshake is expected next.
+ The accept state is an initial state resulting from accepting an incoming connection request on a listening socket. The remote IP address and port are known, and a handshake is expected next.
- `connect`
- The connect state is an initial state used when actively establishing outbound
- connection attempts. The desired remote IP address and port are known.
+ The connect state is an initial state used when actively establishing outbound connection attempts. The desired remote IP address and port are known.
- `connected`
- When an outbound connection attempt succeeds, it moves to the connected state.
- The handshake is initiated but not completed.
+ When an outbound connection attempt succeeds, it moves to the connected state. The handshake is initiated but not completed.
- `active`
- The state becomes Active when a connection in either the Accepted or Connected
- state completes the handshake process, and a slot is available based on the
- properties. If no slot is available when the handshake completes, the socket
- is gracefully closed.
+ The state becomes Active when a connection in either the Accepted or Connected state completes the handshake process, and a slot is available based on the properties. If no slot is available when the handshake completes, the socket is gracefully closed.
- `closing`
- The Closing state represents a connected socket in the process of being
- gracefully closed.
+ The Closing state represents a connected socket in the process of being gracefully closed.
#### Properties (Slot)
@@ -235,48 +134,27 @@ Slot properties may be combined and are not mutually exclusive.
- **Inbound**
- An inbound slot is the condition of a socket which has accepted an incoming
- connection request. A connection which is not inbound is by definition
- outbound.
+ An inbound slot is the condition of a socket which has accepted an incoming connection request. A connection which is not inbound is by definition outbound.
- **Fixed**
- A fixed slot is a desired connection to a known peer identified by IP address,
- usually entered manually in the configuration file. For the purpose of
- establishing outbound connections, the peer also has an associated port number
- although only the IP address is checked to determine if the fixed peer is
- already connected. Fixed slots do not count towards connection limits.
+ A fixed slot is a desired connection to a known peer identified by IP address, usually entered manually in the configuration file. For the purpose of establishing outbound connections, the peer also has an associated port number although only the IP address is checked to determine if the fixed peer is already connected. Fixed slots do not count towards connection limits.
- **Cluster**
- A cluster slot is a connection which has completed the handshake stage, whose
- public key matches a known public key usually entered manually in the
- configuration file or learned through overlay messages from other trusted
- peers. Cluster slots do not count towards connection limits.
+ A cluster slot is a connection which has completed the handshake stage, whose public key matches a known public key usually entered manually in the configuration file or learned through overlay messages from other trusted peers. Cluster slots do not count towards connection limits.
- **Superpeer** (forthcoming)
- A superpeer slot is a connection to a peer which can accept incoming
- connections, meets certain resource availability requirements (such as
- bandwidth, CPU, and storage capacity), and operates full duplex in the
- overlay. Connections which are not superpeers are by definition leaves. A
- leaf slot is a connection to a peer which does not route overlay messages to
- other peers, and operates in a partial half duplex fashion in the overlay.
+ A superpeer slot is a connection to a peer which can accept incoming connections, meets certain resource availability requirements (such as bandwidth, CPU, and storage capacity), and operates full duplex in the overlay. Connections which are not superpeers are by definition leaves. A leaf slot is a connection to a peer which does not route overlay messages to other peers, and operates in a partial half duplex fashion in the overlay.
#### Fixed Slots
-Fixed slots are identified by IP address and set up during the initialization
-of the Manager, usually from the configuration file. The Logic will always make
-outgoing connection attempts to each fixed slot which is not currently
-connected. If we receive an inbound connection from an endpoint whose address
-portion (without port) matches a fixed slot address, we consider the fixed
-slot to be connected.
+Fixed slots are identified by IP address and set up during the initialization of the Manager, usually from the configuration file. The Logic will always make outgoing connection attempts to each fixed slot which is not currently connected. If we receive an inbound connection from an endpoint whose address portion (without port) matches a fixed slot address, we consider the fixed slot to be connected.
#### Cluster Slots
-Cluster slots are identified by the public key and set up during the
-initialization of the manager or discovered upon receipt of messages in the
-overlay from trusted connections.
+Cluster slots are identified by the public key and set up during the initialization of the manager or discovered upon receipt of messages in the overlay from trusted connections.
---
@@ -284,62 +162,35 @@ overlay from trusted connections.
## Connection Strategy
-The _Connection Strategy_ applies the configuration settings to establish
-desired outbound connections. It runs periodically and progresses through a
-series of stages, remaining in each stage until a condition is met
+The _Connection Strategy_ applies the configuration settings to establish desired outbound connections. It runs periodically and progresses through a series of stages, remaining in each stage until a condition is met
### Stage 1: Fixed Slots
-This stage is invoked when the number of active fixed connections is below the
-number of fixed connections specified in the configuration, and one of the
-following is true:
+This stage is invoked when the number of active fixed connections is below the number of fixed connections specified in the configuration, and one of the following is true:
- There are eligible fixed addresses to try
- Any outbound connection attempts are in progress
-Each fixed address is associated with a retry timer. On a fixed connection
-failure, the timer is reset so that the address is not tried for some amount
-of time, which increases according to a scheduled sequence up to some maximum
-which is currently set to approximately one hour between retries. A fixed
-address is considered eligible if we are not currently connected or attempting
-the address, and its retry timer has expired.
+Each fixed address is associated with a retry timer. On a fixed connection failure, the timer is reset so that the address is not tried for some amount of time, which increases according to a scheduled sequence up to some maximum which is currently set to approximately one hour between retries. A fixed address is considered eligible if we are not currently connected or attempting the address, and its retry timer has expired.
-The PeerFinder makes its best effort to become fully connected to the fixed
-addresses specified in the configuration file before moving on to establish
-outgoing connections to foreign peers. This security feature helps xrpld
-establish itself with a trusted set of peers first before accepting untrusted
-data from the network.
+The PeerFinder makes its best effort to become fully connected to the fixed addresses specified in the configuration file before moving on to establish outgoing connections to foreign peers. This security feature helps xrpld establish itself with a trusted set of peers first before accepting untrusted data from the network.
### Stage 2: Livecache
-The Livecache is invoked when Stage 1 is not active, autoconnect is enabled,
-and the number of active outbound connections is below the number desired. The
-stage remains active while:
+The Livecache is invoked when Stage 1 is not active, autoconnect is enabled, and the number of active outbound connections is below the number desired. The stage remains active while:
- The Livecache has addresses to try
- Any outbound connection attempts are in progress
-PeerFinder makes its best effort to exhaust addresses in the Livecache before
-moving on to the Bootcache, because Livecache addresses are highly likely
-to be connectable (since they are known to have been online within the last
-minute), and highly likely to have an open slot for an incoming connection
-(because peers only advertise themselves in the Livecache when they have
-open slots).
+PeerFinder makes its best effort to exhaust addresses in the Livecache before moving on to the Bootcache, because Livecache addresses are highly likely to be connectable (since they are known to have been online within the last minute), and highly likely to have an open slot for an incoming connection (because peers only advertise themselves in the Livecache when they have open slots).
### Stage 3: Bootcache
-The Bootcache is invoked when Stage 1 and Stage 2 are not active, autoconnect
-is enabled, and the number of active outbound connections is below the number
-desired. The stage remains active while:
+The Bootcache is invoked when Stage 1 and Stage 2 are not active, autoconnect is enabled, and the number of active outbound connections is below the number desired. The stage remains active while:
- There are addresses in the cache that have not been tried recently.
-Entries in the Bootcache are ranked, with highly connectable addresses preferred
-over others. Connection attempts to Bootcache addresses are very likely to
-succeed but unlikely to produce an active connection since the peers likely do
-not have open slots. Before the remote peer closes the connection it will send
-a handful of addresses from its Livecache to help the new peer coming online
-obtain connections.
+Entries in the Bootcache are ranked, with highly connectable addresses preferred over others. Connection attempts to Bootcache addresses are very likely to succeed but unlikely to produce an active connection since the peers likely do not have open slots. Before the remote peer closes the connection it will send a handful of addresses from its Livecache to help the new peer coming online obtain connections.
---
@@ -347,8 +198,7 @@ obtain connections.
Much of the work in PeerFinder was inspired by earlier work in Gnutella:
-[Revised Gnutella Ping Pong Scheme](http://rfc-gnutella.sourceforge.net/src/pong-caching.html)
-_By Christopher Rohrs and Vincent Falco_
+[Revised Gnutella Ping Pong Scheme](http://rfc-gnutella.sourceforge.net/src/pong-caching.html)
_By Christopher Rohrs and Vincent Falco_
[Gnutella 0.6 Protocol:](http://rfc-gnutella.sourceforge.net/src/rfc-0_6-draft.html) Sections:
diff --git a/src/xrpld/rpc/README.md b/src/xrpld/rpc/README.md
index cf023770ea..5e85ecf114 100644
--- a/src/xrpld/rpc/README.md
+++ b/src/xrpld/rpc/README.md
@@ -2,72 +2,49 @@
## Introduction.
-By default, an RPC handler runs as an uninterrupted task on the JobQueue. This
-is fine for commands that are fast to compute but might not be acceptable for
-tasks that require multiple parts or are large, like a full ledger.
+By default, an RPC handler runs as an uninterrupted task on the JobQueue. This is fine for commands that are fast to compute but might not be acceptable for tasks that require multiple parts or are large, like a full ledger.
For this purpose, the xrpld RPC handler allows _suspension with continuation_
-- a request to suspend execution of the RPC response and to continue it after
- some function or job has been executed. A default continuation is supplied
- which simply reschedules the job on the JobQueue, or the programmer can supply
- their own.
+- a request to suspend execution of the RPC response and to continue it after some function or job has been executed. A default continuation is supplied which simply reschedules the job on the JobQueue, or the programmer can supply their own.
## The classes.
-Suspension with continuation uses four `std::function`s in the `xrpl::RPC`
-namespace:
+Suspension with continuation uses four `std::function`s in the `xrpl::RPC` namespace:
using Callback = std::function ;
using Continuation = std::function ;
using Suspend = std::function ;
using Coroutine = std::function ;
-A `Callback` is a generic 0-argument function. A given `Callback` might or might
-not block. Unless otherwise advised, do not hold locks or any resource that
-would prevent any other task from making forward progress when you call a
-`Callback`.
+A `Callback` is a generic 0-argument function. A given `Callback` might or might not block. Unless otherwise advised, do not hold locks or any resource that would prevent any other task from making forward progress when you call a `Callback`.
-A `Continuation` is a function that is given a `Callback` and promises to call
-it later. A `Continuation` guarantees to call the `Callback` exactly once at
-some point in the future, but it does not have to be immediately or even in the
-current thread.
+A `Continuation` is a function that is given a `Callback` and promises to call it later. A `Continuation` guarantees to call the `Callback` exactly once at some point in the future, but it does not have to be immediately or even in the current thread.
-A `Suspend` is a function belonging to a `Coroutine`. A `Suspend` runs a
-`Continuation`, passing it a `Callback` that continues execution of the
-`Coroutine`.
+A `Suspend` is a function belonging to a `Coroutine`. A `Suspend` runs a `Continuation`, passing it a `Callback` that continues execution of the `Coroutine`.
-And finally, a `Coroutine` is a `std::function` which is given a
-`Suspend`. This is what the RPC handler gives to the coroutine manager,
-expecting to get called back with a `Suspend` and to be able to start execution.
+And finally, a `Coroutine` is a `std::function` which is given a `Suspend`. This is what the RPC handler gives to the coroutine manager, expecting to get called back with a `Suspend` and to be able to start execution.
## The flow of control.
-Given these functions, the flow of RPC control when using coroutines is
-straight-forward.
+Given these functions, the flow of RPC control when using coroutines is straight-forward.
1. The instance of `ServerHandler` receives an RPC request.
2. It creates a `Coroutine` and gives it to the coroutine manager.
-3. The coroutine manager creates a `Coroutine`, starts it up, and then calls
- the `Coroutine` with a `Suspend`.
+3. The coroutine manager creates a `Coroutine`, starts it up, and then calls the `Coroutine` with a `Suspend`.
4. Now the RPC response starts to be calculated.
-5. When the RPC handler wants to suspend, it calls the `Suspend` function with
- a `Continuation`.
+5. When the RPC handler wants to suspend, it calls the `Suspend` function with a `Continuation`.
6. Coroutine execution is suspended.
-7. The `Continuation` is called with a `Callback` that the coroutine manager
- creates.
+7. The `Continuation` is called with a `Callback` that the coroutine manager creates.
-8. The `Continuation` may choose to execute immediately, defer execution on the
- job queue, or wait for some resource to be free.
+8. The `Continuation` may choose to execute immediately, defer execution on the job queue, or wait for some resource to be free.
-9. When the `Continuation` is finished, it calls the `Callback` that the
- coroutine manager gave it, perhaps a long time ago.
+9. When the `Continuation` is finished, it calls the `Callback` that the coroutine manager gave it, perhaps a long time ago.
-10. This `Callback` continues execution on the suspended `Coroutine` from where
- it left off.
+10. This `Callback` continues execution on the suspended `Coroutine` from where it left off.
diff --git a/tests/README.md b/tests/README.md
index 431c2c464a..9ffad85e3e 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -1,5 +1,3 @@
# Integration tests
-This directory contains integration tests for the project. These tests are run
-against the `libxrpl` library or `xrpld` binary to verify they are working as
-expected.
+This directory contains integration tests for the project. These tests are run against the `libxrpl` library or `xrpld` binary to verify they are working as expected.