Compare commits

..

3 Commits

Author SHA1 Message Date
Denis Angell
4c5ab49d2e feat: async trace writer 2026-05-11 10:13:12 +02:00
Denis Angell
6a079eddee revert 2026-05-11 09:01:01 +02:00
Denis Angell
84ce5482e6 feat: logging 2026-05-10 23:02:48 +02:00
1027 changed files with 18116 additions and 19725 deletions

View File

@@ -4,8 +4,8 @@ Checks: "-*,
bugprone-assert-side-effect,
bugprone-bad-signal-to-kill-thread,
bugprone-bool-pointer-implicit-conversion,
bugprone-capturing-this-in-member-variable,
bugprone-casting-through-void,
bugprone-capturing-this-in-member-variable,
bugprone-chained-comparison,
bugprone-compare-pointer-to-member-virtual-function,
bugprone-copy-constructor-init,
@@ -24,10 +24,10 @@ Checks: "-*,
bugprone-lambda-function-name,
bugprone-macro-parentheses,
bugprone-macro-repeated-side-effects,
bugprone-misleading-setter-of-reference,
bugprone-misplaced-operator-in-strlen-in-alloc,
bugprone-misplaced-pointer-arithmetic-in-alloc,
bugprone-misplaced-widening-cast,
bugprone-misleading-setter-of-reference,
bugprone-move-forwarding-reference,
bugprone-multi-level-implicit-pointer-conversion,
bugprone-multiple-new-in-one-expression,
@@ -73,10 +73,10 @@ Checks: "-*,
bugprone-unhandled-self-assignment,
bugprone-unique-ptr-array-mismatch,
bugprone-unsafe-functions,
bugprone-unused-local-non-trivial-variable,
bugprone-use-after-move,
bugprone-unused-raii,
bugprone-unused-return-value,
bugprone-use-after-move,
bugprone-unused-local-non-trivial-variable,
bugprone-virtual-near-miss,
cppcoreguidelines-init-variables,
cppcoreguidelines-misleading-capture-default-by-value,
@@ -88,7 +88,6 @@ Checks: "-*,
cppcoreguidelines-use-enum-class,
cppcoreguidelines-virtual-class-destructor,
hicpp-ignored-remove-result,
llvm-namespace-comment,
misc-const-correctness,
misc-definitions-in-headers,
misc-header-include-cycle,
@@ -100,7 +99,6 @@ Checks: "-*,
misc-unused-alias-decls,
misc-unused-using-decls,
modernize-concat-nested-namespaces,
modernize-deprecated-headers,
modernize-make-shared,
modernize-make-unique,
modernize-pass-by-value,
@@ -116,6 +114,8 @@ Checks: "-*,
modernize-use-starts-ends-with,
modernize-use-std-numbers,
modernize-use-using,
modernize-deprecated-headers,
llvm-namespace-comment,
performance-faster-string-find,
performance-for-range-copy,
performance-implicit-conversion-in-loop,
@@ -156,13 +156,7 @@ Checks: "-*,
# readability-inconsistent-declaration-parameter-name, # in this codebase this check will break a lot of arg names
# readability-static-accessed-through-instance, # this check is probably unnecessary. it makes the code less readable
# ---
CheckOptions:
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
misc-include-cleaner.IgnoreHeaders: ".*/(detail|impl)/.*;.*fwd\\.h(pp)?;time.h;stdlib.h;sqlite3.h;netinet/in\\.h;sys/resource\\.h;sys/sysinfo\\.h;linux/sysinfo\\.h;__chrono/.*;bits/.*;_abort\\.h;boost/uuid/uuid_hash.hpp;boost/beast/core/flat_buffer\\.hpp;boost/beast/http/field\\.hpp;boost/beast/http/dynamic_body\\.hpp;boost/beast/http/message\\.hpp;boost/beast/http/read\\.hpp;boost/beast/http/write\\.hpp;openssl/obj_mac\\.h"
readability-braces-around-statements.ShortStatementLines: 2
readability-identifier-naming.MacroDefinitionCase: UPPER_CASE
readability-identifier-naming.ClassCase: CamelCase
@@ -171,7 +165,7 @@ CheckOptions:
readability-identifier-naming.EnumCase: CamelCase
readability-identifier-naming.EnumConstantCase: CamelCase
readability-identifier-naming.ScopedEnumConstantCase: CamelCase
readability-identifier-naming.GlobalConstantCase: CamelCase
readability-identifier-naming.GlobalConstantCase: UPPER_CASE
readability-identifier-naming.GlobalConstantPrefix: "k"
readability-identifier-naming.GlobalVariableCase: CamelCase
readability-identifier-naming.GlobalVariablePrefix: "g"
@@ -179,12 +173,14 @@ CheckOptions:
readability-identifier-naming.ConstexprMethodCase: camelBack
readability-identifier-naming.ClassMethodCase: camelBack
readability-identifier-naming.ClassMemberCase: camelBack
readability-identifier-naming.ClassConstantCase: CamelCase
readability-identifier-naming.ClassConstantCase: UPPER_CASE
readability-identifier-naming.ClassConstantPrefix: "k"
readability-identifier-naming.StaticConstantCase: CamelCase
readability-identifier-naming.StaticConstantCase: UPPER_CASE
readability-identifier-naming.StaticConstantPrefix: "k"
readability-identifier-naming.StaticVariableCase: camelBack
readability-identifier-naming.ConstexprVariableCase: camelBack
readability-identifier-naming.StaticVariableCase: UPPER_CASE
readability-identifier-naming.StaticVariablePrefix: "k"
readability-identifier-naming.ConstexprVariableCase: UPPER_CASE
readability-identifier-naming.ConstexprVariablePrefix: "k"
readability-identifier-naming.LocalConstantCase: camelBack
readability-identifier-naming.LocalVariableCase: camelBack
readability-identifier-naming.TemplateParameterCase: CamelCase
@@ -195,7 +191,9 @@ CheckOptions:
readability-identifier-naming.ProtectedMemberSuffix: _
readability-identifier-naming.PublicMemberSuffix: ""
readability-identifier-naming.GlobalFunctionIgnoredRegexp: "^(to_string|hash_append|tuple_hash)$"
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
misc-include-cleaner.IgnoreHeaders: ".*/(detail|impl)/.*;.*fwd\\.h(pp)?;time.h;stdlib.h;sqlite3.h;netinet/in\\.h;sys/resource\\.h;sys/sysinfo\\.h;linux/sysinfo\\.h;__chrono/.*;bits/.*;_abort\\.h;boost/uuid/uuid_hash.hpp;boost/beast/core/flat_buffer\\.hpp;boost/beast/http/field\\.hpp;boost/beast/http/dynamic_body\\.hpp;boost/beast/http/message\\.hpp;boost/beast/http/read\\.hpp;boost/beast/http/write\\.hpp;openssl/obj_mac\\.h"
HeaderFilterRegex: '^.*/(test|xrpl|xrpld)/.*\.(h|hpp|ipp)$'
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$'
WarningsAsErrors: "*"

View File

@@ -62,7 +62,7 @@ ${SED_COMMAND} -i 's@ripple/@xrpld/@g' src/test/core/Config_test.cpp
${SED_COMMAND} -i 's/Rippled/File/g' src/test/core/Config_test.cpp
# Restore the old config file name in the code that maintains support for now.
${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp
${SED_COMMAND} -i 's/kCONFIG_LEGACY_NAME = "xrpld.cfg"/kCONFIG_LEGACY_NAME = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp
# Restore an URL.
${SED_COMMAND} -i 's/connect-your-xrpld-to-the-xrp-test-net.html/connect-your-rippled-to-the-xrp-test-net.html/g' cfg/xrpld-example.cfg

View File

@@ -90,7 +90,7 @@ ${SED_COMMAND} -i 's/www.ripple.com/www.xrpl.org/g' src/test/protocol/Seed_test.
# Restore specific changes.
${SED_COMMAND} -i 's@b5efcc/src/xrpld@b5efcc/src/ripple@' include/xrpl/protocol/README.md
${SED_COMMAND} -i 's/dbPrefix_ = "xrpldb"/dbPrefix_ = "rippledb"/' src/xrpld/app/misc/SHAMapStoreImp.h # cspell: disable-line
${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/' src/xrpld/core/detail/Config.cpp
${SED_COMMAND} -i 's/kCONFIG_LEGACY_NAME = "xrpld.cfg"/kCONFIG_LEGACY_NAME = "rippled.cfg"/' src/xrpld/core/detail/Config.cpp
popd
echo "Renaming complete."

View File

@@ -32,32 +32,7 @@ We will further set additional CMake arguments as follows:
"""
def build_config_name(os_entry: dict[str, str], platform: str, build_type: str) -> str:
parts = [os_entry["distro_name"]]
for key in ("distro_version", "compiler_name", "compiler_version"):
if value := os_entry[key]:
parts.append(value)
parts.append("arm64" if "arm64" in platform else "amd64")
parts.append(build_type.lower())
return "-".join(parts)
def generate_packaging_matrix(config: Config) -> list[dict]:
"""Emit one entry per os entry with `package: true`. Architecture is
hardcoded to linux/amd64 here (and the runner is hardcoded at the
workflow level) until arm64 packaging is ready.
"""
return [
{
"artifact_name": f"xrpld-{build_config_name(os, 'linux/amd64', 'Release')}",
"os": os,
}
for os in config.os
if os.get("package", False)
]
def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
def generate_strategy_matrix(all: bool, config: Config) -> list:
configurations = []
for architecture, os, build_type, cmake_args in itertools.product(
config.architecture, config.os, config.build_type, config.cmake_args
@@ -97,7 +72,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
and build_type == "Release"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
@@ -115,9 +90,8 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
):
cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}"
skip = False
elif os["distro_version"] == "trixie":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-22"
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20"
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
@@ -126,15 +100,14 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
continue
# RHEL:
# - 9 using GCC 12: Debug and Release on linux/amd64
# (Release is required for RPM packaging).
# - 9 using GCC 12: Debug on linux/amd64.
# - 10 using Clang: Release on linux/amd64.
if os["distro_name"] == "rhel":
skip = True
if os["distro_version"] == "9":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type in ["Debug", "Release"]
and build_type == "Debug"
and architecture["platform"] == "linux/amd64"
):
skip = False
@@ -149,8 +122,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
continue
# Ubuntu:
# - Jammy using GCC 12: Debug on linux/arm64, Release on
# linux/amd64 (Release is required for DEB packaging).
# - Jammy using GCC 12: Debug on linux/arm64.
# - Noble using GCC 14: Release on linux/amd64.
# - Noble using Clang 18: Debug on linux/amd64.
# - Noble using Clang 19: Release on linux/arm64.
@@ -163,12 +135,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
and architecture["platform"] == "linux/arm64"
):
skip = False
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Release"
and architecture["platform"] == "linux/amd64"
):
skip = False
elif os["distro_version"] == "noble":
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14"
@@ -222,9 +188,8 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
# We skip all clang 20+ on arm64 due to Boost build error.
if (
os["compiler_name"] == "clang"
and os["compiler_version"].isdigit()
and int(os["compiler_version"]) >= 20
f"{os['compiler_name']}-{os['compiler_version']}"
in ["clang-20", "clang-21"]
and architecture["platform"] == "linux/arm64"
):
continue
@@ -251,7 +216,17 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
# Generate a unique name for the configuration, e.g. macos-arm64-debug
# or debian-bookworm-gcc-12-amd64-release.
config_name = build_config_name(os, architecture["platform"], build_type)
config_name = os["distro_name"]
if (n := os["distro_version"]) != "":
config_name += f"-{n}"
if (n := os["compiler_name"]) != "":
config_name += f"-{n}"
if (n := os["compiler_version"]) != "":
config_name += f"-{n}"
config_name += (
f"-{architecture['platform'][architecture['platform'].find('/')+1:]}"
)
config_name += f"-{build_type.lower()}"
if "-Dcoverage=ON" in cmake_args:
config_name += "-coverage"
if "-Dunity=ON" in cmake_args:
@@ -263,14 +238,13 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
# Add Address and UB sanitizers as separate configurations for specific
# bookworm distros. Thread sanitizer is currently disabled (see below).
# GCC-Asan xrpld-embedded tests are failing because of https://github.com/google/sanitizers/issues/856
if (
os["distro_version"] == "bookworm"
and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
) or (
os["distro_version"] == "trixie"
and f"{os['compiler_name']}-{os['compiler_version']}" == "clang-22"
):
# Add ASAN and UBSAN configurations for both gcc-15 and clang-22
if os[
"distro_version"
] == "bookworm" and f"{os['compiler_name']}-{os['compiler_version']}" in [
"gcc-15",
"clang-20",
]:
# Add ASAN configuration.
configurations.append(
{
"config_name": config_name + "-asan",
@@ -283,6 +257,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
"sanitizers": "address",
}
)
# Add UBSAN configuration.
configurations.append(
{
"config_name": config_name + "-ubsan",
@@ -355,19 +330,10 @@ if __name__ == "__main__":
required=False,
type=Path,
)
parser.add_argument(
"-p",
"--packaging",
help="Emit the packaging matrix (derived from the 'package' field on os entries) instead of the build/test matrix.",
action="store_true",
)
args = parser.parse_args()
matrix = []
if args.packaging:
config_path = args.config if args.config else THIS_DIR / "linux.json"
matrix += generate_packaging_matrix(read_config(config_path))
elif args.config is None or args.config == "":
if args.config is None or args.config == "":
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "linux.json")
)

View File

@@ -15,205 +15,196 @@
"distro_version": "bookworm",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "gcc",
"compiler_version": "15",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "16",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "17",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "18",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "19",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "bookworm",
"compiler_name": "clang",
"compiler_version": "20",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "gcc",
"compiler_version": "15",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "clang",
"compiler_version": "20",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "clang",
"compiler_version": "21",
"image_sha": "4c086b9"
},
{
"distro_name": "debian",
"distro_version": "trixie",
"compiler_name": "clang",
"compiler_version": "22",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "4c086b9",
"package": true
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "jammy",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "4c086b9",
"package": true
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "16",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "17",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "18",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
},
{
"distro_name": "ubuntu",
"distro_version": "noble",
"compiler_name": "clang",
"compiler_version": "19",
"image_sha": "4c086b9"
"image_sha": "ab4d1f0"
}
],
"build_type": ["Debug", "Release"],

View File

@@ -1,101 +0,0 @@
name: Build Nix Docker image
on:
push:
branches:
- develop
paths:
- ".github/workflows/build-nix-image.yml"
- "docker/nix.Dockerfile"
- "flake.nix"
- "flake.lock"
- "nix/**"
pull_request:
paths:
- ".github/workflows/build-nix-image.yml"
- "docker/nix.Dockerfile"
- "flake.nix"
- "flake.lock"
- "nix/**"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
env:
UBUNTU_VERSION: "20.04"
RHEL_VERSION: "9"
DEBIAN_VERSION: "bookworm"
jobs:
build:
name: Build and push Nix image (${{ matrix.distro }})
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- distro: nixos
- distro: ubuntu
- distro: rhel
- distro: debian
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Determine base image
id: vars
run: |
case "${{ matrix.distro }}" in
nixos)
echo "base_image=nixos/nix:latest" >> $GITHUB_OUTPUT
;;
ubuntu)
echo "base_image=ubuntu:${UBUNTU_VERSION}" >> $GITHUB_OUTPUT
;;
rhel)
echo "base_image=registry.access.redhat.com/ubi${RHEL_VERSION}/ubi:latest" >> $GITHUB_OUTPUT
;;
debian)
echo "base_image=debian:${DEBIAN_VERSION}" >> $GITHUB_OUTPUT
;;
esac
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
- name: Login to GitHub Container Registry
if: github.event_name == 'push'
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
with:
images: ghcr.io/xrplf/ci/nix-${{ matrix.distro }}
tags: |
type=sha,prefix=sha-,format=short
type=raw,value=latest
- name: Build and push
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
file: docker/nix.Dockerfile
platforms: linux/amd64
push: ${{ github.event_name == 'push' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: BASE_IMAGE=${{ steps.vars.outputs.base_image }}

View File

@@ -11,4 +11,4 @@ on:
jobs:
check_title:
if: ${{ github.event.pull_request.draft != true }}
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@291206777251b4d493641b5afbdf7c23009d2988
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@a5d8dd35be543365e90a11358447130c8763871d

View File

@@ -58,19 +58,20 @@ jobs:
# Keep the paths below in sync with those in `on-trigger.yml`.
.github/actions/build-deps/**
.github/actions/build-test/**
.github/actions/generate-version/**
.github/actions/setup-conan/**
.github/scripts/strategy-matrix/**
.github/workflows/reusable-build.yml
.github/workflows/reusable-build-test-config.yml
.github/workflows/reusable-build-test.yml
.github/workflows/reusable-clang-tidy.yml
.github/workflows/reusable-package.yml
.github/workflows/reusable-clang-tidy-files.yml
.github/workflows/reusable-strategy-matrix.yml
.github/workflows/reusable-test.yml
.github/workflows/reusable-upload-recipe.yml
.clang-tidy
.codecov.yml
cfg/**
cmake/**
conan/**
external/**
@@ -80,10 +81,6 @@ jobs:
CMakeLists.txt
conanfile.py
conan.lock
LICENSE.md
package/**
README.md
- name: Check whether to run
# This step determines whether the rest of the workflow should
# run. The rest of the workflow will run if this job runs AND at
@@ -140,11 +137,6 @@ jobs:
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
package:
needs: [should-run, build-test]
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-package.yml
upload-recipe:
needs:
- should-run
@@ -179,10 +171,9 @@ jobs:
- check-rename
- clang-tidy
- build-test
- package
- upload-recipe
- notify-clio
runs-on: ubuntu-latest
steps:
- name: Fail
run: exit 1
run: false

View File

@@ -1,5 +1,5 @@
# This workflow uploads the libxrpl recipe to the Conan remote and builds
# release packages when a versioned tag is pushed.
# This workflow uploads the libxrpl recipe to the Conan remote when a versioned
# tag is pushed.
name: Tag
on:
@@ -22,22 +22,3 @@ jobs:
secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
build-test:
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: ./.github/workflows/reusable-build-test.yml
strategy:
fail-fast: true
matrix:
os: [linux]
with:
ccache_enabled: false
os: ${{ matrix.os }}
strategy_matrix: minimal
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
package:
if: ${{ github.repository == 'XRPLF/rippled' }}
needs: build-test
uses: ./.github/workflows/reusable-package.yml

View File

@@ -15,19 +15,20 @@ on:
# Keep the paths below in sync with those in `on-pr.yml`.
- ".github/actions/build-deps/**"
- ".github/actions/build-test/**"
- ".github/actions/generate-version/**"
- ".github/actions/setup-conan/**"
- ".github/scripts/strategy-matrix/**"
- ".github/workflows/reusable-build.yml"
- ".github/workflows/reusable-build-test-config.yml"
- ".github/workflows/reusable-build-test.yml"
- ".github/workflows/reusable-clang-tidy.yml"
- ".github/workflows/reusable-package.yml"
- ".github/workflows/reusable-clang-tidy-files.yml"
- ".github/workflows/reusable-strategy-matrix.yml"
- ".github/workflows/reusable-test.yml"
- ".github/workflows/reusable-upload-recipe.yml"
- ".clang-tidy"
- ".codecov.yml"
- "cfg/**"
- "cmake/**"
- "conan/**"
- "external/**"
@@ -37,9 +38,6 @@ on:
- "CMakeLists.txt"
- "conanfile.py"
- "conan.lock"
- "LICENSE.md"
- "package/**"
- "README.md"
# Run at 06:32 UTC on every day of the week from Monday through Friday. This
# will force all dependencies to be rebuilt, which is useful to verify that
@@ -100,7 +98,3 @@ jobs:
secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
package:
needs: build-test
uses: ./.github/workflows/reusable-package.yml

View File

@@ -143,6 +143,7 @@ jobs:
working-directory: ${{ env.BUILD_DIR }}
env:
BUILD_TYPE: ${{ inputs.build_type }}
SANITIZERS: ${{ inputs.sanitizers }}
CMAKE_ARGS: ${{ inputs.cmake_args }}
run: |
cmake \
@@ -181,7 +182,7 @@ jobs:
- name: Build the binary
working-directory: ${{ env.BUILD_DIR }}
env:
BUILD_NPROC: ${{ runner.os == 'Linux' && '16' || steps.nproc.outputs.nproc }}
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
BUILD_TYPE: ${{ inputs.build_type }}
CMAKE_TARGET: ${{ inputs.cmake_target }}
run: |
@@ -283,16 +284,8 @@ jobs:
- name: Show test failure summary
if: ${{ failure() && !inputs.build_only }}
env:
WORKING_DIR: ${{ runner.os == 'Windows' && format('{0}\{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
run: |
if [ ! -d "${WORKING_DIR}" ]; then
echo "Working directory '${WORKING_DIR}' does not exist."
exit 0
fi
cd "${WORKING_DIR}"
if [ ! -f unittest.log ]; then
echo "unittest.log not found; embedded tests may not have run."
exit 0

View File

@@ -0,0 +1,175 @@
name: Run clang-tidy on files
on:
workflow_call:
inputs:
files:
description: "List of files to check (empty means check all files)"
type: string
default: ""
create_issue_on_failure:
description: "Whether to create an issue if the check failed"
type: boolean
default: false
defaults:
run:
shell: bash
env:
# Conan installs the generators in the build/generators directory, see the
# layout() method in conanfile.py. We then run CMake from the build directory.
BUILD_DIR: build
BUILD_TYPE: Debug # Debug so that ASSERTS and such participate in clang-tidy check
jobs:
run-clang-tidy:
name: Run clang tidy
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/ci/debian-trixie:clang-21-sha-53033a2"
permissions:
issues: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
with:
enable_ccache: false
- name: Print build environment
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
- name: Get number of processors
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
id: nproc
- name: Setup Conan
uses: ./.github/actions/setup-conan
- name: Build dependencies
uses: ./.github/actions/build-deps
with:
build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ env.BUILD_TYPE }}
log_verbosity: verbose
- name: Configure CMake
working-directory: ${{ env.BUILD_DIR }}
run: |
cmake \
-G 'Ninja' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
-Dtests=ON \
-Dwerr=ON \
-Dxrpld=ON \
..
# clang-tidy needs headers generated from proto files
- name: Build libxrpl.libpb
working-directory: ${{ env.BUILD_DIR }}
run: |
ninja -j ${{ steps.nproc.outputs.nproc }} xrpl.libpb
- name: Run clang tidy
id: run_clang_tidy
continue-on-error: true
env:
TARGETS: ${{ inputs.files != '' && inputs.files || 'src tests' }}
run: |
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -fix -allow-no-checks ${TARGETS} 2>&1 | tee clang-tidy-output.txt
- name: Upload clang-tidy output
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: clang-tidy-results
path: clang-tidy-output.txt
retention-days: 30
- name: Generate git diff
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
git diff | tee clang-tidy-git-diff.txt
- name: Upload clang-tidy diff output
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: clang-tidy-git-diff
path: clang-tidy-git-diff.txt
retention-days: 30
- name: Create an issue
if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }}
id: create_issue
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
# Prepare issue body with clang-tidy output
cat > issue.md <<EOF
## Clang-tidy Check Failed
**Workflow:** ${{ github.workflow }}
**Run ID:** ${{ github.run_id }}
**Commit:** ${{ github.sha }}
**Branch/Ref:** ${{ github.ref }}
**Triggered by:** ${{ github.actor }}
### Clang-tidy Output:
\`\`\`
EOF
# Append clang-tidy output (filter for errors and warnings)
if [ -f clang-tidy-output.txt ]; then
# Extract lines containing 'error:', 'warning:', or 'note:'
grep -E '(error:|warning:|note:)' clang-tidy-output.txt > filtered-output.txt || true
# If filtered output is empty, use original (might be a different error format)
if [ ! -s filtered-output.txt ]; then
cp clang-tidy-output.txt filtered-output.txt
fi
# Truncate if too large
head -c 60000 filtered-output.txt >> issue.md
if [ "$(wc -c < filtered-output.txt)" -gt 60000 ]; then
echo "" >> issue.md
echo "... (output truncated, see artifacts for full output)" >> issue.md
fi
rm filtered-output.txt
else
echo "No output file found" >> issue.md
fi
cat >> issue.md <<EOF
\`\`\`
**Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
---
*This issue was automatically created by the clang-tidy workflow.*
EOF
# Create the issue
gh issue create \
--label "Bug,Clang-tidy" \
--title "Clang-tidy check failed" \
--body-file ./issue.md \
> create_issue.log
created_issue="$(sed 's|.*/||' create_issue.log)"
echo "created_issue=$created_issue" >> $GITHUB_OUTPUT
echo "Created issue #$created_issue"
rm -f create_issue.log issue.md clang-tidy-output.txt
- name: Fail the workflow if clang-tidy failed
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
echo "Clang-tidy check failed!"
exit 1

View File

@@ -1,4 +1,4 @@
name: Run clang-tidy on files
name: Clang-tidy check
on:
workflow_call:
@@ -16,175 +16,40 @@ defaults:
run:
shell: bash
env:
BUILD_DIR: build
BUILD_TYPE: Debug # Debug so that ASSERTS and such participate in clang-tidy check
OUTPUT_FILE: clang-tidy-output.txt
DIFF_FILE: clang-tidy-git-diff.txt
ISSUE_FILE: clang-tidy-issue.md
jobs:
determine-files:
name: Determine files to check
if: ${{ inputs.check_only_changed }}
permissions:
contents: read
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@224f3c48d3014d082a1129237b8291ff0b0a331f
run-clang-tidy:
name: Run clang tidy
needs: [determine-files]
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: "ghcr.io/xrplf/ci/debian-trixie:clang-21-sha-53033a2"
permissions:
contents: read
issues: write
runs-on: ubuntu-latest
outputs:
clang_tidy_config_changed: ${{ steps.changed_clang_tidy.outputs.any_changed }}
any_cpp_changed: ${{ steps.changed_files.outputs.any_changed }}
all_changed_files: ${{ steps.changed_files.outputs.all_changed_files }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Prepare runner
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
- name: Get changed C++ files
id: changed_files
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
with:
enable_ccache: false
files: |
**/*.cpp
**/*.h
**/*.ipp
separator: " "
- name: Print build environment
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
- name: Get number of processors
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
id: nproc
- name: Setup Conan
uses: ./.github/actions/setup-conan
- name: Build dependencies
uses: ./.github/actions/build-deps
- name: Get changed clang-tidy configuration
id: changed_clang_tidy
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
with:
build_nproc: ${{ steps.nproc.outputs.nproc }}
build_type: ${{ env.BUILD_TYPE }}
log_verbosity: verbose
files: |
.clang-tidy
- name: Configure CMake
working-directory: ${{ env.BUILD_DIR }}
run: |
cmake \
-G 'Ninja' \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
-Dtests=ON \
-Dwerr=ON \
-Dxrpld=ON \
..
# clang-tidy needs headers generated from proto files
- name: Build libxrpl.libpb
working-directory: ${{ env.BUILD_DIR }}
run: |
ninja -j ${{ steps.nproc.outputs.nproc }} xrpl.libpb
- name: Run clang tidy
id: run_clang_tidy
continue-on-error: true
env:
TARGETS: ${{ (needs.determine-files.outputs.clang_tidy_config_changed != 'true' && inputs.check_only_changed) && needs.determine-files.outputs.cpp_changed_files || 'src tests' }}
run: |
set -o pipefail
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -fix -allow-no-checks ${TARGETS} 2>&1 | tee "${OUTPUT_FILE}"
- name: Print errors
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
sed '/error\||/!d' "${OUTPUT_FILE}"
- name: Upload clang-tidy output
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
path: ${{ env.OUTPUT_FILE }}
archive: false
retention-days: 30
- name: Check for changes
id: files_changed
continue-on-error: true
run: |
git diff --exit-code
- name: Fix style
if: ${{ steps.files_changed.outcome != 'success' }}
run: |
pre-commit run --all-files || true
- name: Generate git diff
if: ${{ steps.files_changed.outcome != 'success' }}
run: |
git diff | tee "${DIFF_FILE}"
- name: Upload clang-tidy diff output
if: ${{ github.event.repository.visibility == 'public' && steps.files_changed.outcome != 'success' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
path: ${{ env.DIFF_FILE }}
archive: false
retention-days: 30
- name: Write issue header
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
cat > "${ISSUE_FILE}" <<EOF
## Clang-tidy Check Failed
### Clang-tidy Output:
\`\`\`
EOF
- name: Append clang-tidy output to issue body (filter for errors and warnings)
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
if [ -f "${OUTPUT_FILE}" ]; then
# Extract lines containing 'error:', 'warning:', or 'note:'
grep -E '(error:|warning:|note:)' "${OUTPUT_FILE}" > filtered-output.txt || true
# If filtered output is empty, use original (might be a different error format)
if [ ! -s filtered-output.txt ]; then
cp "${OUTPUT_FILE}" filtered-output.txt
fi
# Truncate if too large
head -c 60000 filtered-output.txt >> "${ISSUE_FILE}"
if [ "$(wc -c < filtered-output.txt)" -gt 60000 ]; then
echo "" >> "${ISSUE_FILE}"
echo "... (output truncated, see artifacts for full output)" >> "${ISSUE_FILE}"
fi
rm filtered-output.txt
else
echo "No output file found" >> "${ISSUE_FILE}"
fi
- name: Append issue footer
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
cat >> "${ISSUE_FILE}" <<EOF
\`\`\`
---
*This issue was automatically created by the clang-tidy workflow.*
EOF
- name: Create issue
if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }}
uses: XRPLF/actions/create-issue@36d450d12d301e8410c1b7936e5de70c291cbe36
with:
title: "Clang-tidy check failed"
body_file: ${{ env.ISSUE_FILE }}
labels: "Bug,Clang-tidy"
assignees: "godexsoft,mathbunnyru"
- name: Fail if clang-tidy found issues
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
run: |
echo "Clang-tidy check failed!"
exit 1
run-clang-tidy:
needs: [determine-files]
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_cpp_changed == 'true' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
uses: ./.github/workflows/reusable-clang-tidy-files.yml
with:
files: ${{ (needs.determine-files.outputs.clang_tidy_config_changed != 'true' && inputs.check_only_changed) && needs.determine-files.outputs.all_changed_files || '' }}
create_issue_on_failure: ${{ inputs.create_issue_on_failure }}

View File

@@ -1,99 +0,0 @@
# Build Linux packages (DEB and RPM) from pre-built binary artifacts.
# Discovers which configurations to package from linux.json (os entries
# with "package": true) and fans out one job per entry. Today only
# linux/amd64 is emitted; the architecture is hardcoded both here
# (runner) and in generate.py.
name: Package
on:
workflow_call:
inputs:
pkg_release:
description: "Package release number. Increment when repackaging the same executable."
required: false
type: string
default: "1"
defaults:
run:
shell: bash
env:
BUILD_DIR: build
jobs:
generate-matrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: 3.13
- name: Generate packaging matrix
id: generate
working-directory: .github/scripts/strategy-matrix
run: |
./generate.py --packaging --config=linux.json >> "${GITHUB_OUTPUT}"
generate-version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout: |
.github/actions/generate-version
src/libxrpl/protocol/BuildInfo.cpp
- name: Generate version
id: version
uses: ./.github/actions/generate-version
package:
needs: [generate-matrix, generate-version]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
name: "${{ matrix.artifact_name }}"
permissions:
contents: read
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
container: ${{ format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) }}
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Download pre-built binary
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ matrix.artifact_name }}
path: ${{ env.BUILD_DIR }}
- name: Make binary executable
run: chmod +x "${BUILD_DIR}/xrpld"
- name: Build package
env:
PKG_VERSION: ${{ needs.generate-version.outputs.version }}
PKG_RELEASE: ${{ inputs.pkg_release }}
run: ./package/build_pkg.sh
- name: Upload package artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: ${{ github.event.repository.visibility == 'public' }}
with:
name: ${{ matrix.artifact_name }}-pkg-${{ needs.generate-version.outputs.version }}
path: |
${{ env.BUILD_DIR }}/debbuild/*.deb
${{ env.BUILD_DIR }}/debbuild/*.ddeb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/*.rpm
if-no-files-found: error

View File

@@ -70,11 +70,7 @@ repos:
rev: a42085ade523f591dca134379a595e7859986445 # frozen: v9.7.0
hooks:
- id: cspell # Spell check changed files
exclude: |
(?x)^(
.config/cspell.config.yaml|
include/xrpl/protocol_autogen/(transactions|ledger_entries)/.*
)$
exclude: (.config/cspell.config.yaml|^include/xrpl/protocol_autogen/(transactions|ledger_entries)/)
- id: cspell # Spell check the commit message
name: check commit message spelling
args:

View File

@@ -141,7 +141,7 @@ Alternatively, you can pull our recipes from the repository and export them loca
```bash
# Define which recipes to export.
recipes=('abseil' 'ed25519' 'mpt-crypto' 'openssl' 'secp256k1' 'snappy' 'soci' 'wasm-xrplf' 'wasmi')
recipes=('abseil' 'ed25519' 'grpc' 'm4' 'mpt-crypto' 'openssl' 'secp256k1' 'snappy' 'soci' 'wasm-xrplf' 'wasmi')
# Selectively check out the recipes from our CCI fork.
cd external
@@ -530,15 +530,15 @@ stored inside the build directory, as either of:
## Sanitizers
To build dependencies and xrpld with sanitizer instrumentation, set the
`SANITIZERS` environment variable when running `conan install` and use the `sanitizers` profile:
`SANITIZERS` environment variable (only once before running conan and cmake) and use the `sanitizers` profile in conan:
```bash
export SANITIZERS=address,undefinedbehavior
conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug
```
You can then build and test as usual, with the generated `xrpld` binary containing the sanitizer instrumentation. When you run it, it will report any sanitizer errors it detects in the console output.
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -Dxrpld=ON -Dtests=ON ..
```
See [Sanitizers docs](./docs/build/sanitizers.md) for more details.

View File

@@ -134,7 +134,6 @@ endif()
include(XrplCore)
include(XrplProtocolAutogen)
include(XrplInstall)
include(XrplPackaging)
include(XrplValidatorKeys)
if(tests)

499
bin/add_trace_logging.py Normal file
View File

@@ -0,0 +1,499 @@
#!/usr/bin/env python3
"""
Instrument every function in the rippled codebase with TRACE_FUNC().
Adds an RAII trace scope to every function body that logs:
- ENTER on function entry (with file:line)
- EXIT on function exit (with file:line and duration in microseconds)
Usage:
python3 bin/add_trace_logging.py [--dry-run] [--verbose] [--dir path]
"""
import argparse
import os
import re
import sys
from pathlib import Path
TRACE_INCLUDE = '#include <xrpl/basics/TraceLog.h>'
TRACE_CALL = ' TRACE_FUNC();'
# Control-flow keywords that produce a '{' on its own line
# (due to AfterControlStatement: true in .clang-format)
CONTROL_KW_RE = re.compile(
r'^\s*('
r'if\s*\(|'
r'else\s*if\s*\(|'
r'else\s*$|'
r'for\s*\(|'
r'while\s*\(|'
r'do\s*$|'
r'switch\s*\(|'
r'try\s*$|'
r'catch\s*\('
r')'
)
# Structural keywords (class/struct/enum/union) — brace on own line
STRUCT_KW_RE = re.compile(
r'^\s*(class|struct|enum|union)\b'
)
# Namespace — AfterNamespace: false so '{' is on same line,
# but handle edge cases where someone puts it on next line
NAMESPACE_RE = re.compile(r'^\s*namespace\b')
# Lambda capture: line contains ] possibly followed by () and qualifiers
LAMBDA_RE = re.compile(r'\]\s*(\([^)]*\))?\s*(mutable\s*)?(noexcept\s*)?'
r'(->[\s\S]*)?\s*$')
# Function ending: line ends with ) and optional qualifiers
FUNC_END_RE = re.compile(
r'\)\s*'
r'(const\s*)?'
r'(volatile\s*)?'
r'(noexcept(\([^)]*\))?\s*)?'
r'(override\s*)?'
r'(final\s*)?'
r'(requires\s*\([^)]*\)\s*)?'
r'(->[\s\w:<>,*&]+\s*)?'
r'\s*$'
)
# Constructor initializer list line: starts with : or , for member init
INIT_LIST_RE = re.compile(r'^\s*[,:]\s+\w')
# Macro-like patterns to skip
MACRO_RE = re.compile(r'^\s*\\?\s*$')
def find_source_files(root, dirs, extensions=('.cpp',), exclude_dirs=None):
"""Find all source files under given directories."""
if exclude_dirs is None:
exclude_dirs = {'tests', 'test'}
files = []
for d in dirs:
search_dir = root / d
if not search_dir.exists():
continue
for ext in extensions:
for f in sorted(search_dir.rglob(f'*{ext}')):
# Skip test directories
parts = f.relative_to(root).parts
if any(p in exclude_dirs for p in parts):
continue
files.append(f)
return files
def find_template_headers(root):
"""Find .h files with template implementations that need instrumentation."""
headers = []
# These directories have header-only template implementations
template_dirs = [
'src/xrpld/consensus',
'src/xrpld/overlay',
'src/xrpld/overlay/detail',
'src/xrpld/peerfinder',
'src/xrpld/peerfinder/detail',
'src/xrpld/app/consensus',
'src/xrpld/app/ledger',
'src/xrpld/app/ledger/detail',
'src/xrpld/app/misc',
'src/xrpld/app/misc/detail',
'src/xrpld/app/main',
'src/xrpld/rpc',
'src/xrpld/rpc/detail',
'src/xrpld/core',
'src/xrpld/core/detail',
]
for d in template_dirs:
search_dir = root / d
if not search_dir.exists():
continue
for f in sorted(search_dir.glob('*.h')):
headers.append(f)
# Also include key libxrpl headers with implementations
libxrpl_dirs = [
'include/xrpl/shamap',
'include/xrpl/basics',
'include/xrpl/protocol',
]
for d in libxrpl_dirs:
search_dir = root / d
if not search_dir.exists():
continue
for f in sorted(search_dir.glob('*.h')):
# Skip TraceLog.h itself
if f.name == 'TraceLog.h':
continue
headers.append(f)
return headers
def add_include(lines):
"""Add the TraceLog.h include if not already present. Returns modified lines."""
# Check if already included
for line in lines:
if 'TraceLog.h' in line:
return lines, False
# Find insertion point: after last #include <xrpl/...> or <xrpld/...>
last_xrpl_idx = -1
last_xrpld_idx = -1
last_include_idx = -1
for i, line in enumerate(lines):
stripped = line.strip()
if stripped.startswith('#include'):
last_include_idx = i
if '<xrpl/' in stripped:
last_xrpl_idx = i
elif '<xrpld/' in stripped:
last_xrpld_idx = i
if last_include_idx == -1:
return lines, False # No includes at all — skip
# Prefer inserting after xrpl/ includes (same group), else after xrpld/
if last_xrpl_idx >= 0:
insert_at = last_xrpl_idx + 1
elif last_xrpld_idx >= 0:
# Insert after the xrpld block, with a blank line before xrpl includes
insert_at = last_xrpld_idx + 1
else:
insert_at = last_include_idx + 1
lines.insert(insert_at, TRACE_INCLUDE + '\n')
return lines, True
def get_prev_nonblank(lines, idx):
"""Get the index of the previous non-blank line before idx."""
i = idx - 1
while i >= 0:
if lines[i].strip():
return i
i -= 1
return -1
def find_matching_open_paren_line(lines, start_idx):
"""
Starting from start_idx, walk backwards through lines to find the line
containing the '(' that matches the last ')' on start_idx's line.
Returns the line index, or -1 if not found.
Uses character-level paren tracking for accuracy.
"""
depth = 0
for scan in range(start_idx, max(start_idx - 30, -1), -1):
line = lines[scan].rstrip()
for ch in reversed(line):
if ch == ')':
depth += 1
elif ch == '(':
depth -= 1
if depth == 0:
return scan
return -1
def is_lambda(lines, brace_idx):
"""Check if the '{' at brace_idx opens a lambda body."""
# Walk back up to 5 non-blank lines looking for ] (lambda capture close)
prev = brace_idx - 1
checked = 0
while prev >= 0 and checked < 6:
line = lines[prev].rstrip()
if not line.strip():
prev -= 1
continue
# Lambda pattern: line contains ']' possibly followed by () qualifiers
if ']' in line:
# Skip C++ attributes like [[nodiscard]], [[maybe_unused]], etc.
# Attributes use [[ ]] (double brackets)
stripped = line.strip()
if re.match(r'^\[\[', stripped):
# This is a C++ attribute, not a lambda
checked += 1
prev -= 1
continue
# Also skip ]] patterns mid-line (attributes in return types)
if ']]' in line and '[[' in line:
checked += 1
prev -= 1
continue
# Check for actual lambda pattern: ] followed by ( or { or mutable
# Lambda captures end with ] then optional (params) or {body}
if re.search(r'\]\s*(\([^)]*\))?\s*(mutable\s*)?(noexcept\s*)?'
r'(->[\s\S]*)?\s*$', line):
return True
# Stop walking back at scope boundaries
if line.strip().startswith('{') or line.strip().startswith('}'):
break
if line.strip().startswith('#'):
break
checked += 1
prev -= 1
return False
def is_function_body(lines, brace_idx):
"""
Determine if the '{' at brace_idx opens a function body.
Returns True if this looks like a function definition, False otherwise.
"""
prev_idx = get_prev_nonblank(lines, brace_idx)
if prev_idx < 0:
return False
prev_line = lines[prev_idx].rstrip()
# Skip if preceded by a single-line control keyword
if CONTROL_KW_RE.match(prev_line):
return False
# Skip namespace
if NAMESPACE_RE.match(prev_line):
return False
# Skip class/struct/enum/union
if STRUCT_KW_RE.match(prev_line):
return False
# Skip lambdas
if is_lambda(lines, brace_idx):
return False
# Case 1: Previous line ends with ) + optional qualifiers
if FUNC_END_RE.search(prev_line):
# Walk back to find the line with the matching '('
open_paren_line = find_matching_open_paren_line(lines, prev_idx)
if open_paren_line >= 0:
# Check if that line (or preceding lines) is a control keyword
line = lines[open_paren_line].rstrip()
if CONTROL_KW_RE.match(line):
return False
# Also check the line before (for multi-line: "else\n if(...)")
prev_kw = get_prev_nonblank(lines, open_paren_line)
if prev_kw >= 0:
kw_line = lines[prev_kw].rstrip()
if re.match(r'^\s*else\s*$', kw_line):
return False
return True
# Case 2: Constructor initializer list — line starts with , or :
if INIT_LIST_RE.match(prev_line):
# Walk back through initializer list to find constructor signature
scan = prev_idx - 1
while scan >= 0:
line = lines[scan].rstrip()
if FUNC_END_RE.search(line):
return True
if not INIT_LIST_RE.match(line) and ')' not in line:
break
scan -= 1
# Even if we can't find the signature, an init list implies constructor
return True
# Case 3: Previous line ends with something unusual — check a few
# lines back for a ')' that might be part of a function signature
# (e.g., trailing requires clause or -> return type on separate line)
for lookback in range(1, 4):
check_idx = prev_idx - lookback
if check_idx < 0:
break
check_line = lines[check_idx].rstrip()
if check_line.strip() == '' or check_line.strip().startswith('#'):
break
if FUNC_END_RE.search(check_line):
open_paren_line = find_matching_open_paren_line(
lines, check_idx)
if open_paren_line >= 0:
if CONTROL_KW_RE.match(lines[open_paren_line].rstrip()):
return False
return True
return False
def is_empty_body(lines, brace_idx):
"""Check if the function body is empty (next non-blank line is '}')."""
i = brace_idx + 1
while i < len(lines):
stripped = lines[i].strip()
if stripped:
return stripped == '}'
i += 1
return True
def already_has_trace(lines, brace_idx):
"""Check if TRACE_FUNC is already the first statement."""
i = brace_idx + 1
while i < len(lines):
stripped = lines[i].strip()
if stripped:
return 'TRACE_FUNC()' in stripped
i += 1
return False
def get_function_context(lines, brace_idx):
"""Try to extract a meaningful function name from the context."""
prev_idx = get_prev_nonblank(lines, brace_idx)
if prev_idx < 0:
return "unknown"
# Walk back to find the function name line
scan = prev_idx
while scan >= 0:
line = lines[scan].strip()
# Look for ClassName::methodName or just functionName
match = re.search(r'(\w+(?:::\w+)?)\s*\(', line)
if match:
return match.group(1)
if line.startswith('#') or line == '':
break
scan -= 1
return lines[prev_idx].strip()[:60]
def instrument_file(filepath, dry_run=False, verbose=False):
"""
Add TRACE_FUNC() to every function body in the given file.
Returns (functions_found, include_added) tuple.
"""
with open(filepath, 'r') as f:
lines = f.readlines()
original_lines = list(lines)
functions_found = 0
insertions = [] # (line_index, context_string)
# Pass 1: Find all function body openings
# Track brace depth to skip nested blocks inside functions
brace_depth = 0
in_function = False
i = 0
while i < len(lines):
line = lines[i]
stripped = line.strip()
if in_function:
# Count braces to track nesting within the current function
brace_depth += stripped.count('{') - stripped.count('}')
if brace_depth <= 0:
in_function = False
brace_depth = 0
elif stripped == '{':
if is_function_body(lines, i):
if not is_empty_body(lines, i) and not already_has_trace(lines, i):
ctx = get_function_context(lines, i)
insertions.append((i, ctx))
functions_found += 1
in_function = True
brace_depth = 1
i += 1
if functions_found == 0 and not any('TraceLog.h' in l for l in lines):
return 0, False # Nothing to do
# Pass 2: Add include
include_added = False
if functions_found > 0:
lines, include_added = add_include(lines)
# Adjust insertion indices if include was added
if include_added:
# Find where the include was inserted
for idx in range(len(lines)):
if TRACE_INCLUDE in lines[idx]:
include_line = idx
break
insertions = [
(i + 1 if i >= include_line else i, ctx)
for i, ctx in insertions
]
# Pass 3: Insert TRACE_FUNC() calls (reverse order to preserve indices)
for insert_idx, ctx in reversed(insertions):
lines.insert(insert_idx + 1, TRACE_CALL + '\n')
if verbose and functions_found > 0:
rel_path = filepath.name
print(f" {rel_path}: {functions_found} functions")
for _, ctx in insertions:
print(f" -> {ctx}")
if not dry_run and lines != original_lines:
with open(filepath, 'w') as f:
f.writelines(lines)
return functions_found, include_added
def main():
parser = argparse.ArgumentParser(
description='Add TRACE_FUNC() to every function in the rippled codebase')
parser.add_argument('--dry-run', action='store_true',
help='Print what would change without modifying files')
parser.add_argument('--verbose', '-v', action='store_true',
help='Show each function found')
parser.add_argument('--dir', type=str, default=None,
help='Only process files under this subdirectory')
parser.add_argument('--headers', action='store_true',
help='Also process .h files with template implementations')
parser.add_argument('--root', type=str, default='.',
help='Project root directory')
args = parser.parse_args()
root = Path(args.root).resolve()
# Find source files
if args.dir:
dirs = [args.dir]
else:
dirs = ['src/xrpld', 'src/libxrpl']
files = find_source_files(root, dirs)
if args.headers:
files.extend(find_template_headers(root))
if not files:
print(f"No source files found under {root}")
sys.exit(1)
total_functions = 0
total_includes = 0
total_files_modified = 0
mode = "DRY RUN" if args.dry_run else "INSTRUMENTING"
print(f"[{mode}] Processing {len(files)} files under {root}")
print()
for filepath in files:
funcs, inc = instrument_file(
filepath, dry_run=args.dry_run, verbose=args.verbose)
if funcs > 0:
total_functions += funcs
total_files_modified += 1
if inc:
total_includes += 1
print()
print(f"{'Would instrument' if args.dry_run else 'Instrumented'}: "
f"{total_functions} functions across {total_files_modified} files")
print(f"{'Would add' if args.dry_run else 'Added'}: "
f"{total_includes} new #include directives")
if __name__ == '__main__':
main()

View File

@@ -28,7 +28,7 @@
# https://vl.ripple.com
# https://unl.xrplf.org
# http://127.0.0.1:8000
# file:///etc/xrpld/vl.txt
# file:///etc/opt/xrpld/vl.txt
#
# [validator_list_keys]
#

View File

@@ -527,17 +527,6 @@
#
# The current default (which is subject to change) is 300 seconds.
#
# verify_endpoints = <0 | 1>
#
# If set to 0, the server will skip validation of endpoint
# addresses received in TMEndpoints peer protocol messages,
# allowing addresses that are not publicly routable or have a
# port of 0. The default is 1 (verification enabled).
#
# WARNING: Disabling this option is a security risk and should
# only be used for local testing and debugging. Do not disable
# on mainnet.
#
#
# [transaction_queue] EXPERIMENTAL
#
@@ -1269,7 +1258,7 @@
# default. Don't change this without understanding the consequences.
#
# Example:
# account_reserve = 1000000 # 1 XRP
# account_reserve = 10000000 # 10 XRP
#
# owner_reserve = <drops>
#
@@ -1281,7 +1270,7 @@
# default. Don't change this without understanding the consequences.
#
# Example:
# owner_reserve = 200000 # 0.2 XRP
# owner_reserve = 2000000 # 2 XRP
#
#-------------------------------------------------------------------------------
#
@@ -1466,7 +1455,10 @@ admin = 127.0.0.1
protocol = http
[port_peer]
port = 2459
# Many servers still use the legacy port of 51235, so for backward-compatibility
# we maintain that port number here. However, for new servers we recommend
# changing this to the default port of 2459.
port = 51235
ip = 0.0.0.0
# alternatively, to accept connections on IPv4 + IPv6, use:
#ip = ::

View File

@@ -1,44 +0,0 @@
#[===================================================================[
Linux packaging support: 'package' target.
The packaging script (package/build_pkg.sh) installs to FHS-standard
paths (/usr/bin, /etc/xrpld, etc.) regardless of CMAKE_INSTALL_PREFIX,
so no prefix guard is needed here.
#]===================================================================]
if(NOT is_linux)
message(STATUS "Packaging not supported on non-Linux hosts")
return()
endif()
if(NOT DEFINED pkg_release)
set(pkg_release 1)
endif()
find_program(RPMBUILD_EXECUTABLE rpmbuild)
find_program(DPKG_BUILDPACKAGE_EXECUTABLE dpkg-buildpackage)
if(NOT (RPMBUILD_EXECUTABLE OR DPKG_BUILDPACKAGE_EXECUTABLE))
message(
STATUS
"Neither rpmbuild nor dpkg-buildpackage found; 'package' target not available"
)
return()
endif()
set(package_env
SRC_DIR=${CMAKE_SOURCE_DIR}
BUILD_DIR=${CMAKE_BINARY_DIR}
PKG_VERSION=${xrpld_version}
PKG_RELEASE=${pkg_release}
)
add_custom_target(
package
COMMAND
${CMAKE_COMMAND} -E env ${package_env}
${CMAKE_SOURCE_DIR}/package/build_pkg.sh
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS xrpld
COMMENT "Building Linux package (deb/rpm inferred from host tooling)"
VERBATIM
)

View File

@@ -1,33 +1,140 @@
#[===================================================================[
Apply sanitizer flags built by the Conan profile.
Configure sanitizers based on environment variables.
Parsing, validation, and flag construction are performed in conan/profiles/sanitizers.
This module reads the following CMake variables injected by the Conan toolchain via extra_variables:
This module reads the following environment variables:
- SANITIZERS: The sanitizers to enable. Possible values:
- "address"
- "address,undefinedbehavior"
- "thread"
- "thread,undefinedbehavior"
- "undefinedbehavior"
- SANITIZERS: The active sanitizers (e.g. "address,undefinedbehavior").
- SANITIZERS_COMPILER_FLAGS: Space-separated compiler flags.
- SANITIZERS_LINKER_FLAGS: Space-separated linker flags.
The compiler type and platform are detected in CompilationEnv.cmake.
The sanitizer compile options are applied to the 'common' interface library
which is linked to all targets in the project.
The flags are applied to the 'common' interface library which is linked to all targets in the project.
Internal flag variables set by this module:
- SANITIZER_TYPES: List of sanitizer types to enable (e.g., "address",
"thread", "undefined"). And two more flags for undefined behavior sanitizer (e.g., "float-divide-by-zero", "unsigned-integer-overflow").
This list is joined with commas and passed to -fsanitize=<list>.
- SANITIZERS_COMPILE_FLAGS: Compiler flags for sanitizer instrumentation.
Includes:
* -fno-omit-frame-pointer: Preserves frame pointers for stack traces
* -O1: Minimum optimization for reasonable performance
* -fsanitize=<types>: Enables sanitizer instrumentation
* -fsanitize-ignorelist=<path>: (Clang only) Compile-time ignorelist
* -mcmodel=large/medium: (GCC only) Code model for large binaries
* -Wno-stringop-overflow: (GCC only) Suppresses false positive warnings
* -Wno-tsan: (For GCC TSAN combination only) Suppresses atomic_thread_fence warnings
- SANITIZERS_LINK_FLAGS: Linker flags for sanitizer runtime libraries.
Includes:
* -fsanitize=<types>: Links sanitizer runtime libraries
* -mcmodel=large/medium: (GCC only) Matches compile-time code model
- SANITIZERS_RELOCATION_FLAGS: (GCC only, x86_64 only) Code model flags for linking.
Used to handle large instrumented binaries on x86_64:
* -mcmodel=large: For AddressSanitizer (prevents relocation errors)
* -mcmodel=medium: For ThreadSanitizer (large model is incompatible)
On ARM64, these flags are omitted since GCC does not support
-mcmodel=large with -fPIC, and -mcmodel=medium does not exist.
#]===================================================================]
include_guard(GLOBAL)
include(CompilationEnv)
if(NOT DEFINED SANITIZERS)
# Read environment variable
set(SANITIZERS "")
if(DEFINED ENV{SANITIZERS})
set(SANITIZERS "$ENV{SANITIZERS}")
endif()
# Set SANITIZERS_ENABLED flag for use in other modules
if(SANITIZERS MATCHES "address|thread|undefinedbehavior")
set(SANITIZERS_ENABLED TRUE)
else()
set(SANITIZERS_ENABLED FALSE)
return()
endif()
set(SANITIZERS_ENABLED TRUE)
message(STATUS "=== Configuring Sanitizers ===")
message(STATUS " SANITIZERS: ${SANITIZERS}")
message(STATUS " Compile flags: ${SANITIZERS_COMPILER_FLAGS}")
message(STATUS " Link flags: ${SANITIZERS_LINKER_FLAGS}")
# Sanitizers are not supported on Windows/MSVC
if(is_msvc)
message(
FATAL_ERROR
"Sanitizers are not supported on Windows/MSVC. "
"Please unset the SANITIZERS environment variable."
)
endif()
# GCC with sanitizers is incompatible with mold, gold, and lld linkers.
# Namely, the instrumented binary exceeds size limits imposed by these linkers.
message(STATUS "Configuring sanitizers: ${SANITIZERS}")
# Parse SANITIZERS value to determine which sanitizers to enable
set(enable_asan FALSE)
set(enable_tsan FALSE)
set(enable_ubsan FALSE)
# Normalize SANITIZERS into a list
set(san_list "${SANITIZERS}")
string(REPLACE "," ";" san_list "${san_list}")
separate_arguments(san_list)
foreach(san IN LISTS san_list)
if(san STREQUAL "address")
set(enable_asan TRUE)
elseif(san STREQUAL "thread")
set(enable_tsan TRUE)
elseif(san STREQUAL "undefinedbehavior")
set(enable_ubsan TRUE)
else()
message(
FATAL_ERROR
"Unsupported sanitizer type: ${san}"
"Supported: address, thread, undefinedbehavior and their combinations."
)
endif()
endforeach()
# Validate sanitizer compatibility
if(enable_asan AND enable_tsan)
message(
FATAL_ERROR
"AddressSanitizer and ThreadSanitizer are incompatible and cannot be enabled simultaneously. "
"Use 'address' or 'thread', optionally with 'undefinedbehavior'."
)
endif()
# Frame pointer is required for meaningful stack traces. Sanitizers recommend minimum of -O1 for reasonable performance
set(SANITIZERS_COMPILE_FLAGS "-fno-omit-frame-pointer" "-O1")
# Build the sanitizer flags list
set(SANITIZER_TYPES)
if(enable_asan)
list(APPEND SANITIZER_TYPES "address")
elseif(enable_tsan)
list(APPEND SANITIZER_TYPES "thread")
endif()
if(enable_ubsan)
# UB sanitizer flags
list(APPEND SANITIZER_TYPES "undefined" "float-divide-by-zero")
if(is_clang)
# Clang supports additional UB checks. More info here
# https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
list(APPEND SANITIZER_TYPES "unsigned-integer-overflow")
endif()
endif()
# Configure code model for GCC on amd64 Use large code model for ASAN to avoid relocation errors Use medium code model
# for TSAN (large is not compatible with TSAN)
set(SANITIZERS_RELOCATION_FLAGS)
# Compiler-specific configuration
if(is_gcc)
# Disable mold, gold and lld linkers for GCC with sanitizers Use default linker (bfd/ld) which is more lenient with
# mixed code models This is needed since the size of instrumented binary exceeds the limits set by mold, lld and
# gold linkers
set(use_mold OFF CACHE BOOL "Use mold linker" FORCE)
set(use_gold OFF CACHE BOOL "Use gold linker" FORCE)
set(use_lld OFF CACHE BOOL "Use lld linker" FORCE)
@@ -35,62 +142,82 @@ if(is_gcc)
STATUS
" Disabled mold, gold, and lld linkers for GCC with sanitizers"
)
# Suppress false positive warnings in GCC with stringop-overflow
list(APPEND SANITIZERS_COMPILE_FLAGS "-Wno-stringop-overflow")
if(is_amd64 AND enable_asan)
message(STATUS " Using large code model (-mcmodel=large)")
list(APPEND SANITIZERS_COMPILE_FLAGS "-mcmodel=large")
list(APPEND SANITIZERS_RELOCATION_FLAGS "-mcmodel=large")
elseif(enable_tsan)
# GCC doesn't support atomic_thread_fence with tsan. Suppress warnings.
list(APPEND SANITIZERS_COMPILE_FLAGS "-Wno-tsan")
if(is_amd64)
message(STATUS " Using medium code model (-mcmodel=medium)")
list(APPEND SANITIZERS_COMPILE_FLAGS "-mcmodel=medium")
list(APPEND SANITIZERS_RELOCATION_FLAGS "-mcmodel=medium")
endif()
endif()
# Join sanitizer flags with commas for -fsanitize option
list(JOIN SANITIZER_TYPES "," SANITIZER_TYPES_STR)
# Add sanitizer to compile and link flags
list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
set(SANITIZERS_LINK_FLAGS
"${SANITIZERS_RELOCATION_FLAGS}"
"-fsanitize=${SANITIZER_TYPES_STR}"
)
elseif(is_clang)
# Add ignorelist for Clang (GCC doesn't support this) Use CMAKE_SOURCE_DIR to get the path to the ignorelist
set(IGNORELIST_PATH
"${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt"
)
if(NOT EXISTS "${IGNORELIST_PATH}")
message(
FATAL_ERROR
"Sanitizer ignorelist not found: ${IGNORELIST_PATH}"
)
endif()
list(
APPEND SANITIZERS_COMPILE_FLAGS
"-fsanitize-ignorelist=${IGNORELIST_PATH}"
)
message(STATUS " Using sanitizer ignorelist: ${IGNORELIST_PATH}")
# Join sanitizer flags with commas for -fsanitize option
list(JOIN SANITIZER_TYPES "," SANITIZER_TYPES_STR)
# Add sanitizer to compile and link flags
list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
set(SANITIZERS_LINK_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
endif()
# Flags arrive as space-separated strings; split into CMake lists before use
separate_arguments(
sanitizers_compiler_flags
UNIX_COMMAND
"${SANITIZERS_COMPILER_FLAGS}"
)
separate_arguments(
sanitizers_linker_flags
UNIX_COMMAND
"${SANITIZERS_LINKER_FLAGS}"
)
message(STATUS " Compile flags: ${SANITIZERS_COMPILE_FLAGS}")
message(STATUS " Link flags: ${SANITIZERS_LINK_FLAGS}")
# Apply the sanitizer flags to the 'common' interface library This is the same library used by XrplCompiler.cmake
target_compile_options(
common
INTERFACE
$<$<COMPILE_LANGUAGE:CXX>:${sanitizers_compiler_flags}>
$<$<COMPILE_LANGUAGE:C>:${sanitizers_compiler_flags}>
$<$<COMPILE_LANGUAGE:CXX>:${SANITIZERS_COMPILE_FLAGS}>
$<$<COMPILE_LANGUAGE:C>:${SANITIZERS_COMPILE_FLAGS}>
)
target_link_options(common INTERFACE ${sanitizers_linker_flags})
# This module appends -fsanitize-ignorelist=<path> for Clang builds.
# The ignorelist path contains CMAKE_SOURCE_DIR, so it must be set here, rather than in the Conan profile.
# GCC does not support -fsanitize-ignorelist.
if(is_clang)
set(ignorelist_path
"${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt"
)
if(NOT EXISTS "${ignorelist_path}")
message(
FATAL_ERROR
"Sanitizer ignorelist not found: ${ignorelist_path}"
)
endif()
target_compile_options(
common
INTERFACE
$<$<COMPILE_LANGUAGE:CXX>:-fsanitize-ignorelist=${ignorelist_path}>
$<$<COMPILE_LANGUAGE:C>:-fsanitize-ignorelist=${ignorelist_path}>
)
message(STATUS " Ignorelist: ${ignorelist_path}")
endif()
# Apply linker flags
target_link_options(common INTERFACE ${SANITIZERS_LINK_FLAGS})
# Define SANITIZERS macro for BuildInfo.cpp
set(sanitizers_list)
if(SANITIZERS MATCHES "address")
set(enable_asan ON)
if(enable_asan)
list(APPEND sanitizers_list "ASAN")
endif()
if(SANITIZERS MATCHES "thread")
set(enable_tsan ON)
if(enable_tsan)
list(APPEND sanitizers_list "TSAN")
endif()
if(SANITIZERS MATCHES "undefinedbehavior")
set(enable_ubsan ON)
if(enable_ubsan)
list(APPEND sanitizers_list "UBSAN")
endif()

View File

@@ -10,4 +10,4 @@ pcpp>=1.30
pyparsing>=3.0.0
# Template engine - used to generate C++ code from templates
Mako>=1.2.2
Mako>=1.2.0

View File

@@ -1,38 +1,38 @@
{
"version": "0.5",
"requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1777558780.503",
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1774439233.809",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987",
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1776096494.149",
"sqlite3/3.51.0#66aa11eabd0e34954c5c1c061ad44abe%1774467355.988",
"soci/4.0.3#fe32b9ad5eb47e79ab9e45a68f363945%1774450067.231",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878",
"secp256k1/0.7.1#481881709eb0bdd0185a12b912bbe8ad%1770910500.329",
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1765850186.86",
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1774398111.888",
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12",
"openssl/3.6.2#4789bbf131b77d0515d15e094c8f697f%1778071755.506",
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1775040983.408",
"openssl/3.6.1#e6399de266349245a4542fc5f6c71552%1774458290.139",
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1774883011.384",
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914",
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492",
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1765842973.03",
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1776147552.838",
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
"libarchive/3.8.1#ffee18995c706e02bf96e7a2f7042e0d%1765850144.736",
"jemalloc/5.3.0#e951da9cf599e956cebc117880d2d9f8%1729241615.244",
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1768312129.152",
"grpc/1.78.1#b1a9e74b145cc471bed4dc64dc6eb2c1%1774467387.342",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1765850143.772",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1765850143.772",
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1774439234.681",
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1765850143.837",
"boost/1.91.0#ea540ca2133d831b560036aa24dece3c%1778050991.9",
"boost/1.90.0#d5e8defe7355494953be18524a7f135b%1769454080.269",
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196"
],
"build_requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1777558780.503",
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1774439233.809",
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1774447376.964",
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12",
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1765850144.707",
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
"m4/1.4.19#4523e4347b55cd26ae918bd5770cab9a%1778062762.471",
"m4/1.4.19#5d7a4994e5875d76faf7acf3ed056036%1774365463.87",
"cmake/4.3.0#b939a42e98f593fb34d3a8c5cc860359%1774439249.183",
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1774439233.447",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
@@ -48,13 +48,13 @@
"lz4/1.10.0"
],
"boost/[>=1.83.0 <1.91.0]": [
"boost/1.91.0"
"boost/1.90.0"
],
"sqlite3/[>=3.44 <4]": [
"sqlite3/3.53.0"
"sqlite3/3.51.0"
],
"boost/1.83.0": [
"boost/1.91.0"
"boost/1.90.0"
],
"lz4/[>=1.9.4 <2]": [
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504"

View File

@@ -3,5 +3,3 @@
core:non_interactive=True
core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }}
tools.files.download:retry=5
tools.files.download:retry_wait=10

View File

@@ -1 +1 @@
include(sanitizers)
include(sanitizers)

View File

@@ -3,120 +3,96 @@ include(default)
{% set arch = detect_api.detect_arch() %}
{% set sanitizers = os.getenv("SANITIZERS") %}
{% if not sanitizers %}
{# Sanitizers not configured; no additional settings needed #}
{% else %}
[conf]
{% if sanitizers %}
{% if compiler == "gcc" %}
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
{% set sanitizer_list = [] %}
{% set defines = [] %}
{% set model_code = "" %}
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1", "-Wno-stringop-overflow"] %}
{% if compiler == "msvc" %}
{{ "Sanitizers are not supported on Windows/MSVC. Please unset the SANITIZERS environment variable." }}
{% endif %}
{% if "address" in sanitizers %}
{% set _ = sanitizer_list.append("address") %}
{% if arch == "x86_64" %}
{% set model_code = "-mcmodel=large" %}
{% endif %}
{% set _ = defines.append("BOOST_USE_ASAN")%}
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
{% elif "thread" in sanitizers %}
{% set _ = sanitizer_list.append("thread") %}
{% if arch == "x86_64" %}
{% set model_code = "-mcmodel=medium" %}
{% endif %}
{% set _ = extra_cxxflags.append("-Wno-tsan") %}
{% set _ = defines.append("BOOST_USE_TSAN")%}
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
{% endif %}
{% set known_sanitizers = ["address", "thread", "undefinedbehavior"] %}
{% set provided_sanitizers = [] %}
{% for san in sanitizers.split(",") %}
{% set san = san.strip() %}
{% if san not in known_sanitizers %}
{{ "Unknown sanitizer in SANITIZERS: " ~ san }}
{% endif %}
{% set _ = provided_sanitizers.append(san) %}
{% endfor %}
{% if "undefinedbehavior" in sanitizers %}
{% set _ = sanitizer_list.append("undefined") %}
{% set _ = sanitizer_list.append("float-divide-by-zero") %}
{% endif %}
{% set enable_asan = "address" in provided_sanitizers %}
{% set enable_tsan = "thread" in provided_sanitizers %}
{% set enable_ubsan = "undefinedbehavior" in provided_sanitizers %}
{% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) ~ " " ~ model_code %}
{% if enable_asan and enable_tsan %}
{{ "AddressSanitizer and ThreadSanitizer are incompatible and cannot be enabled simultaneously." }}
{% endif %}
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
tools.build:exelinkflags+=['{{sanitizer_flags}}']
tools.build:defines+={{defines}}
{% endif %}
{% elif compiler == "apple-clang" or compiler == "clang" %}
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
{% set sanitizer_list = [] %}
{% set defines = [] %}
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1"] %}
{% set sanitizer_types = [] %}
{% set defines = [] %}
{% if "address" in sanitizers %}
{% set _ = sanitizer_list.append("address") %}
{% set _ = defines.append("BOOST_USE_ASAN")%}
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
{% elif "thread" in sanitizers %}
{% set _ = sanitizer_list.append("thread") %}
{% set _ = defines.append("BOOST_USE_TSAN")%}
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
{% endif %}
{% if enable_asan %}
{% set _ = sanitizer_types.append("address") %}
{% set _ = defines.append("BOOST_USE_ASAN") %}
{% set _ = defines.append("BOOST_USE_UCONTEXT") %}
{% elif enable_tsan %}
{% set _ = sanitizer_types.append("thread") %}
{% set _ = defines.append("BOOST_USE_TSAN") %}
{% set _ = defines.append("BOOST_USE_UCONTEXT") %}
{% endif %}
{% if "undefinedbehavior" in sanitizers %}
{% set _ = sanitizer_list.append("undefined") %}
{% set _ = sanitizer_list.append("float-divide-by-zero") %}
{% set _ = sanitizer_list.append("unsigned-integer-overflow") %}
{% endif %}
{% if enable_ubsan %}
{% set _ = sanitizer_types.append("undefined") %}
{% set _ = sanitizer_types.append("float-divide-by-zero") %}
{# Clang supports additional UB checks beyond the GCC baseline #}
{% if compiler == "clang" or compiler == "apple-clang" %}
{% set _ = sanitizer_types.append("unsigned-integer-overflow") %}
{% endif %}
{% endif %}
{% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) %}
{# Frame pointer required for meaningful stack traces; -O1 for reasonable performance #}
{% set compile_flags = ["-fno-omit-frame-pointer", "-O1"] %}
{% if compiler == "gcc" %}
{# Suppress false positive warnings with GCC #}
{% set _ = compile_flags.append("-Wno-stringop-overflow") %}
{% set relocation_flags = [] %}
{% if arch == "x86_64" and enable_asan %}
{# Large code model prevents relocation errors in instrumented ASAN binaries #}
{% set _ = compile_flags.append("-mcmodel=large") %}
{% set _ = relocation_flags.append("-mcmodel=large") %}
{% elif enable_tsan %}
{# GCC doesn't support atomic_thread_fence with TSAN; suppress warnings #}
{% set _ = compile_flags.append("-Wno-tsan") %}
{% if arch == "x86_64" %}
{# Medium code model for TSAN; large is incompatible #}
{% set _ = compile_flags.append("-mcmodel=medium") %}
{% set _ = relocation_flags.append("-mcmodel=medium") %}
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
tools.build:exelinkflags+=['{{sanitizer_flags}}']
tools.build:defines+={{defines}}
{% endif %}
{% endif %}
{% set fsanitize = "-fsanitize=" ~ ",".join(sanitizer_types) %}
{% set _ = compile_flags.append(fsanitize) %}
{% set _ = relocation_flags.append(fsanitize) %}
{% set sanitizer_compiler_flags = " ".join(compile_flags) %}
{% set sanitizer_linker_flags = " ".join(relocation_flags) %}
{% elif compiler == "clang" or compiler == "apple-clang" %}
{% set fsanitize = "-fsanitize=" ~ ",".join(sanitizer_types) %}
{% set _ = compile_flags.append(fsanitize) %}
{% set sanitizer_compiler_flags = " ".join(compile_flags) %}
{% set sanitizer_linker_flags = fsanitize %}
{% endif %}
[conf]
tools.build:defines+={{defines}}
tools.build:cxxflags+=['{{sanitizer_compiler_flags}}']
tools.build:sharedlinkflags+=['{{sanitizer_linker_flags}}']
tools.build:exelinkflags+=['{{sanitizer_linker_flags}}']
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags", "tools.build:defines"]
# &: means "apply only to the consumer/root package"
&:tools.cmake.cmaketoolchain:extra_variables={"SANITIZERS": "{{sanitizers}}", "SANITIZERS_COMPILER_FLAGS": "{{sanitizer_compiler_flags}}", "SANITIZERS_LINKER_FLAGS": "{{sanitizer_linker_flags}}"}
[options]
{% if enable_asan %}
# Build Boost.Context with ucontext backend (not fcontext) so that
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
# are compiled into the library. fcontext (assembly) has no ASAN support.
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
boost/*:without_context=False
# Boost stacktrace fails to build with some sanitizers
boost/*:without_stacktrace=True
{% elif enable_tsan %}
# Build Boost.Context with ucontext backend for TSAN. fcontext (assembly)
# has no TSAN annotations, so without this the BOOST_USE_TSAN/BOOST_USE_UCONTEXT
# defines in [conf] would be ineffective.
boost/*:extra_b2_flags=context-impl=ucontext thread-sanitizer=on define=BOOST_USE_TSAN=1
boost/*:without_context=False
boost/*:without_stacktrace=True
{% endif %}
{% if sanitizers %}
{% if "address" in sanitizers %}
# Build Boost.Context with ucontext backend (not fcontext) so that
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
# are compiled into the library. fcontext (assembly) has no ASAN support.
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
boost/*:without_context=False
# Boost stacktrace fails to build with some sanitizers
boost/*:without_stacktrace=True
{% elif "thread" in sanitizers %}
# Build Boost.Context with ucontext backend for TSAN. fcontext (assembly)
# has no TSAN annotations, so without this the BOOST_USE_TSAN/BOOST_USE_UCONTEXT
# defines in [conf] would be ineffective.
boost/*:extra_b2_flags=context-impl=ucontext thread-sanitizer=on define=BOOST_USE_TSAN=1
boost/*:without_context=False
boost/*:without_stacktrace=True
{% endif %}
{% endif %}

View File

@@ -1,3 +1,4 @@
import os
import re
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
@@ -29,12 +30,12 @@ class Xrpl(ConanFile):
requires = [
"ed25519/2015.03",
"grpc/1.78.1",
"libarchive/3.8.7",
"libarchive/3.8.1",
"nudb/2.0.9",
"openssl/3.6.2",
"openssl/3.6.1",
"secp256k1/0.7.1",
"soci/4.0.3",
"zlib/1.3.2",
"zlib/1.3.1",
]
test_requires = [
@@ -56,7 +57,6 @@ class Xrpl(ConanFile):
"tests": False,
"unity": False,
"xrpld": False,
"boost/*:without_cobalt": True,
"boost/*:without_context": False,
"boost/*:without_coroutine": True,
"boost/*:without_coroutine2": False,
@@ -130,13 +130,13 @@ class Xrpl(ConanFile):
self.options["boost"].without_cobalt = True
def requirements(self):
self.requires("boost/1.91.0", force=True, transitive_headers=True)
self.requires("boost/1.90.0", force=True, transitive_headers=True)
self.requires("date/3.0.4", transitive_headers=True)
self.requires("lz4/1.10.0", force=True)
self.requires("protobuf/6.33.5", force=True)
self.requires("sqlite3/3.53.0", force=True)
self.requires("sqlite3/3.51.0", force=True)
if self.options.jemalloc:
self.requires("jemalloc/5.3.1")
self.requires("jemalloc/5.3.0")
if self.options.rocksdb:
self.requires("rocksdb/10.5.1")
self.requires("xxhash/0.8.3", transitive_headers=True)

View File

@@ -63,7 +63,6 @@ words:
- Bougalis
- Britto
- Btrfs
- Buildx
- canonicality
- changespq
- checkme
@@ -72,7 +71,6 @@ words:
- citardauq
- clawback
- clawbacks
- cmaketoolchain
- coeffs
- coldwallet
- compr
@@ -99,15 +97,12 @@ words:
- desync
- desynced
- determ
- disablerepo
- distro
- doxyfile
- dxrpl
- enabled
- enablerepo
- endmacro
- exceptioned
- EXPECT_STREQ
- Falco
- fcontext
- finalizers
@@ -119,7 +114,6 @@ words:
- gcovr
- ghead
- Gnutella
- godexsoft
- gpgcheck
- gpgkey
- hotwallet
@@ -157,7 +151,6 @@ words:
- lseq
- lsmf
- ltype
- mathbunnyru
- mcmodel
- MEMORYSTATUSEX
- MPTAMM
@@ -165,7 +158,6 @@ words:
- Merkle
- Metafuncton
- misprediction
- missingok
- mptbalance
- MPTDEX
- mptflags
@@ -197,9 +189,7 @@ words:
- NOLINT
- NOLINTNEXTLINE
- nonxrp
- noreplace
- noripple
- notifempty
- nudb
- nullptr
- nunl
@@ -219,7 +209,6 @@ words:
- preauthorize
- preauthorizes
- preclaim
- preun
- protobuf
- protos
- ptrs
@@ -254,14 +243,12 @@ words:
- sfields
- shamap
- shamapitem
- shlibs
- sidechain
- SIGGOOD
- sle
- sles
- soci
- socidb
- SRPMS
- sslws
- statsd
- STATSDCOLLECTOR
@@ -289,8 +276,8 @@ words:
- txn
- txns
- txs
- ubsan
- UBSAN
- ubsan
- umant
- unacquired
- unambiguity
@@ -327,6 +314,7 @@ words:
- xbridge
- xchain
- ximinez
- EXPECT_STREQ
- XMACRO
- xrpkuwait
- xrpl
@@ -334,4 +322,3 @@ words:
- xrplf
- xxhash
- xxhasher
- CGNAT

View File

@@ -1,66 +0,0 @@
ARG BASE_IMAGE=nixos/nix:latest
# Nix builder
FROM nixos/nix:latest AS builder-source
RUN mkdir -p ~/.config/nix && \
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
# Copy our source and setup our working dir.
COPY nix/ci-env.nix /tmp/build/nix/ci-env.nix
COPY nix/packages.nix /tmp/build/nix/packages.nix
COPY nix/utils.nix /tmp/build/nix/utils.nix
COPY flake.nix /tmp/build/
COPY flake.lock /tmp/build/
WORKDIR /tmp/build
FROM builder-source AS builder
# Build our Nix CI environment (all build tools in a single store path)
RUN nix \
--option filter-syscalls false \
build
# Copy the Nix store closure into a directory. The Nix store closure is the
# entire set of Nix store values that we need for our build.
RUN mkdir /tmp/nix-store-closure && \
cp -R $(nix-store -qR result/) /tmp/nix-store-closure
# Final image
FROM ${BASE_IMAGE}
# bash is not located at /bin/bash in nixos/nix, so we need to create a symlink to it.
RUN if [ -d /nix ]; then \
ln -s /root/.nix-profile/bin/bash /bin/bash; \
fi
# Use Bash as the default shell for RUN commands, using the options
# `set -o errexit -o pipefail`, and as the entrypoint.
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
ENTRYPOINT ["/bin/bash"]
# Copy /nix/store and the env symlink tree
COPY --from=builder /tmp/nix-store-closure /nix/store
COPY --from=builder /tmp/build/result /nix/ci-env
ENV PATH="/nix/ci-env/bin:$PATH"
RUN <<EOF
ccache --version
clang-format --version
cmake --version
conan --version
g++ --version
gcc --version
gcovr --version
git --version
make --version
mold --version
ninja --version
perl --version
pkg-config --version
pre-commit --version
python3 --version
run-clang-tidy --help
vim --version
EOF

View File

@@ -1,17 +1,15 @@
# Sanitizer Configuration for Xrpld
This document explains how to properly configure and run sanitizers (`AddressSanitizer`, `UndefinedBehaviorSanitizer`, `ThreadSanitizer`) with the xrpld project.
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.
- [Sanitizer Configuration for Xrpld](#sanitizer-configuration-for-xrpld)
- [Building with Sanitizers](#building-with-sanitizers)
- [Summary](#summary)
- [Build steps:](#build-steps)
- [Install dependencies](#install-dependencies)
- [Call CMake](#call-cmake)
- [Build](#build)
- [Running Tests with Sanitizers](#running-tests-with-sanitizers)
- [AddressSanitizer (ASAN)](#addresssanitizer-asan)
- [ThreadSanitizer (TSan)](#threadsanitizer-tsan)
@@ -35,13 +33,9 @@ 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.
2. Set the `SANITIZERS` environment variable before calling conan install and cmake. Only set it once. Make sure both conan and cmake read the same values.
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.
3. Optionally 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.
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).
---
@@ -57,13 +51,36 @@ cd .build
#### Install dependencies
The `SANITIZERS` environment variable is used during `conan install` command.
The `SANITIZERS` environment variable is used by both Conan and CMake.
```bash
SANITIZERS=address,undefinedbehavior conan install .. --output-folder . --build missing --settings build_type=Debug --profile:all sanitizers
export SANITIZERS=address,undefinedbehavior
# Standard build (without instrumenting dependencies)
conan install .. --output-folder . --build missing --settings build_type=Debug
# Or with sanitizer-instrumented dependencies (takes longer but fewer false positives)
conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug
```
Proceed with the rest of the build instructions as mentioned in [BUILD.md](../../BUILD.md).
[!CAUTION]
Do not mix Address and Thread sanitizers - they are incompatible.
Since you already set the `SANITIZERS` environment variable when running Conan, same values will be read for the next part.
#### Call CMake
```bash
cmake .. -G Ninja \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Debug \
-Dtests=ON -Dxrpld=ON
```
#### Build
```bash
cmake --build . --parallel 4
```
## Running Tests with Sanitizers

26
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1777954456,
"narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=",
"lastModified": 1769461804,
"narHash": "sha256-6h5sROT/3CTHvzPy9koKBmoCa2eJKh4fzQK8eYFEgl8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1",
"rev": "b579d443b37c9c5373044201ea77604e37e748c8",
"type": "github"
},
"original": {
@@ -15,27 +15,9 @@
"type": "indirect"
}
},
"nixpkgs-glibc231": {
"flake": false,
"locked": {
"lastModified": 1593520194,
"narHash": "sha256-+TZW+2I7kLL9JglPNOagm1ywjf9ua0JYGoptq/dzVn0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9cd98386a38891d1074fc18036b842dc4416f562",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9cd98386a38891d1074fc18036b842dc4416f562",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"nixpkgs-glibc231": "nixpkgs-glibc231"
"nixpkgs": "nixpkgs"
}
}
},

View File

@@ -2,24 +2,15 @@
description = "Nix related things for xrpld";
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
# nixpkgs snapshot (2020-06-30) that shipped glibc 2.31 as the primary
# version — matches the system libc on Ubuntu 20.04 LTS. Imported
# manually (flake = false) because this revision predates nixpkgs'
# own flake.nix.
nixpkgs-glibc231 = {
url = "github:NixOS/nixpkgs/9cd98386a38891d1074fc18036b842dc4416f562";
flake = false;
};
};
outputs =
{ nixpkgs, nixpkgs-glibc231, ... }:
{ nixpkgs, ... }:
let
forEachSystem = import ./nix/utils.nix { inherit nixpkgs nixpkgs-glibc231; };
forEachSystem = (import ./nix/utils.nix { inherit nixpkgs; }).forEachSystem;
in
{
devShells = forEachSystem (import ./nix/devshell.nix);
packages = forEachSystem (import ./nix/ci-env.nix);
formatter = forEachSystem ({ pkgs, ... }: pkgs.nixfmt);
};
}

View File

@@ -148,23 +148,17 @@ public:
}
[[nodiscard]] constexpr E const&
error() const&
error() const
{
return Base::error();
}
[[nodiscard]] constexpr E&
error() &
constexpr E&
error()
{
return Base::error();
}
[[nodiscard]] constexpr E&&
error() &&
{
return std::move(Base::error());
}
constexpr explicit
operator bool() const
{
@@ -221,23 +215,17 @@ public:
}
[[nodiscard]] constexpr E const&
error() const&
error() const
{
return Base::error();
}
[[nodiscard]] constexpr E&
error() &
constexpr E&
error()
{
return Base::error();
}
[[nodiscard]] constexpr E&&
error() &&
{
return std::move(Base::error());
}
constexpr explicit
operator bool() const
{

View File

@@ -406,8 +406,8 @@ private:
// pointer. The low bit must be masked to zero when converting back to a
// pointer. If the low bit is '1', this is a weak pointer.
std::uintptr_t tp_{0};
static constexpr std::uintptr_t kTagMask = 1;
static constexpr std::uintptr_t kPtrMask = ~kTagMask;
static constexpr std::uintptr_t kTAG_MASK = 1;
static constexpr std::uintptr_t kPTR_MASK = ~kTAG_MASK;
private:
/** Return the raw pointer held by this object.

View File

@@ -567,14 +567,14 @@ template <class T>
bool
SharedWeakUnion<T>::isStrong() const
{
return (tp_ & kTagMask) == 0u;
return (tp_ & kTAG_MASK) == 0u;
}
template <class T>
bool
SharedWeakUnion<T>::isWeak() const
{
return (tp_ & kTagMask) != 0u;
return (tp_ & kTAG_MASK) != 0u;
}
template <class T>
@@ -641,7 +641,7 @@ template <class T>
T*
SharedWeakUnion<T>::unsafeGetRawPtr() const
{
return reinterpret_cast<T*>(tp_ & kPtrMask);
return reinterpret_cast<T*>(tp_ & kPTR_MASK);
}
template <class T>
@@ -650,7 +650,7 @@ SharedWeakUnion<T>::unsafeSetRawPtr(T* p, RefStrength rs)
{
tp_ = reinterpret_cast<std::uintptr_t>(p);
if (tp_ && rs == RefStrength::Weak)
tp_ |= kTagMask;
tp_ |= kTAG_MASK;
}
template <class T>

View File

@@ -98,11 +98,11 @@ private:
// enough for strong pointers and 14 bit counts are enough for weak
// pointers. Use type aliases to make it easy to switch types.
using CountType = std::uint16_t;
static constexpr size_t kStrongCountNumBits = sizeof(CountType) * 8;
static constexpr size_t kWeakCountNumBits = kStrongCountNumBits - 2;
static constexpr size_t kSTRONG_COUNT_NUM_BITS = sizeof(CountType) * 8;
static constexpr size_t kWEAK_COUNT_NUM_BITS = kSTRONG_COUNT_NUM_BITS - 2;
using FieldType = std::uint32_t;
static constexpr size_t kFieldTypeBits = sizeof(FieldType) * 8;
static constexpr FieldType kOne = 1;
static constexpr size_t kFIELD_TYPE_BITS = sizeof(FieldType) * 8;
static constexpr FieldType kONE = 1;
/** `refCounts` consists of four fields that are treated atomically:
@@ -137,21 +137,21 @@ private:
*/
mutable std::atomic<FieldType> refCounts_{kStrongDelta};
mutable std::atomic<FieldType> refCounts_{kSTRONG_DELTA};
/** Amount to change the strong count when adding or releasing a reference
Note: The strong count is stored in the low `StrongCountNumBits` bits
of refCounts
*/
static constexpr FieldType kStrongDelta = 1;
static constexpr FieldType kSTRONG_DELTA = 1;
/** Amount to change the weak count when adding or releasing a reference
Note: The weak count is stored in the high `WeakCountNumBits` bits of
refCounts
*/
static constexpr FieldType kWeakDelta = (kOne << kStrongCountNumBits);
static constexpr FieldType kWEAK_DELTA = (kONE << kSTRONG_COUNT_NUM_BITS);
/** Flag that is set when the partialDestroy function has started running
(or is about to start running).
@@ -159,33 +159,34 @@ private:
See description of the `refCounts` field for a fuller description of
this field.
*/
static constexpr FieldType kPartialDestroyStartedMask = (kOne << (kFieldTypeBits - 1));
static constexpr FieldType kPARTIAL_DESTROY_STARTED_MASK = (kONE << (kFIELD_TYPE_BITS - 1));
/** Flag that is set when the partialDestroy function has finished running
See description of the `refCounts` field for a fuller description of
this field.
*/
static constexpr FieldType kPartialDestroyFinishedMask = (kOne << (kFieldTypeBits - 2));
static constexpr FieldType kPARTIAL_DESTROY_FINISHED_MASK = (kONE << (kFIELD_TYPE_BITS - 2));
/** Mask that will zero out all the `count` bits and leave the tag bits
unchanged.
*/
static constexpr FieldType kTagMask = kPartialDestroyStartedMask | kPartialDestroyFinishedMask;
static constexpr FieldType kTAG_MASK =
kPARTIAL_DESTROY_STARTED_MASK | kPARTIAL_DESTROY_FINISHED_MASK;
/** Mask that will zero out the `tag` bits and leave the count bits
unchanged.
*/
static constexpr FieldType kValueMask = ~kTagMask;
static constexpr FieldType kVALUE_MASK = ~kTAG_MASK;
/** Mask that will zero out everything except the strong count.
*/
static constexpr FieldType kStrongMask = ((kOne << kStrongCountNumBits) - 1) & kValueMask;
static constexpr FieldType kSTRONG_MASK = ((kONE << kSTRONG_COUNT_NUM_BITS) - 1) & kVALUE_MASK;
/** Mask that will zero out everything except the weak count.
*/
static constexpr FieldType kWeakMask =
(((kOne << kWeakCountNumBits) - 1) << kStrongCountNumBits) & kValueMask;
static constexpr FieldType kWEAK_MASK =
(((kONE << kWEAK_COUNT_NUM_BITS) - 1) << kSTRONG_COUNT_NUM_BITS) & kVALUE_MASK;
/** Unpack the count and tag fields from the packed atomic integer form. */
struct RefCountPair
@@ -210,29 +211,29 @@ private:
[[nodiscard]] FieldType
combinedValue() const noexcept;
static constexpr CountType kMaxStrongValue =
static_cast<CountType>((kOne << kStrongCountNumBits) - 1);
static constexpr CountType kMaxWeakValue =
static_cast<CountType>((kOne << kWeakCountNumBits) - 1);
static constexpr CountType kMAX_STRONG_VALUE =
static_cast<CountType>((kONE << kSTRONG_COUNT_NUM_BITS) - 1);
static constexpr CountType kMAX_WEAK_VALUE =
static_cast<CountType>((kONE << kWEAK_COUNT_NUM_BITS) - 1);
/** Put an extra margin to detect when running up against limits.
This is only used in debug code, and is useful if we reduce the
number of bits in the strong and weak counts (to 16 and 14 bits).
*/
static constexpr CountType kCheckStrongMaxValue = kMaxStrongValue - 32;
static constexpr CountType kCheckWeakMaxValue = kMaxWeakValue - 32;
static constexpr CountType kCHECK_STRONG_MAX_VALUE = kMAX_STRONG_VALUE - 32;
static constexpr CountType kCHECK_WEAK_MAX_VALUE = kMAX_WEAK_VALUE - 32;
};
};
inline void
IntrusiveRefCounts::addStrongRef() const noexcept
{
refCounts_.fetch_add(kStrongDelta, std::memory_order_acq_rel);
refCounts_.fetch_add(kSTRONG_DELTA, std::memory_order_acq_rel);
}
inline void
IntrusiveRefCounts::addWeakRef() const noexcept
{
refCounts_.fetch_add(kWeakDelta, std::memory_order_acq_rel);
refCounts_.fetch_add(kWEAK_DELTA, std::memory_order_acq_rel);
}
inline ReleaseStrongRefAction
@@ -251,10 +252,10 @@ IntrusiveRefCounts::releaseStrongRef() const
{
RefCountPair const prevVal{prevIntVal};
XRPL_ASSERT(
(prevVal.strong >= kStrongDelta),
(prevVal.strong >= kSTRONG_DELTA),
"xrpl::IntrusiveRefCounts::releaseStrongRef : previous ref "
"higher than new");
auto nextIntVal = prevIntVal - kStrongDelta;
auto nextIntVal = prevIntVal - kSTRONG_DELTA;
ReleaseStrongRefAction action = NoOp;
if (prevVal.strong == 1)
{
@@ -264,7 +265,7 @@ IntrusiveRefCounts::releaseStrongRef() const
}
else
{
nextIntVal |= kPartialDestroyStartedMask;
nextIntVal |= kPARTIAL_DESTROY_STARTED_MASK;
action = PartialDestroy;
}
}
@@ -275,7 +276,7 @@ IntrusiveRefCounts::releaseStrongRef() const
// count to zero can start a partial destroy, and that can't happen
// twice.
XRPL_ASSERT(
(action == NoOp) || !(prevIntVal & kPartialDestroyStartedMask),
(action == NoOp) || !(prevIntVal & kPARTIAL_DESTROY_STARTED_MASK),
"xrpl::IntrusiveRefCounts::releaseStrongRef : not in partial "
"destroy");
return action;
@@ -288,8 +289,8 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
{
using enum ReleaseStrongRefAction;
static_assert(kWeakDelta > kStrongDelta);
static constexpr auto kDelta = kWeakDelta - kStrongDelta;
static_assert(kWEAK_DELTA > kSTRONG_DELTA);
auto constexpr kDELTA = kWEAK_DELTA - kSTRONG_DELTA;
auto prevIntVal = refCounts_.load(std::memory_order_acquire);
// This loop will almost always run once. The loop is needed to atomically
// change the counts and flags (the count could be atomically changed, but
@@ -311,7 +312,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
"xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not in "
"partial destroy");
auto nextIntVal = prevIntVal + kDelta;
auto nextIntVal = prevIntVal + kDELTA;
ReleaseStrongRefAction action = NoOp;
if (prevVal.strong == 1)
{
@@ -321,14 +322,14 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
}
else
{
nextIntVal |= kPartialDestroyStartedMask;
nextIntVal |= kPARTIAL_DESTROY_STARTED_MASK;
action = PartialDestroy;
}
}
if (refCounts_.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
{
XRPL_ASSERT(
(!(prevIntVal & kPartialDestroyStartedMask)),
(!(prevIntVal & kPARTIAL_DESTROY_STARTED_MASK)),
"xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not "
"started partial destroy");
return action;
@@ -339,7 +340,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
inline ReleaseWeakRefAction
IntrusiveRefCounts::releaseWeakRef() const
{
auto prevIntVal = refCounts_.fetch_sub(kWeakDelta, std::memory_order_acq_rel);
auto prevIntVal = refCounts_.fetch_sub(kWEAK_DELTA, std::memory_order_acq_rel);
RefCountPair prev = prevIntVal;
if (prev.weak == 1 && prev.strong == 0)
{
@@ -356,7 +357,7 @@ IntrusiveRefCounts::releaseWeakRef() const
{
// partial destroy MUST finish before running a full destroy (when
// using weak pointers)
refCounts_.wait(prevIntVal - kWeakDelta, std::memory_order_acquire);
refCounts_.wait(prevIntVal - kWEAK_DELTA, std::memory_order_acquire);
}
return ReleaseWeakRefAction::Destroy;
}
@@ -375,7 +376,7 @@ IntrusiveRefCounts::checkoutStrongRefFromWeak() const noexcept
if (prev.strong == 0u)
return false;
desiredValue = curValue + kStrongDelta;
desiredValue = curValue + kSTRONG_DELTA;
}
return true;
}
@@ -399,22 +400,23 @@ inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
#ifndef NDEBUG
auto v = refCounts_.load(std::memory_order_acquire);
XRPL_ASSERT(
(!(v & kValueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
auto t = v & kTagMask;
XRPL_ASSERT((!t || t == kTagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
(!(v & kVALUE_MASK)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
auto t = v & kTAG_MASK;
XRPL_ASSERT(
(!t || t == kTAG_MASK), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
#endif
}
//------------------------------------------------------------------------------
inline IntrusiveRefCounts::RefCountPair::RefCountPair(IntrusiveRefCounts::FieldType v) noexcept
: strong{static_cast<CountType>(v & kStrongMask)}
, weak{static_cast<CountType>((v & kWeakMask) >> kStrongCountNumBits)}
, partialDestroyStartedBit{v & kPartialDestroyStartedMask}
, partialDestroyFinishedBit{v & kPartialDestroyFinishedMask}
: strong{static_cast<CountType>(v & kSTRONG_MASK)}
, weak{static_cast<CountType>((v & kWEAK_MASK) >> kSTRONG_COUNT_NUM_BITS)}
, partialDestroyStartedBit{v & kPARTIAL_DESTROY_STARTED_MASK}
, partialDestroyFinishedBit{v & kPARTIAL_DESTROY_FINISHED_MASK}
{
XRPL_ASSERT(
(strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
(strong < kCHECK_STRONG_MAX_VALUE && weak < kCHECK_WEAK_MAX_VALUE),
"xrpl::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside "
"range");
}
@@ -425,7 +427,7 @@ inline IntrusiveRefCounts::RefCountPair::RefCountPair(
: strong{s}, weak{w}
{
XRPL_ASSERT(
(strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
(strong < kCHECK_STRONG_MAX_VALUE && weak < kCHECK_WEAK_MAX_VALUE),
"xrpl::IntrusiveRefCounts::RefCountPair(CountType, CountType) : "
"inputs inside range");
}
@@ -434,11 +436,11 @@ inline IntrusiveRefCounts::FieldType
IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept
{
XRPL_ASSERT(
(strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
(strong < kCHECK_STRONG_MAX_VALUE && weak < kCHECK_WEAK_MAX_VALUE),
"xrpl::IntrusiveRefCounts::RefCountPair::combinedValue : inputs "
"inside range");
return (static_cast<IntrusiveRefCounts::FieldType>(weak)
<< IntrusiveRefCounts::kStrongCountNumBits) |
<< IntrusiveRefCounts::kSTRONG_COUNT_NUM_BITS) |
static_cast<IntrusiveRefCounts::FieldType>(strong) | partialDestroyStartedBit |
partialDestroyFinishedBit;
}
@@ -449,7 +451,7 @@ partialDestructorFinished(T** o)
{
T& self = **o;
IntrusiveRefCounts::RefCountPair const p =
self.refCounts_.fetch_or(IntrusiveRefCounts::kPartialDestroyFinishedMask);
self.refCounts_.fetch_or(IntrusiveRefCounts::kPARTIAL_DESTROY_FINISHED_MASK);
XRPL_ASSERT(
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit && !p.strong),
"xrpl::partialDestructorFinished : not a weak ref");

View File

@@ -55,8 +55,8 @@ template <class = void>
boost::thread_specific_ptr<detail::LocalValues>&
getLocalValues()
{
static boost::thread_specific_ptr<detail::LocalValues> kTsp(&detail::LocalValues::cleanup);
return kTsp;
static boost::thread_specific_ptr<detail::LocalValues> kTSP(&detail::LocalValues::cleanup);
return kTSP;
}
} // namespace detail

View File

@@ -10,11 +10,24 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <utility>
namespace xrpl {
// DEPRECATED use beast::severities::Severity instead
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum LogSeverity {
LSInvalid = -1, // used to indicate an invalid severity
LSTrace = 0, // Very low-level progress information, details inside
// an operation
LSDebug = 1, // Function-level progress information, operations
LSInfo = 2, // Server-level progress information, major operations
LSWarning = 3, // Conditions that warrant human attention, may indicate
// a problem
LSError = 4, // A condition that indicates a problem
LSFatal = 5 // A severe condition that indicates a server problem
};
/** Manages partitions for logging. */
class Logs
{
@@ -26,17 +39,17 @@ private:
std::string partition_;
public:
Sink(std::string partition, beast::Severity thresh, Logs& logs);
Sink(std::string partition, beast::severities::Severity thresh, Logs& logs);
Sink(Sink const&) = delete;
Sink&
operator=(Sink const&) = delete;
void
write(beast::Severity level, std::string const& text) override;
write(beast::severities::Severity level, std::string const& text) override;
void
writeAlways(beast::Severity level, std::string const& text) override;
writeAlways(beast::severities::Severity level, std::string const& text) override;
};
/** Manages a system file containing logged output.
@@ -123,12 +136,12 @@ private:
std::mutex mutable mutex_;
std::map<std::string, std::unique_ptr<beast::Journal::Sink>, boost::beast::iless> sinks_;
beast::Severity thresh_;
beast::severities::Severity thresh_;
File file_;
bool silent_ = false;
public:
Logs(beast::Severity level);
Logs(beast::severities::Severity level);
Logs(Logs const&) = delete;
Logs&
@@ -148,18 +161,18 @@ public:
beast::Journal
journal(std::string const& name);
beast::Severity
beast::severities::Severity
threshold() const;
void
threshold(beast::Severity thresh);
threshold(beast::severities::Severity thresh);
std::vector<std::pair<std::string, std::string>>
partitionSeverities() const;
void
write(
beast::Severity level,
beast::severities::Severity level,
std::string const& partition,
std::string const& text,
bool console);
@@ -179,25 +192,36 @@ public:
}
virtual std::unique_ptr<beast::Journal::Sink>
makeSink(std::string const& partition, beast::Severity startingLevel);
makeSink(std::string const& partition, beast::severities::Severity startingLevel);
public:
static std::string
toString(beast::Severity s);
static LogSeverity
fromSeverity(beast::severities::Severity level);
static std::optional<beast::Severity>
static beast::severities::Severity
toSeverity(LogSeverity level);
static std::string
toString(LogSeverity s);
static LogSeverity
fromString(std::string const& s);
private:
// Maximum line length for log messages.
// If the message exceeds this length it will be truncated with ellipses.
static constexpr auto kMaximumMessageCharacters = 12 * 1024;
// Need to be named before converting
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum {
// Maximum line length for log messages.
// If the message exceeds this length it will be truncated with
// ellipses.
MaximumMessageCharacters = 12 * 1024
};
static void
format(
std::string& output,
std::string const& message,
beast::Severity severity,
beast::severities::Severity severity,
std::string const& partition);
};

View File

@@ -7,9 +7,7 @@
#include <limits>
#include <optional>
#include <ostream>
#include <set>
#include <string>
#include <unordered_map>
namespace xrpl {
@@ -46,11 +44,11 @@ isPowerOfTen(T value)
* * min is a power of 10, and
* * max = min * 10 - 1.
*
* The MantissaScale enum indicates properties of the range: size, and some behavioral
* options. This intentionally restricts the number of unique MantissaRanges that can
* be instantiated: one for each scale.
* The mantissa_scale enum indicates whether the range is "small" or "large".
* This intentionally restricts the number of MantissaRanges that can be
* instantiated to two: one for each scale.
*
* The "Small" scale is based on the behavior of STAmount for IOUs. It has a min
* The "small" scale is based on the behavior of STAmount for IOUs. It has a min
* value of 10^15, and a max value of 10^16-1. This was sufficient for
* uses before Lending Protocol was implemented, mostly related to AMM.
*
@@ -61,54 +59,29 @@ isPowerOfTen(T value)
* STNumber field type, and for internal calculations. That necessitated the
* "large" scale.
*
* The "Large" scales are intended to represent all values that can be represented
* The "large" scale is intended to represent all values that can be represented
* by an STAmount - IOUs, XRP, and MPTs. It has a min value of 10^18, and a max
* value of 10^19-1. "LargeLegacy" is like "Large", but preserves
* a rounding error when a computation results in a mantissa of
* Number::kMAX_REP that needs to be rounded up, but rounds down
* instead. It will maintain consistent behavior until the fixCleanup3_2_0
* amendment is enabled.
* value of 10^19-1.
*
* Note that if the mentioned amendments are eventually retired, this class
* should be left in place, but the "Small" scale option should be removed. This
* should be left in place, but the "small" scale option should be removed. This
* will allow for future expansion beyond 64-bits if it is ever needed.
*/
struct MantissaRange final
struct MantissaRange
{
using rep = std::uint64_t;
enum class MantissaScale {
Small,
// LargeLegacy can be removed when fixCleanup3_2_0 is retired
LargeLegacy,
Large,
};
// This entire enum can be removed when fixCleanup3_2_0 is retired
enum class CuspRoundingFix : bool {
Disabled = false,
Enabled = true,
};
enum class MantissaScale { Small, Large };
explicit constexpr MantissaRange(MantissaScale scale)
: min(getMin(scale))
, cuspRoundingFixEnabled(isCuspFixEnabled(scale))
, log(logTen(min).value_or(-1))
, scale(scale)
: min(getMin(scale)), log(logTen(min).value_or(-1)), scale(scale)
{
}
rep min;
rep max{(min * 10) - 1};
CuspRoundingFix cuspRoundingFixEnabled;
int log;
MantissaScale scale;
static MantissaRange const&
getMantissaRange(MantissaScale scale);
static std::set<MantissaScale> const&
getAllScales();
private:
static constexpr rep
getMin(MantissaScale scale)
@@ -117,35 +90,15 @@ private:
{
case MantissaScale::Small:
return 1'000'000'000'000'000ULL;
case MantissaScale::LargeLegacy:
case MantissaScale::Large:
return 1'000'000'000'000'000'000ULL;
default:
// If called in a constexpr context, this throw assures that the build fails if an
// Since this can never be called outside a non-constexpr
// context, this throw assures that the build fails if an
// invalid scale is used.
throw std::runtime_error("Unknown mantissa scale");
}
}
static constexpr CuspRoundingFix
isCuspFixEnabled(MantissaScale scale)
{
switch (scale)
{
case MantissaScale::Small:
case MantissaScale::LargeLegacy:
return CuspRoundingFix::Disabled;
case MantissaScale::Large:
return CuspRoundingFix::Enabled;
default:
// If called in a constexpr context, this throw assures that the build fails if an
// invalid scale is used.
throw std::runtime_error("Unknown mantissa scale");
}
}
static std::unordered_map<MantissaScale, MantissaRange> const&
getRanges();
};
// Like std::integral, but only 64-bit integral types.
@@ -250,7 +203,7 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
* amendments are enabled to determine which result to expect.
*
*/
class Number final
class Number
{
using rep = std::int64_t;
using internalrep = MantissaRange::rep;
@@ -261,12 +214,12 @@ class Number final
public:
// The range for the exponent when normalized
static constexpr int kMinExponent = -32768;
static constexpr int kMaxExponent = 32768;
constexpr static int kMIN_EXPONENT = -32768;
constexpr static int kMAX_EXPONENT = 32768;
static constexpr internalrep kMaxRep = std::numeric_limits<rep>::max();
static_assert(kMaxRep == 9'223'372'036'854'775'807);
static_assert(-kMaxRep == std::numeric_limits<rep>::min() + 1);
constexpr static internalrep kMAX_REP = std::numeric_limits<rep>::max();
static_assert(kMAX_REP == 9'223'372'036'854'775'807);
static_assert(-kMAX_REP == std::numeric_limits<rep>::min() + 1);
// May need to make unchecked private
struct Unchecked
@@ -456,49 +409,69 @@ public:
static internalrep
minMantissa()
{
return kRange.get().min;
return kRANGE.get().min;
}
static internalrep
maxMantissa()
{
return kRange.get().max;
return kRANGE.get().max;
}
static int
mantissaLog()
{
return kRange.get().log;
return kRANGE.get().log;
}
/// oneSmall is needed because the ranges are private
constexpr static Number
oneSmall();
/// oneLarge is needed because the ranges are private
constexpr static Number
oneLarge();
// And one is needed because it needs to choose between oneSmall and
// oneLarge based on the current range
static Number
one();
template <
auto MinMantissa,
auto MaxMantissa,
Integral64 T = std::decay_t<decltype(MinMantissa)>,
Integral64 TMax = std::decay_t<decltype(MaxMantissa)>>
template <Integral64 T>
[[nodiscard]]
std::pair<T, int>
normalizeToRange() const;
normalizeToRange(T minMantissa, T maxMantissa) const;
private:
static thread_local RoundingMode mode;
// The available ranges for mantissa
constexpr static MantissaRange kSMALL_RANGE{MantissaRange::MantissaScale::Small};
static_assert(isPowerOfTen(kSMALL_RANGE.min));
static_assert(kSMALL_RANGE.min == 1'000'000'000'000'000LL);
static_assert(kSMALL_RANGE.max == 9'999'999'999'999'999LL);
static_assert(kSMALL_RANGE.log == 15);
static_assert(kSMALL_RANGE.min < kMAX_REP);
static_assert(kSMALL_RANGE.max < kMAX_REP);
constexpr static MantissaRange kLARGE_RANGE{MantissaRange::MantissaScale::Large};
static_assert(isPowerOfTen(kLARGE_RANGE.min));
static_assert(kLARGE_RANGE.min == 1'000'000'000'000'000'000ULL);
static_assert(kLARGE_RANGE.max == internalrep(9'999'999'999'999'999'999ULL));
static_assert(kLARGE_RANGE.log == 18);
static_assert(kLARGE_RANGE.min < kMAX_REP);
static_assert(kLARGE_RANGE.max > kMAX_REP);
// The range for the mantissa when normalized.
// Use reference_wrapper to avoid making copies, and prevent accidentally
// changing the values inside the range.
static thread_local std::reference_wrapper<MantissaRange const> kRange;
static thread_local std::reference_wrapper<MantissaRange const> kRANGE;
void
normalize(MantissaRange const& range);
normalize();
/** Normalize Number components to an arbitrary range.
*
* min/maxMantissa are parameters because this function is used by both
* normalize(), which reads from kRange, and by normalizeToRange,
* normalize(), which reads from kRANGE, and by normalizeToRange,
* which is public and can accept an arbitrary range from the caller.
*/
template <class T>
@@ -508,8 +481,7 @@ private:
T& mantissa,
int& exponent,
internalrep const& minMantissa,
internalrep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled);
internalrep const& maxMantissa);
template <class T>
friend void
@@ -518,8 +490,7 @@ private:
T& mantissa,
int& exponent,
MantissaRange::rep const& minMantissa,
MantissaRange::rep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled);
MantissaRange::rep const& maxMantissa);
[[nodiscard]] bool
isnormal() const noexcept;
@@ -550,12 +521,12 @@ constexpr Number::Number(internalrep mantissa, int exponent, Unchecked) noexcept
{
}
static constexpr Number kNumZero{};
constexpr static Number kNUM_ZERO{};
inline Number::Number(bool negative, internalrep mantissa, int exponent, Normalized)
: Number(negative, mantissa, exponent, Unchecked{})
{
normalize(kRange);
normalize();
}
inline Number::Number(internalrep mantissa, int exponent, Normalized)
@@ -581,10 +552,10 @@ constexpr Number::rep
Number::mantissa() const noexcept
{
auto m = mantissa_;
if (m > kMaxRep)
if (m > kMAX_REP)
{
XRPL_ASSERT_PARTS(
!isnormal() || (m % 10 == 0 && m / 10 <= kMaxRep),
!isnormal() || (m % 10 == 0 && m / 10 <= kMAX_REP),
"xrpl::Number::mantissa",
"large normalized mantissa has no remainder");
m /= 10;
@@ -602,10 +573,10 @@ constexpr int
Number::exponent() const noexcept
{
auto e = exponent_;
if (mantissa_ > kMaxRep)
if (mantissa_ > kMAX_REP)
{
XRPL_ASSERT_PARTS(
!isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= kMaxRep),
!isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= kMAX_REP),
"xrpl::Number::exponent",
"large normalized mantissa has no remainder");
++e;
@@ -700,44 +671,35 @@ operator/(Number const& x, Number const& y)
inline Number
Number::min() noexcept
{
return Number{false, kRange.get().min, kMinExponent, Unchecked{}};
return Number{false, kRANGE.get().min, kMIN_EXPONENT, Unchecked{}};
}
inline Number
Number::max() noexcept
{
return Number{false, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
return Number{false, std::min(kRANGE.get().max, kMAX_REP), kMAX_EXPONENT, Unchecked{}};
}
inline Number
Number::lowest() noexcept
{
return Number{true, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
return Number{true, std::min(kRANGE.get().max, kMAX_REP), kMAX_EXPONENT, Unchecked{}};
}
inline bool
Number::isnormal() const noexcept
{
MantissaRange const& range = kRange;
MantissaRange const& range = kRANGE;
auto const absM = mantissa_;
return *this == Number{} ||
(range.min <= absM && absM <= range.max && (absM <= kMaxRep || absM % 10 == 0) &&
kMinExponent <= exponent_ && exponent_ <= kMaxExponent);
(range.min <= absM && absM <= range.max && (absM <= kMAX_REP || absM % 10 == 0) &&
kMIN_EXPONENT <= exponent_ && exponent_ <= kMAX_EXPONENT);
}
template <auto MinMantissa, auto MaxMantissa, Integral64 T, Integral64 TMax>
template <Integral64 T>
std::pair<T, int>
Number::normalizeToRange() const
Number::normalizeToRange(T minMantissa, T maxMantissa) const
{
static_assert(std::is_same_v<T, std::uint64_t> || std::is_same_v<T, std::int64_t>);
static_assert(std::is_same_v<T, TMax>);
auto constexpr kMIN = static_cast<T>(MinMantissa);
auto constexpr kMAX = static_cast<T>(MaxMantissa);
static_assert(kMIN > 0);
static_assert(kMIN % 10 == 0);
static_assert(kMAX % 10 == 9);
static_assert((kMAX + 1) / 10 == kMIN);
bool negative = negative_;
internalrep mantissa = mantissa_;
int exponent = exponent_;
@@ -749,10 +711,7 @@ Number::normalizeToRange() const
"xrpl::Number::normalizeToRange",
"Number is non-negative for unsigned range.");
}
// Don't need to worry about the cuspRounding fix because rounding up will never take the
// mantissa over maxMantissa with a ones digit value other than 0. 0 can safely be truncated.
Number::normalize(
negative, mantissa, exponent, kMIN, kMAX, MantissaRange::CuspRoundingFix::Disabled);
Number::normalize(negative, mantissa, exponent, minMantissa, maxMantissa);
auto const sign = negative ? -1 : 1;
return std::make_pair(static_cast<T>(sign * mantissa), exponent);
@@ -804,8 +763,6 @@ to_string(MantissaRange::MantissaScale const& scale)
{
case MantissaRange::MantissaScale::Small:
return "small";
case MantissaRange::MantissaScale::LargeLegacy:
return "largeLegacy";
case MantissaRange::MantissaScale::Large:
return "large";
default:

View File

@@ -21,12 +21,12 @@ public:
}
[[nodiscard]] uint256 const&
asUInt256() const
asUint256() const
{
return hash_;
}
uint256&
asUInt256()
asUint256()
{
return hash_;
}
@@ -93,7 +93,7 @@ template <>
inline std::size_t
extract(SHAMapHash const& key)
{
return *reinterpret_cast<std::size_t const*>(key.asUInt256().data());
return *reinterpret_cast<std::size_t const*>(key.asUint256().data());
}
} // namespace xrpl

View File

@@ -57,10 +57,10 @@ template <class T>
std::shared_ptr<T> const&
SharedWeakCachePointer<T>::getStrong() const
{
static std::shared_ptr<T> const kEmpty;
static std::shared_ptr<T> const kEMPTY;
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
return *p;
return kEmpty;
return kEMPTY;
}
template <class T>

View File

@@ -7,11 +7,9 @@
#include <boost/utility/string_view.hpp>
#include <array>
#include <concepts>
#include <cstdint>
#include <optional>
#include <string>
#include <type_traits>
namespace xrpl {
@@ -28,39 +26,28 @@ namespace xrpl {
std::string
sqlBlobLiteral(Blob const& blob);
namespace detail {
template <typename T>
concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> ||
std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>;
inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = []() {
std::array<std::optional<int>, 256> t{};
for (int i = 0; i < 10; ++i)
t['0' + i] = i;
for (int i = 0; i < 6; ++i)
{
t['A' + i] = 10 + i;
t['a' + i] = 10 + i;
}
return t;
}();
inline std::optional<int>
hexCharToInt(SomeChar auto hexChar)
{
return kDigitLookupTable[static_cast<uint8_t>(hexChar)];
}
} // namespace detail
template <class Iterator>
std::optional<Blob>
strUnHex(std::size_t strSize, Iterator begin, Iterator end)
{
static constexpr std::array<int, 256> const kDIGIT_LOOKUP_TABLE = []() {
std::array<int, 256> t{};
for (auto& x : t)
x = -1;
for (int i = 0; i < 10; ++i)
t['0' + i] = i;
for (int i = 0; i < 6; ++i)
{
t['A' + i] = 10 + i;
t['a' + i] = 10 + i;
}
return t;
}();
Blob out;
out.reserve((strSize + 1) / 2);
@@ -69,26 +56,27 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end)
if (strSize & 1)
{
auto const c = detail::hexCharToInt(*iter++);
if (!c.has_value())
int c = kDIGIT_LOOKUP_TABLE[*iter++];
if (c < 0)
return {};
out.push_back(static_cast<unsigned char>(*c));
out.push_back(c);
}
while (iter != end)
{
auto const cHigh = detail::hexCharToInt(*iter++);
int const cHigh = kDIGIT_LOOKUP_TABLE[*iter++];
if (!cHigh.has_value())
if (cHigh < 0)
return {};
auto const cLow = detail::hexCharToInt(*iter++);
int const cLow = kDIGIT_LOOKUP_TABLE[*iter++];
if (!cLow.has_value())
if (cLow < 0)
return {};
out.push_back(static_cast<unsigned char>((*cHigh << 4) | *cLow));
out.push_back(static_cast<unsigned char>((cHigh << 4) | cLow));
}
return {std::move(out)};
@@ -132,7 +120,7 @@ std::string
trimWhitespace(std::string str);
std::optional<std::uint64_t>
toUInt64(std::string const& s);
toUint64(std::string const& s);
/** Determines if the given string looks like a TOML-file hosting domain.

View File

@@ -0,0 +1,37 @@
#pragma once
#include <cstdint>
namespace xrpl {
namespace tracing {
void init(
char const* outputPath,
double samplingRate = 1.0,
std::uint64_t maxFileSizeMB = 500,
int maxFiles = 10);
void shutdown();
} // namespace tracing
class TraceScope
{
std::uint64_t spanId_;
std::uint64_t traceId_;
std::uint64_t parentId_;
char const* func_;
char const* file_;
int line_;
std::int64_t startUs_;
bool active_;
public:
TraceScope(char const* func, char const* file, int line) noexcept;
~TraceScope() noexcept;
TraceScope(TraceScope const&) = delete;
TraceScope& operator=(TraceScope const&) = delete;
};
} // namespace xrpl
#define TRACE_FUNC() \
xrpl::TraceScope xrpl_trace_scope_(__func__, __FILE__, __LINE__)

View File

@@ -30,8 +30,8 @@ public:
now(); // seconds since xrpld program start
private:
static std::atomic<rep> kNow;
static std::atomic<bool> kStop;
static std::atomic<rep> kNOW;
static std::atomic<bool> kSTOP;
struct UpdateThread : private std::thread
{

View File

@@ -46,11 +46,6 @@ struct IsContiguousContainer<Slice> : std::true_type
{
};
template <typename...>
struct AlwaysFalseT : std::bool_constant<false>
{
};
} // namespace detail
/** Integers of any length that is a multiple of 32-bits
@@ -67,18 +62,18 @@ struct AlwaysFalseT : std::bool_constant<false>
number of bits.
*/
template <std::size_t Bits, class Tag = void>
class BaseUInt
class BaseUint
{
static_assert((Bits % 32) == 0, "The length of a base_uint in bits must be a multiple of 32.");
static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64.");
static constexpr std::size_t kWidth = Bits / 32;
static constexpr std::size_t kWIDTH = Bits / 32;
// This is really big-endian in byte order.
// We sometimes use std::uint32_t for speed.
std::array<std::uint32_t, kWidth> data_;
std::array<std::uint32_t, kWIDTH> data_;
public:
//--------------------------------------------------------------------------
@@ -86,8 +81,8 @@ public:
// STL Container Interface
//
static constexpr std::size_t kBytes = Bits / 8;
static_assert(sizeof(data_) == kBytes, "");
static std::size_t constexpr kBYTES = Bits / 8;
static_assert(sizeof(data_) == kBYTES, "");
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
@@ -121,7 +116,7 @@ public:
iterator
end()
{
return data() + kBytes;
return data() + kBYTES;
}
[[nodiscard]] const_iterator
begin() const
@@ -131,7 +126,7 @@ public:
[[nodiscard]] const_iterator
end() const
{
return data() + kBytes;
return data() + kBYTES;
}
[[nodiscard]] const_iterator
cbegin() const
@@ -141,7 +136,7 @@ public:
[[nodiscard]] const_iterator
cend() const
{
return data() + kBytes;
return data() + kBYTES;
}
/** Value hashing function.
@@ -165,9 +160,9 @@ private:
explicit VoidHelper() = default;
};
explicit BaseUInt(void const* data, VoidHelper)
explicit BaseUint(void const* data, VoidHelper)
{
memcpy(data_.data(), data, kBytes);
memcpy(data_.data(), data, kBYTES);
}
// Helper function to initialize a base_uint from a std::string_view.
@@ -249,15 +244,15 @@ private:
}
public:
constexpr BaseUInt() : data_{}
constexpr BaseUint() : data_{}
{
}
constexpr BaseUInt(beast::Zero) : data_{}
constexpr BaseUint(beast::Zero) : data_{}
{
}
explicit BaseUInt(std::uint64_t b)
explicit BaseUint(std::uint64_t b)
{
*this = b;
}
@@ -265,7 +260,7 @@ public:
// This constructor is intended to be used at compile time since it might
// throw at runtime. Consider declaring this constructor consteval once
// we get to C++23.
explicit constexpr BaseUInt(std::string_view sv) noexcept(false)
explicit constexpr BaseUint(std::string_view sv) noexcept(false)
: data_(parseFromStringViewThrows(sv))
{
}
@@ -275,42 +270,24 @@ public:
class = std::enable_if_t<
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>>>
explicit BaseUInt(Container const& c)
explicit BaseUint(Container const& c)
{
// Use AlwaysFalseT so the static_assert condition is dependent
// and only triggers when this constructor template is instantiated.
static_assert(
detail::AlwaysFalseT<Container>::value,
"This constructor is not intended to be used and will be soon removed. "
"Use base_uint::fromRaw instead.");
}
template <
class Container,
class = std::enable_if_t<
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>>>
static BaseUInt
fromRaw(Container const& c)
{
BaseUInt result;
XRPL_ASSERT(
c.size() * sizeof(typename Container::value_type) == size(),
"xrpl::BaseUInt::fromRaw(Container auto) : input size match");
std::memcpy(result.data_.data(), c.data(), size());
return result;
"xrpl::base_uint::base_uint(Container auto) : input size match");
std::memcpy(data_.data(), c.data(), size());
}
template <class Container>
std::enable_if_t<
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>,
BaseUInt&>
BaseUint&>
operator=(Container const& c)
{
XRPL_ASSERT(
c.size() * sizeof(typename Container::value_type) == size(),
"xrpl::BaseUInt::operator=(Container auto) : input size match");
"xrpl::base_uint::operator=(Container auto) : input size match");
std::memcpy(data_.data(), c.data(), size());
return *this;
}
@@ -318,14 +295,14 @@ public:
/* Construct from a raw pointer.
The buffer pointed to by `data` must be at least Bits/8 bytes.
*/
static BaseUInt
static BaseUint
fromVoid(void const* data)
{
return BaseUInt(data, VoidHelper());
return BaseUint(data, VoidHelper());
}
template <class T>
static std::optional<BaseUInt>
static std::optional<BaseUint>
fromVoidChecked(T const& from)
{
if (from.size() != size())
@@ -336,7 +313,7 @@ public:
[[nodiscard]] constexpr int
signum() const
{
for (int i = 0; i < kWidth; i++)
for (int i = 0; i < kWIDTH; i++)
{
if (data_[i] != 0)
return 1;
@@ -348,24 +325,24 @@ public:
bool
operator!() const
{
return *this == beast::kZero;
return *this == beast::kZERO;
}
constexpr BaseUInt
constexpr BaseUint
operator~() const
{
BaseUInt ret;
BaseUint ret;
for (int i = 0; i < kWidth; i++)
for (int i = 0; i < kWIDTH; i++)
ret.data_[i] = ~data_[i];
return ret;
}
BaseUInt&
BaseUint&
operator=(std::uint64_t uHost)
{
*this = beast::kZero;
*this = beast::kZERO;
// NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
union
{
@@ -375,43 +352,43 @@ public:
// NOLINTEND(cppcoreguidelines-pro-type-member-init)
// Put in least significant bits.
ul = boost::endian::native_to_big(uHost);
data_[kWidth - 2] = u[0];
data_[kWidth - 1] = u[1];
data_[kWIDTH - 2] = u[0];
data_[kWIDTH - 1] = u[1];
return *this;
}
BaseUInt&
operator^=(BaseUInt const& b)
BaseUint&
operator^=(BaseUint const& b)
{
for (int i = 0; i < kWidth; i++)
for (int i = 0; i < kWIDTH; i++)
data_[i] ^= b.data_[i];
return *this;
}
BaseUInt&
operator&=(BaseUInt const& b)
BaseUint&
operator&=(BaseUint const& b)
{
for (int i = 0; i < kWidth; i++)
for (int i = 0; i < kWIDTH; i++)
data_[i] &= b.data_[i];
return *this;
}
BaseUInt&
operator|=(BaseUInt const& b)
BaseUint&
operator|=(BaseUint const& b)
{
for (int i = 0; i < kWidth; i++)
for (int i = 0; i < kWIDTH; i++)
data_[i] |= b.data_[i];
return *this;
}
BaseUInt&
BaseUint&
operator++()
{
// prefix operator
for (int i = kWidth - 1; i >= 0; --i)
for (int i = kWIDTH - 1; i >= 0; --i)
{
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1);
if (data_[i] != 0)
@@ -421,20 +398,20 @@ public:
return *this;
}
BaseUInt
BaseUint
operator++(int)
{
// postfix operator
BaseUInt const ret = *this;
BaseUint const ret = *this;
++(*this);
return ret;
}
BaseUInt&
BaseUint&
operator--()
{
for (int i = kWidth - 1; i >= 0; --i)
for (int i = kWIDTH - 1; i >= 0; --i)
{
auto prev = data_[i];
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
@@ -446,36 +423,36 @@ public:
return *this;
}
BaseUInt
BaseUint
operator--(int)
{
// postfix operator
BaseUInt const ret = *this;
BaseUint const ret = *this;
--(*this);
return ret;
}
[[nodiscard]] BaseUInt
[[nodiscard]] BaseUint
next() const
{
auto ret = *this;
return ++ret;
}
[[nodiscard]] BaseUInt
[[nodiscard]] BaseUint
prev() const
{
auto ret = *this;
return --ret;
}
BaseUInt&
operator+=(BaseUInt const& b)
BaseUint&
operator+=(BaseUint const& b)
{
std::uint64_t carry = 0;
for (int i = kWidth - 1; i >= 0; i--)
for (int i = kWIDTH - 1; i >= 0; i--)
{
std::uint64_t const n = carry + boost::endian::big_to_native(data_[i]) +
boost::endian::big_to_native(b.data_[i]);
@@ -489,7 +466,7 @@ public:
template <class Hasher>
friend void
hash_append(Hasher& h, BaseUInt const& a) noexcept
hash_append(Hasher& h, BaseUint const& a) noexcept
{
// Do not allow any endian transformations on this memory
h(a.data_.data(), sizeof(a.data_));
@@ -526,13 +503,13 @@ public:
return parseHex(std::string_view{str});
}
static constexpr std::size_t
constexpr static std::size_t
size()
{
return kBytes;
return kBYTES;
}
BaseUInt<Bits, Tag>&
BaseUint<Bits, Tag>&
operator=(beast::Zero)
{
data_.fill(0);
@@ -543,28 +520,28 @@ public:
[[nodiscard]] bool
isZero() const
{
return *this == beast::kZero;
return *this == beast::kZERO;
}
[[nodiscard]] bool
isNonZero() const
{
return *this != beast::kZero;
return *this != beast::kZERO;
}
void
zero()
{
*this = beast::kZero;
*this = beast::kZERO;
}
};
using uint128 = BaseUInt<128>;
using uint160 = BaseUInt<160>;
using uint256 = BaseUInt<256>;
using uint192 = BaseUInt<192>;
using uint128 = BaseUint<128>;
using uint160 = BaseUint<160>;
using uint256 = BaseUint<256>;
using uint192 = BaseUint<192>;
template <std::size_t Bits, class Tag>
[[nodiscard]] constexpr std::strong_ordering
operator<=>(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
operator<=>(BaseUint<Bits, Tag> const& lhs, BaseUint<Bits, Tag> const& rhs)
{
// This comparison might seem wrong on a casual inspection because it
// compares data internally stored as std::uint32_t byte-by-byte. But
@@ -585,7 +562,7 @@ operator<=>(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
template <std::size_t Bits, typename Tag>
[[nodiscard]] constexpr bool
operator==(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
operator==(BaseUint<Bits, Tag> const& lhs, BaseUint<Bits, Tag> const& rhs)
{
return (lhs <=> rhs) == 0;
}
@@ -593,59 +570,59 @@ operator==(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
//------------------------------------------------------------------------------
template <std::size_t Bits, class Tag>
constexpr bool
operator==(BaseUInt<Bits, Tag> const& a, std::uint64_t b)
operator==(BaseUint<Bits, Tag> const& a, std::uint64_t b)
{
return a == BaseUInt<Bits, Tag>(b);
return a == BaseUint<Bits, Tag>(b);
}
//------------------------------------------------------------------------------
template <std::size_t Bits, class Tag>
constexpr BaseUInt<Bits, Tag>
operator^(BaseUInt<Bits, Tag> const& a, BaseUInt<Bits, Tag> const& b)
constexpr BaseUint<Bits, Tag>
operator^(BaseUint<Bits, Tag> const& a, BaseUint<Bits, Tag> const& b)
{
return BaseUInt<Bits, Tag>(a) ^= b;
return BaseUint<Bits, Tag>(a) ^= b;
}
template <std::size_t Bits, class Tag>
constexpr BaseUInt<Bits, Tag>
operator&(BaseUInt<Bits, Tag> const& a, BaseUInt<Bits, Tag> const& b)
constexpr BaseUint<Bits, Tag>
operator&(BaseUint<Bits, Tag> const& a, BaseUint<Bits, Tag> const& b)
{
return BaseUInt<Bits, Tag>(a) &= b;
return BaseUint<Bits, Tag>(a) &= b;
}
template <std::size_t Bits, class Tag>
constexpr BaseUInt<Bits, Tag>
operator|(BaseUInt<Bits, Tag> const& a, BaseUInt<Bits, Tag> const& b)
constexpr BaseUint<Bits, Tag>
operator|(BaseUint<Bits, Tag> const& a, BaseUint<Bits, Tag> const& b)
{
return BaseUInt<Bits, Tag>(a) |= b;
return BaseUint<Bits, Tag>(a) |= b;
}
template <std::size_t Bits, class Tag>
constexpr BaseUInt<Bits, Tag>
operator+(BaseUInt<Bits, Tag> const& a, BaseUInt<Bits, Tag> const& b)
constexpr BaseUint<Bits, Tag>
operator+(BaseUint<Bits, Tag> const& a, BaseUint<Bits, Tag> const& b)
{
return BaseUInt<Bits, Tag>(a) += b;
return BaseUint<Bits, Tag>(a) += b;
}
//------------------------------------------------------------------------------
template <std::size_t Bits, class Tag>
inline std::string
to_string(BaseUInt<Bits, Tag> const& a)
to_string(BaseUint<Bits, Tag> const& a)
{
return strHex(a.cbegin(), a.cend());
}
template <std::size_t Bits, class Tag>
inline std::string
toShortString(BaseUInt<Bits, Tag> const& a)
toShortString(BaseUint<Bits, Tag> const& a)
{
static_assert(BaseUInt<Bits, Tag>::kBytes > 4, "For 4 bytes or less, use a native type");
static_assert(BaseUint<Bits, Tag>::kBYTES > 4, "For 4 bytes or less, use a native type");
return strHex(a.cbegin(), a.cbegin() + 4) + "...";
}
template <std::size_t Bits, class Tag>
inline std::ostream&
operator<<(std::ostream& out, BaseUInt<Bits, Tag> const& u)
operator<<(std::ostream& out, BaseUint<Bits, Tag> const& u)
{
return out << to_string(u);
}
@@ -673,7 +650,7 @@ static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
namespace beast {
template <std::size_t Bits, class Tag>
struct IsUniquelyRepresented<xrpl::BaseUInt<Bits, Tag>> : public std::true_type
struct IsUniquelyRepresented<xrpl::BaseUint<Bits, Tag>> : public std::true_type
{
explicit IsUniquelyRepresented() = default;
};

View File

@@ -30,10 +30,10 @@ using weeks = std::chrono::duration<int, std::ratio_multiply<days::period, std::
= seconds(946684800)
*/
static constexpr std::chrono::seconds kEpochOffset =
constexpr static std::chrono::seconds kEPOCH_OFFSET =
date::sys_days{date::year{2000} / 1 / 1} - date::sys_days{date::year{1970} / 1 / 1};
static_assert(kEpochOffset.count() == 946684800);
static_assert(kEPOCH_OFFSET.count() == 946684800);
class NetClock
{
@@ -60,7 +60,7 @@ to_string(NetClock::time_point tp)
{
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
using namespace std::chrono;
return to_string(system_clock::time_point{tp.time_since_epoch() + kEpochOffset});
return to_string(system_clock::time_point{tp.time_since_epoch() + kEPOCH_OFFSET});
}
template <class Duration>
@@ -77,7 +77,7 @@ toStringIso(NetClock::time_point tp)
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
// Note, NetClock::duration is seconds, as checked by static_assert
static_assert(std::is_same_v<NetClock::duration::period, std::ratio<1>>);
return toStringIso(date::sys_time<NetClock::duration>{tp.time_since_epoch() + kEpochOffset});
return toStringIso(date::sys_time<NetClock::duration>{tp.time_since_epoch() + kEPOCH_OFFSET});
}
/** A clock for measuring elapsed time.

View File

@@ -31,9 +31,9 @@ makeSeedPair() noexcept
// state_t(state_t const&) = delete;
// state_t& operator=(state_t const&) = delete;
};
static StateT kState;
std::scoped_lock const lock(kState.mutex);
return {kState.dist(kState.gen), kState.dist(kState.gen)};
static StateT kSTATE;
std::scoped_lock const lock(kSTATE.mutex);
return {kSTATE.dist(kSTATE.gen), kSTATE.dist(kSTATE.gen)};
}
} // namespace detail

View File

@@ -5,7 +5,7 @@
#include <optional>
namespace xrpl {
constexpr auto kMuldivMax = std::numeric_limits<std::uint64_t>::max();
auto constexpr kMULDIV_MAX = std::numeric_limits<std::uint64_t>::max();
/** Return value*mul/div accurately.
Computes the result of the multiplication and division in

View File

@@ -236,7 +236,7 @@ public:
map_.resize(partitions_);
XRPL_ASSERT(
partitions_,
"xrpl::PartitionedUnorderedMap::PartitionedUnorderedMap : "
"xrpl::partitioned_unordered_map::partitioned_unordered_map : "
"nonzero partitions");
}

View File

@@ -47,7 +47,7 @@ inline beast::xor_shift_engine&
defaultPrng()
{
// This is used to seed the thread-specific PRNGs on demand
static beast::xor_shift_engine kSeeder = [] {
static beast::xor_shift_engine kSEEDER = [] {
std::random_device rng;
std::uniform_int_distribution<std::uint64_t> distribution{1};
return beast::xor_shift_engine(distribution(rng));
@@ -57,17 +57,17 @@ defaultPrng()
static std::mutex kM;
// The thread-specific PRNGs:
thread_local beast::xor_shift_engine kEngine = [] {
thread_local beast::xor_shift_engine kENGINE = [] {
std::uint64_t seed = 0;
{
std::scoped_lock const lk(kM);
std::uniform_int_distribution<std::uint64_t> distribution{1};
seed = distribution(kSeeder);
seed = distribution(kSEEDER);
}
return beast::xor_shift_engine{seed};
}();
return kEngine;
return kENGINE;
}
/** Return a uniformly distributed random integer.
@@ -94,7 +94,7 @@ template <class Engine, class Integral>
std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
randInt(Engine& engine, Integral min, Integral max)
{
XRPL_ASSERT(max > min, "xrpl::randInt : max over min inputs");
XRPL_ASSERT(max > min, "xrpl::rand_int : max over min inputs");
// This should have no state and constructing it should
// be very cheap. If that turns out not to be the case

View File

@@ -22,9 +22,9 @@ safeCast(Src s) noexcept
{
static_assert(
std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned");
constexpr unsigned kNotSame = std::is_signed_v<Dest> != std::is_signed_v<Src>;
constexpr unsigned kNOT_SAME = std::is_signed_v<Dest> != std::is_signed_v<Src>;
static_assert(
sizeof(Dest) >= sizeof(Src) + kNotSame,
sizeof(Dest) >= sizeof(Src) + kNOT_SAME,
"Destination is too small to hold all values of source");
return static_cast<Dest>(s);
}
@@ -81,7 +81,7 @@ safeDowncast(Src* s) noexcept
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
#else
auto* result = dynamic_cast<Dest>(s);
XRPL_ASSERT(result != nullptr, "xrpl::safeDowncast : pointer downcast is valid");
XRPL_ASSERT(result != nullptr, "xrpl::safe_downcast : pointer downcast is valid");
return result;
#endif
}
@@ -94,7 +94,7 @@ safeDowncast(Src& s) noexcept
#ifndef NDEBUG
XRPL_ASSERT(
dynamic_cast<std::add_pointer_t<std::remove_reference_t<Dest>>>(&s) != nullptr,
"xrpl::safeDowncast : reference downcast is valid");
"xrpl::safe_downcast : reference downcast is valid");
#endif
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
}

View File

@@ -205,7 +205,7 @@ class ScopeUnlock
public:
explicit ScopeUnlock(std::unique_lock<Mutex>& lock) noexcept(true) : plock_(&lock)
{
XRPL_ASSERT(plock_->owns_lock(), "xrpl::ScopeUnlock::ScopeUnlock : mutex must be locked");
XRPL_ASSERT(plock_->owns_lock(), "xrpl::scope_unlock::scope_unlock : mutex must be locked");
plock_->unlock();
}

View File

@@ -103,7 +103,7 @@ public:
{
XRPL_ASSERT(
index >= 0 && (mask_ != 0),
"xrpl::PackedSpinlock::PackedSpinlock : valid index and mask");
"xrpl::packed_spinlock::packed_spinlock : valid index and mask");
}
[[nodiscard]] bool

View File

@@ -15,7 +15,7 @@ namespace beast {
/** Measures handler latency on an io_context queue. */
template <class Clock>
class IOLatencyProbe
class IoLatencyProbe
{
private:
using duration = typename Clock::duration;
@@ -30,12 +30,12 @@ private:
bool cancel_{false};
public:
IOLatencyProbe(duration const& period, boost::asio::io_context& ios)
IoLatencyProbe(duration const& period, boost::asio::io_context& ios)
: period_(period), ios_(ios), timer_(ios_)
{
}
~IOLatencyProbe()
~IoLatencyProbe()
{
std::unique_lock<decltype(mutex_)> lock(mutex_);
cancel(lock, true);
@@ -85,7 +85,7 @@ public:
{
std::scoped_lock const lock(mutex_);
if (cancel_)
throw std::logic_error("IOLatencyProbe is canceled");
throw std::logic_error("io_latency_probe is canceled");
boost::asio::post(
ios_, SampleOp<Handler>(std::forward<Handler>(handler), Clock::now(), false, this));
}
@@ -100,7 +100,7 @@ public:
{
std::scoped_lock const lock(mutex_);
if (cancel_)
throw std::logic_error("IOLatencyProbe is canceled");
throw std::logic_error("io_latency_probe is canceled");
boost::asio::post(
ios_, SampleOp<Handler>(std::forward<Handler>(handler), Clock::now(), true, this));
}
@@ -140,18 +140,18 @@ private:
Handler handler;
time_point start;
bool repeat;
IOLatencyProbe* probe;
IoLatencyProbe* probe;
SampleOp(
Handler const& handler,
time_point const& start,
bool repeat,
IOLatencyProbe* probe)
IoLatencyProbe* probe)
: handler(handler), start(start), repeat(repeat), probe(probe)
{
XRPL_ASSERT(
probe,
"beast::IOLatencyProbe::SampleOp::SampleOp : non-null "
"beast::io_latency_probe::sample_op::sample_op : non-null "
"probe input");
probe->addref();
}
@@ -164,7 +164,7 @@ private:
{
XRPL_ASSERT(
probe,
"beast::IOLatencyProbe::SampleOp::SampleOp(SampleOp&&) : "
"beast::io_latency_probe::sample_op::sample_op(sample_op&&) : "
"non-null probe input");
from.probe = nullptr;
}

View File

@@ -83,8 +83,8 @@ template <class Facade, class Clock = Facade>
AbstractClock<Facade>&
getAbstractClock()
{
static detail::AbstractClockWrapper<Facade, Clock> kClock;
return kClock;
static detail::AbstractClockWrapper<Facade, Clock> kCLOCK;
return kCLOCK;
}
} // namespace beast

View File

@@ -1370,7 +1370,7 @@ private:
buck_.resize(size() + additional, cont_);
XRPL_ASSERT(
loadFactor() <= maxLoadFactor(),
"beast::detail::AgedUnorderedContainer::maybeRehash : maximum "
"beast::detail::AgedUnorderedContainer::maybe_rehash : maximum "
"load factor");
}

View File

@@ -21,7 +21,7 @@ setCurrentThreadName(std::string_view newThreadName);
// On Linux, thread names are limited to 16 bytes including the null terminator.
// Maximum number of characters is therefore 15.
constexpr std::size_t kMaxThreadNameLength = 15;
constexpr std::size_t kMAX_THREAD_NAME_LENGTH = 15;
/** Sets the name of the caller thread with compile-time size checking.
@tparam N The size of the string literal including null terminator
@@ -34,7 +34,7 @@ template <std::size_t N>
void
setCurrentThreadName(char const (&newThreadName)[N])
{
static_assert(N <= kMaxThreadNameLength + 1, "Thread name cannot exceed 15 characters");
static_assert(N <= kMAX_THREAD_NAME_LENGTH + 1, "Thread name cannot exceed 15 characters");
setCurrentThreadName(std::string_view(newThreadName, N - 1));
}

View File

@@ -53,7 +53,7 @@ inline void
maybeReverseBytes(T& t, Hasher&)
{
maybeReverseBytes(
t, std::integral_constant<bool, Hasher::kEndian != boost::endian::order::native>{});
t, std::integral_constant<bool, Hasher::kENDIAN != boost::endian::order::native>{});
}
} // namespace detail
@@ -154,7 +154,7 @@ struct IsContiguouslyHashable
: public std::integral_constant<
bool,
IsUniquelyRepresented<T>::value &&
(sizeof(T) == 1 || HashAlgorithm::kEndian == boost::endian::order::native)>
(sizeof(T) == 1 || HashAlgorithm::kENDIAN == boost::endian::order::native)>
{
explicit IsContiguouslyHashable() = default;
};

View File

@@ -21,9 +21,9 @@ private:
static_assert(sizeof(std::size_t) == 8, "requires 64-bit std::size_t");
// Have an internal buffer to avoid the streaming API
// A 64-byte buffer should to be big enough for us
static constexpr std::size_t kInternalBufferSize = 64;
static constexpr std::size_t kINTERNAL_BUFFER_SIZE = 64;
alignas(64) std::array<std::uint8_t, kInternalBufferSize> buffer_{};
alignas(64) std::array<std::uint8_t, kINTERNAL_BUFFER_SIZE> buffer_{};
std::span<std::uint8_t> readBuffer_;
std::span<std::uint8_t> writeBuffer_;
@@ -102,7 +102,7 @@ private:
}
public:
static constexpr auto kEndian = boost::endian::order::native;
static constexpr auto const kENDIAN = boost::endian::order::native;
Xxhasher(Xxhasher const&) = delete;
Xxhasher&

View File

@@ -62,7 +62,9 @@ private:
{
using run_time = std::pair<std::string, typename clock_type::duration>;
static constexpr auto kMaxTop = 10;
// Need to be named before converting
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum { MaxTop = 10 };
std::size_t suites = 0;
std::size_t cases = 0;
@@ -146,11 +148,11 @@ Reporter<Unused>::Results::add(SuiteResults const& r)
});
if (iter != top.end())
{
if (top.size() == kMaxTop)
if (top.size() == MaxTop)
top.resize(top.size() - 1);
top.emplace(iter, r.name, elapsed);
}
else if (top.size() < kMaxTop)
else if (top.size() < MaxTop)
{
top.emplace_back(r.name, elapsed);
}

View File

@@ -299,8 +299,8 @@ private:
static Suite**
pThisSuite()
{
static Suite* kPTs = nullptr; // NOLINT TODO
return &kPTs;
static Suite* kP_TS = nullptr; // NOLINT TODO
return &kP_TS;
}
/** Runs the suite. */

View File

@@ -2,25 +2,29 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <cstdint>
#include <sstream>
namespace beast {
/** A namespace for easy access to logging severity values. */
namespace severities {
/** Severity level / threshold of a Journal message. */
enum class Severity : std::uint8_t {
All = 0,
// Hundreds of usages via logging macros
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum Severity {
KAll = 0,
Trace = All,
Debug = 1,
Info = 2,
Warning = 3,
Error = 4,
Fatal = 5,
KTrace = KAll,
KDebug = 1,
KInfo = 2,
KWarning = 3,
KError = 4,
KFatal = 5,
Disabled = 6,
None = Disabled
KDisabled = 6,
KNone = KDisabled
};
} // namespace severities
/** A generic endpoint for log messages.
@@ -40,6 +44,9 @@ public:
class Sink;
private:
// Severity level / threshold of a Journal message.
using Severity = severities::Severity;
// Invariant: sink_ always points to a valid Sink
Sink* sink_;
@@ -176,7 +183,7 @@ public:
{
public:
/** Create a stream which produces no output. */
explicit Stream() : sink_(getNullSink()), level_(Severity::Disabled)
explicit Stream() : sink_(getNullSink()), level_(severities::KDisabled)
{
}
@@ -187,7 +194,7 @@ public:
Stream(Sink& sink, Severity level) : sink_(sink), level_(level)
{
XRPL_ASSERT(
level_ < Severity::Disabled, "beast::Journal::Stream::Stream : maximum level");
level_ < severities::KDisabled, "beast::Journal::Stream::Stream : maximum level");
}
/** Construct or copy another Stream. */
@@ -290,37 +297,37 @@ public:
[[nodiscard]] Stream
trace() const
{
return {*sink_, Severity::Trace};
return {*sink_, severities::KTrace};
}
[[nodiscard]] Stream
debug() const
{
return {*sink_, Severity::Debug};
return {*sink_, severities::KDebug};
}
[[nodiscard]] Stream
info() const
{
return {*sink_, Severity::Info};
return {*sink_, severities::KInfo};
}
[[nodiscard]] Stream
warn() const
{
return {*sink_, Severity::Warning};
return {*sink_, severities::KWarning};
}
[[nodiscard]] Stream
error() const
{
return {*sink_, Severity::Error};
return {*sink_, severities::KError};
}
[[nodiscard]] Stream
fatal() const
{
return {*sink_, Severity::Fatal};
return {*sink_, severities::KFatal};
}
/** @} */
};

View File

@@ -36,7 +36,7 @@ public:
}
[[nodiscard]] bool
active(beast::Severity level) const override
active(beast::severities::Severity level) const override
{
return sink_.active(level);
}
@@ -53,27 +53,27 @@ public:
sink_.console(output);
}
[[nodiscard]] beast::Severity
[[nodiscard]] beast::severities::Severity
threshold() const override
{
return sink_.threshold();
}
void
threshold(beast::Severity thresh) override
threshold(beast::severities::Severity thresh) override
{
sink_.threshold(thresh);
}
void
write(beast::Severity level, std::string const& text) override
write(beast::severities::Severity level, std::string const& text) override
{
using beast::Journal;
sink_.write(level, prefix_ + text);
}
void
writeAlways(Severity level, std::string const& text) override
writeAlways(severities::Severity level, std::string const& text) override
{
using beast::Journal;
sink_.writeAlways(level, prefix_ + text);

View File

@@ -27,7 +27,7 @@ struct Zero
};
namespace {
constexpr Zero kZero{};
constexpr Zero kZERO{};
} // namespace
/** Default implementation of signum calls the method on the class. */
@@ -102,42 +102,42 @@ template <typename T>
bool
operator==(Zero, T const& t)
{
return t == kZero;
return t == kZERO;
}
template <typename T>
bool
operator!=(Zero, T const& t)
{
return t != kZero;
return t != kZERO;
}
template <typename T>
bool
operator<(Zero, T const& t)
{
return t > kZero;
return t > kZERO;
}
template <typename T>
bool
operator>(Zero, T const& t)
{
return t < kZero;
return t < kZERO;
}
template <typename T>
bool
operator>=(Zero, T const& t)
{
return t <= kZero;
return t <= kZERO;
}
template <typename T>
bool
operator<=(Zero, T const& t)
{
return t >= kZero;
return t >= kZERO;
}
} // namespace beast

View File

@@ -14,23 +14,23 @@ void
rngfill(void* const buffer, std::size_t const bytes, Generator& g)
{
using result_type = typename Generator::result_type;
constexpr std::size_t kResultSize = sizeof(result_type);
constexpr std::size_t kRESULT_SIZE = sizeof(result_type);
std::uint8_t* const bufferStart = static_cast<std::uint8_t*>(buffer);
std::size_t const completeIterations = bytes / kResultSize;
std::size_t const bytesRemaining = bytes % kResultSize;
std::size_t const completeIterations = bytes / kRESULT_SIZE;
std::size_t const bytesRemaining = bytes % kRESULT_SIZE;
for (std::size_t count = 0; count < completeIterations; ++count)
{
result_type const v = g();
std::size_t const offset = count * kResultSize;
std::memcpy(bufferStart + offset, &v, kResultSize);
std::size_t const offset = count * kRESULT_SIZE;
std::memcpy(bufferStart + offset, &v, kRESULT_SIZE);
}
if (bytesRemaining > 0)
{
result_type const v = g();
std::size_t const offset = completeIterations * kResultSize;
std::size_t const offset = completeIterations * kRESULT_SIZE;
std::memcpy(bufferStart + offset, &v, bytesRemaining);
}
}

View File

@@ -26,14 +26,12 @@ public:
result_type
operator()();
static constexpr result_type
min()
static result_type constexpr min()
{
return std::numeric_limits<result_type>::min();
}
static constexpr result_type
max()
static result_type constexpr max()
{
return std::numeric_limits<result_type>::max();
}

View File

@@ -27,7 +27,7 @@ public:
that were previously considered valid to no longer
be allowed.
*/
static constexpr std::size_t kMaxSerializedCondition = 128;
static constexpr std::size_t kMAX_SERIALIZED_CONDITION = 128;
/** Load a condition from its binary form

View File

@@ -16,7 +16,7 @@ public:
that were previously considered valid to no longer
be allowed.
*/
static constexpr std::size_t kMaxSerializedFulfillment = 256;
static constexpr std::size_t kMAX_SERIALIZED_FULFILLMENT = 256;
/** Load a fulfillment from its binary form

View File

@@ -23,7 +23,7 @@ public:
While future versions of this code will never lower
this limit, they may opt to raise it.
*/
static constexpr std::size_t kMaxPreimageLength = 128;
static constexpr std::size_t kMAX_PREIMAGE_LENGTH = 128;
/** Parse the payload for a PreimageSha256 condition
@@ -65,7 +65,7 @@ public:
return {};
}
if (s.size() > kMaxPreimageLength)
if (s.size() > kMAX_PREIMAGE_LENGTH)
{
ec = Error::PreimageTooLong;
return {};

View File

@@ -6,7 +6,7 @@ namespace xrpl {
/// Coroutine stack size (1.5 MB). Increased from 1 MB because
/// ASAN-instrumented deep call stacks exceeded the original limit.
constexpr std::size_t kCoroStackSize = 1536 * 1024;
constexpr std::size_t kCORO_STACK_SIZE = 1536 * 1024;
template <class F>
JobQueue::Coro::Coro(CoroCreateT, JobQueue& jq, JobType type, std::string name, F&& f)
@@ -14,7 +14,7 @@ JobQueue::Coro::Coro(CoroCreateT, JobQueue& jq, JobType type, std::string name,
, type_(type)
, name_(std::move(name))
, coro_(
boost::context::protected_fixedsize_stack(kCoroStackSize),
boost::context::protected_fixedsize_stack(kCORO_STACK_SIZE),
[this, fn = std::forward<F>(f)](boost::coroutines2::coroutine<void>::push_type& doYield) {
yield_ = &doYield;
yield();

View File

@@ -101,8 +101,8 @@ public:
static JobTypes const&
instance()
{
static JobTypes const kTypes;
return kTypes;
static JobTypes const kTYPES;
return kTYPES;
}
static std::string const&

View File

@@ -5,7 +5,7 @@
namespace xrpl {
/** A PropertyStream::Sink which produces a json::Value of type ValueType::Object. */
/** A PropertyStream::Sink which produces a json::Value of type objectValue. */
class JsonPropertyStream : public beast::PropertyStream
{
public:

View File

@@ -67,25 +67,27 @@ public:
[[nodiscard]] std::string
getFormattedErrorMessages() const;
static constexpr unsigned kNestLimit{25};
static constexpr unsigned kNEST_LIMIT{25};
private:
enum class TokenType {
EndOfStream = 0,
ObjectBegin,
ObjectEnd,
ArrayBegin,
ArrayEnd,
String,
Integer,
Double,
True,
False,
Null,
ArraySeparator,
MemberSeparator,
Comment,
Error
// 53 files, protocol-wide
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum TokenType {
TokenEndOfStream = 0,
TokenObjectBegin,
TokenObjectEnd,
TokenArrayBegin,
TokenArrayEnd,
TokenString,
TokenInteger,
TokenDouble,
TokenTrue,
TokenFalse,
TokenNull,
TokenArraySeparator,
TokenMemberSeparator,
TokenComment,
TokenError
};
class Token

View File

@@ -15,20 +15,22 @@ namespace json {
/** \brief Type of the value held by a Value object.
*/
enum class ValueType {
Null = 0, ///< 'null' value
Int, ///< signed integer value
UInt, ///< unsigned integer value
Real, ///< double value
String, ///< UTF-8 string value
Boolean, ///< bool value
Array, ///< array value (ordered list)
Object ///< object value (collection of name/value pairs).
// Used throughout JSON layer
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum ValueType {
NullValue = 0, ///< 'null' value
IntValue, ///< signed integer value
UintValue, ///< unsigned integer value
RealValue, ///< double value
StringValue, ///< UTF-8 string value
BooleanValue, ///< bool value
ArrayValue, ///< array value (ordered list)
ObjectValue ///< object value (collection of name/value pairs).
};
/** \brief Lightweight wrapper to tag static string.
*
* Value constructor and ValueType::Object member assignment takes advantage of the
* Value constructor and objectValue member assignment takes advantage of the
* StaticString and avoid the cost of string duplication when storing the
* string or the member name.
*
@@ -102,8 +104,8 @@ operator!=(StaticString x, std::string const& y)
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
*
* This class is a discriminated union wrapper that can represent a:
* - signed integer [range: Value::kMinInt - Value::kMaxInt]
* - unsigned integer (range: 0 - Value::kMaxUInt)
* - signed integer [range: Value::minInt - Value::maxInt]
* - unsigned integer (range: 0 - Value::maxUInt)
* - double
* - UTF-8 string
* - boolean
@@ -114,16 +116,16 @@ operator!=(StaticString x, std::string const& y)
* The type of the held value is represented by a #ValueType and
* can be obtained using type().
*
* values of an ValueType::Object or ValueType::Array can be accessed using operator[]()
* methods. Non const methods will automatically create the a ValueType::Null element
* values of an #objectValue or #arrayValue can be accessed using operator[]()
* methods. Non const methods will automatically create the a #nullValue element
* if it does not exist.
* The sequence of an ValueType::Array will be automatically resize and initialized
* with ValueType::Null. resize() can be used to enlarge or truncate an ValueType::Array.
* The sequence of an #arrayValue will be automatically resize and initialized
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
*
* The get() methods can be used to obtain a default value in the case the
* required element does not exist.
*
* It is possible to iterate over the list of a ValueType::Object values using
* It is possible to iterate over the list of a #objectValue values using
* the getMemberNames() method.
*/
class Value
@@ -138,16 +140,18 @@ public:
using Int = json::Int;
using ArrayIndex = UInt;
static Value const kNull;
static constexpr Int kMinInt = std::numeric_limits<Int>::min();
static constexpr Int kMaxInt = std::numeric_limits<Int>::max();
static constexpr UInt kMaxUInt = std::numeric_limits<UInt>::max();
static Value const kNULL;
static constexpr Int kMIN_INT = std::numeric_limits<Int>::min();
static constexpr Int kMAX_INT = std::numeric_limits<Int>::max();
static constexpr UInt kMAX_U_INT = std::numeric_limits<UInt>::max();
private:
class CZString
{
public:
enum class DuplicationPolicy { NoDuplication = 0, Duplicate, DuplicateOnCopy };
// Stored as int field, implicit conversion
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum DuplicationPolicy { NoDuplication = 0, Duplicate, DuplicateOnCopy };
CZString(int index);
CZString(char const* cstr, DuplicationPolicy allocate);
@@ -178,19 +182,19 @@ public:
/** \brief Create a default Value of the given type.
This is a very useful constructor.
To create an empty array, pass ValueType::Array.
To create an empty object, pass ValueType::Object.
To create an empty array, pass arrayValue.
To create an empty object, pass objectValue.
Another Value can then be set to this one by assignment.
This is useful since clear() and resize() will not alter types.
Examples:
\code
json::Value null_value; // null
json::Value arr_value(json::ValueType::Array); // []
json::Value obj_value(json::ValueType::Object); // {}
json::Value arr_value(json::arrayValue); // []
json::Value obj_value(json::objectValue); // {}
\endcode
*/
Value(ValueType type = ValueType::Null);
Value(ValueType type = NullValue);
Value(Int value);
Value(UInt value);
Value(double value);
@@ -286,7 +290,7 @@ public:
operator bool() const;
/// Remove all object members and array elements.
/// \pre type() is ValueType::Array, ValueType::Object, or ValueType::Null
/// \pre type() is arrayValue, objectValue, or nullValue
/// \post type() is unchanged
void
clear();
@@ -363,7 +367,7 @@ public:
///
/// Do nothing if it did not exist.
/// \return the removed Value, or null.
/// \pre type() is ValueType::Object or ValueType::Null
/// \pre type() is objectValue or nullValue
/// \post type() is unchanged
Value
removeMember(char const* key);
@@ -384,8 +388,8 @@ public:
/// \brief Return a list of the member names.
///
/// If null, return an empty list.
/// \pre type() is ValueType::Object or ValueType::Null
/// \post if type() was ValueType::Null, it remains ValueType::Null
/// \pre type() is objectValue or nullValue
/// \post if type() was nullValue, it remains nullValue
[[nodiscard]] Members
getMemberNames() const;
@@ -465,14 +469,16 @@ operator>=(Value const& x, Value const& y)
* string value memory management done by Value.
*
* - makeMemberName() and releaseMemberName() are called to respectively
* duplicate and free an json::ValueType::Object member name.
* duplicate and free an json::objectValue member name.
* - duplicateStringValue() and releaseStringValue() are called similarly to
* duplicate and free a json::ValueType::String value.
* duplicate and free a json::stringValue value.
*/
class ValueAllocator
{
public:
static constexpr auto kUnknown = (unsigned)-1;
// Need to be named before converting
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum { Unknown = (unsigned)-1 };
virtual ~ValueAllocator() = default;
@@ -481,7 +487,7 @@ public:
virtual void
releaseMemberName(char* memberName) = 0;
virtual char*
duplicateStringValue(char const* value, unsigned int length = kUnknown) = 0;
duplicateStringValue(char const* value, unsigned int length = Unknown) = 0;
virtual void
releaseStringValue(char* value) = 0;
};
@@ -517,12 +523,12 @@ public:
[[nodiscard]] Value
key() const;
/// Return the index of the referenced Value. -1 if it is not an ValueType::Array.
/// Return the index of the referenced Value. -1 if it is not an arrayValue.
[[nodiscard]] UInt
index() const;
/// Return the member name of the referenced Value. "" if it is not an
/// ValueType::Object.
/// objectValue.
[[nodiscard]] char const*
memberName() const;

View File

@@ -204,31 +204,31 @@ writeValue(Write const& write, Value const& value)
{
switch (value.type())
{
case ValueType::Null:
case NullValue:
write("null", 4);
break;
case ValueType::Int:
case IntValue:
writeString(write, valueToString(value.asInt()));
break;
case ValueType::UInt:
case UintValue:
writeString(write, valueToString(value.asUInt()));
break;
case ValueType::Real:
case RealValue:
writeString(write, valueToString(value.asDouble()));
break;
case ValueType::String:
case StringValue:
writeString(write, valueToQuotedString(value.asCString()));
break;
case ValueType::Boolean:
case BooleanValue:
writeString(write, valueToString(value.asBool()));
break;
case ValueType::Array: {
case ArrayValue: {
write("[", 1);
int const size = value.size();
for (int index = 0; index < size; ++index)
@@ -241,7 +241,7 @@ writeValue(Write const& write, Value const& value)
break;
}
case ValueType::Object: {
case ObjectValue: {
Value::Members const members = value.getMemberNames();
write("{", 1);
for (auto it = members.begin(); it != members.end(); ++it)

View File

@@ -67,7 +67,7 @@ public:
[[nodiscard]] virtual json::Value
getJson(bool isAdmin) const = 0;
/** Returns a json::ValueType::Object. */
/** Returns a json::objectValue. */
[[nodiscard]] virtual json::Value
getJson(uint256 const& amendment, bool isAdmin) const = 0;

View File

@@ -24,7 +24,7 @@ struct CreateGenesisT
{
explicit CreateGenesisT() = default;
};
extern CreateGenesisT const kCreateGenesis;
extern CreateGenesisT const kCREATE_GENESIS;
/** Holds a ledger.

View File

@@ -12,7 +12,7 @@ namespace xrpl {
Values should not be duplicated.
@see getNextLedgerTimeResolution
*/
constexpr std::chrono::seconds kLedgerPossibleTimeResolutions[] = {
std::chrono::seconds constexpr kLEDGER_POSSIBLE_TIME_RESOLUTIONS[] = {
std::chrono::seconds{10},
std::chrono::seconds{20},
std::chrono::seconds{30},
@@ -21,16 +21,16 @@ constexpr std::chrono::seconds kLedgerPossibleTimeResolutions[] = {
std::chrono::seconds{120}};
//! Initial resolution of ledger close time.
constexpr auto kLedgerDefaultTimeResolution = kLedgerPossibleTimeResolutions[2];
auto constexpr kLEDGER_DEFAULT_TIME_RESOLUTION = kLEDGER_POSSIBLE_TIME_RESOLUTIONS[2];
//! Close time resolution in genesis ledger
constexpr auto kLedgerGenesisTimeResolution = kLedgerPossibleTimeResolutions[0];
auto constexpr kLEDGER_GENESIS_TIME_RESOLUTION = kLEDGER_POSSIBLE_TIME_RESOLUTIONS[0];
//! How often we increase the close time resolution (in numbers of ledgers)
constexpr auto kIncreaseLedgerTimeResolutionEvery = 8;
auto constexpr kINCREASE_LEDGER_TIME_RESOLUTION_EVERY = 8;
//! How often we decrease the close time resolution (in numbers of ledgers)
constexpr auto kDecreaseLedgerTimeResolutionEvery = 1;
auto constexpr kDECREASE_LEDGER_TIME_RESOLUTION_EVERY = 1;
/** Calculates the close time resolution for the specified ledger.
@@ -46,7 +46,7 @@ constexpr auto kDecreaseLedgerTimeResolutionEvery = 1;
@param ledgerSeq the sequence number of the new ledger
@pre previousResolution must be a valid bin
from @ref kLedgerPossibleTimeResolutions
from @ref kLEDGER_POSSIBLE_TIME_RESOLUTIONS
@tparam Rep Type representing number of ticks in std::chrono::duration
@tparam Period An std::ratio representing tick period in
@@ -67,30 +67,30 @@ getNextLedgerTimeResolution(
using namespace std::chrono;
// Find the current resolution:
auto iter = std::find(
std::begin(kLedgerPossibleTimeResolutions),
std::end(kLedgerPossibleTimeResolutions),
std::begin(kLEDGER_POSSIBLE_TIME_RESOLUTIONS),
std::end(kLEDGER_POSSIBLE_TIME_RESOLUTIONS),
previousResolution);
XRPL_ASSERT(
iter != std::end(kLedgerPossibleTimeResolutions),
iter != std::end(kLEDGER_POSSIBLE_TIME_RESOLUTIONS),
"xrpl::getNextLedgerTimeResolution : found time resolution");
// This should never happen, but just as a precaution
if (iter == std::end(kLedgerPossibleTimeResolutions))
if (iter == std::end(kLEDGER_POSSIBLE_TIME_RESOLUTIONS))
return previousResolution;
// If we did not previously agree, we try to decrease the resolution to
// improve the chance that we will agree now.
if (!previousAgree && (ledgerSeq % Seq{kDecreaseLedgerTimeResolutionEvery} == Seq{0}))
if (!previousAgree && (ledgerSeq % Seq{kDECREASE_LEDGER_TIME_RESOLUTION_EVERY} == Seq{0}))
{
if (++iter != std::end(kLedgerPossibleTimeResolutions))
if (++iter != std::end(kLEDGER_POSSIBLE_TIME_RESOLUTIONS))
return *iter;
}
// If we previously agreed, we try to increase the resolution to determine
// if we can continue to agree.
if (previousAgree && (ledgerSeq % Seq{kIncreaseLedgerTimeResolutionEvery} == Seq{0}))
if (previousAgree && (ledgerSeq % Seq{kINCREASE_LEDGER_TIME_RESOLUTION_EVERY} == Seq{0}))
{
if (iter-- != std::begin(kLedgerPossibleTimeResolutions))
if (iter-- != std::begin(kLEDGER_POSSIBLE_TIME_RESOLUTIONS))
return *iter;
}

View File

@@ -23,7 +23,7 @@ namespace xrpl {
inline constexpr struct OpenLedgerT
{
explicit constexpr OpenLedgerT() = default;
} kOpenLedger{};
} kOPEN_LEDGER{};
/** Batch view construction tag.
@@ -33,7 +33,7 @@ inline constexpr struct OpenLedgerT
inline constexpr struct BatchViewT
{
explicit constexpr BatchViewT() = default;
} kBatchView{};
} kBATCH_VIEW{};
//------------------------------------------------------------------------------
@@ -47,7 +47,7 @@ private:
// Initial size for the monotonic_buffer_resource used for allocations
// The size was chosen from the old `qalloc` code (which this replaces).
// It is unclear how the size initially chosen in qalloc.
static constexpr size_t kInitialBufferSize = kilobytes(256);
static constexpr size_t kINITIAL_BUFFER_SIZE = kilobytes(256);
class TxsIterImpl;
@@ -139,7 +139,7 @@ public:
std::shared_ptr<void const> hold = nullptr);
OpenView(OpenLedgerT, Rules const& rules, std::shared_ptr<ReadView const> const& base)
: OpenView(kOpenLedger, &*base, rules, base)
: OpenView(kOPEN_LEDGER, &*base, rules, base)
{
}

View File

@@ -57,7 +57,7 @@ isVaultPseudoAccountFrozen(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptShare,
std::uint8_t depth);
int depth);
[[nodiscard]] bool
isLPTokenFrozen(

View File

@@ -19,16 +19,16 @@ public:
// Initial size for the monotonic_buffer_resource used for allocations
// The size was chosen from the old `qalloc` code (which this replaces).
// It is unclear how the size initially chosen in qalloc.
static constexpr size_t kInitialBufferSize = kilobytes(256);
static constexpr size_t kINITIAL_BUFFER_SIZE = kilobytes(256);
RawStateTable()
: monotonic_resource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
kInitialBufferSize)}
kINITIAL_BUFFER_SIZE)}
, items_{monotonic_resource_.get()} {};
RawStateTable(RawStateTable const& rhs)
: monotonic_resource_{std::make_unique<boost::container::pmr::monotonic_buffer_resource>(
kInitialBufferSize)}
kINITIAL_BUFFER_SIZE)}
, items_{rhs.items_, monotonic_resource_.get()}
, dropsDestroyed_{rhs.dropsDestroyed_} {};

View File

@@ -25,11 +25,11 @@ namespace detail {
Number
reduceOffer(auto const& amount)
{
static Number const kReducedOfferPct(9999, -4);
static Number const kREDUCED_OFFER_PCT(9999, -4);
// Make sure the result is always less than amount or zero.
NumberRoundModeGuard const mg(Number::RoundingMode::TowardsZero);
return amount * kReducedOfferPct;
return amount * kREDUCED_OFFER_PCT;
}
} // namespace detail
@@ -177,7 +177,7 @@ getAMMOfferStartWithTakerGets(
Quality const& targetQuality,
std::uint16_t const& tfee)
{
if (targetQuality.rate() == beast::kZero)
if (targetQuality.rate() == beast::kZERO)
return std::nullopt;
NumberRoundModeGuard const mg(Number::RoundingMode::ToNearest);
@@ -244,7 +244,7 @@ getAMMOfferStartWithTakerPays(
Quality const& targetQuality,
std::uint16_t tfee)
{
if (targetQuality.rate() == beast::kZero)
if (targetQuality.rate() == beast::kZERO)
return std::nullopt;
NumberRoundModeGuard const mg(Number::RoundingMode::ToNearest);

View File

@@ -19,10 +19,14 @@ namespace credentials {
// Check if credential sfExpiration field has passed ledger's parentCloseTime
bool
checkExpired(SLE const& sleCredential, NetClock::time_point const& closed);
checkExpired(std::shared_ptr<SLE const> const& sleCredential, NetClock::time_point const& closed);
// Return true if any expired credential was found in arr (and deleted)
bool
removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j);
// Actually remove a credentials object from the ledger
[[nodiscard]] TER
TER
deleteSLE(ApplyView& view, std::shared_ptr<SLE> const& sleCredential, beast::Journal j);
// Amendment and parameters checks for sfCredentialIDs field

View File

@@ -70,21 +70,21 @@ escrowUnlockApplyHelper<Issue>(
initialBalance.get<Issue>().account = noAccount();
if (TER const ter = trustCreate(
view, // payment sandbox
recvLow, // is dest low?
issuer, // source
receiver, // destination
trustLineKey.key, // ledger index
sleDest, // Account to add to
false, // authorize account
!sleDest->isFlag(lsfDefaultRipple), //
false, // freeze trust line
false, // deep freeze trust line
initialBalance, // zero initial balance
Issue(currency, receiver), // limit of zero
0, // quality in
0, // quality out
journal); // journal
view, // payment sandbox
recvLow, // is dest low?
issuer, // source
receiver, // destination
trustLineKey.key, // ledger index
sleDest, // Account to add to
false, // authorize account
(sleDest->getFlags() & lsfDefaultRipple) == 0, //
false, // freeze trust line
false, // deep freeze trust line
initialBalance, // zero initial balance
Issue(currency, receiver), // limit of zero
0, // quality in
0, // quality out
journal); // journal
!isTesSuccess(ter))
{
return ter; // LCOV_EXCL_LINE
@@ -111,7 +111,7 @@ escrowUnlockApplyHelper<Issue>(
// whereas in a normal payment, the transfer fee is taken on top of the
// sending amount.
auto finalAmt = amount;
if ((!senderIssuer && !receiverIssuer) && lockedRate != kParityRate)
if ((!senderIssuer && !receiverIssuer) && lockedRate != kPARITY_RATE)
{
// compute transfer fee, if any
auto const xferFee =
@@ -211,7 +211,7 @@ escrowUnlockApplyHelper<MPTIssue>(
// whereas in a normal payment, the transfer fee is taken on top of the
// sending amount.
auto finalAmt = amount;
if ((!senderIssuer && !receiverIssuer) && lockedRate != kParityRate)
if ((!senderIssuer && !receiverIssuer) && lockedRate != kPARITY_RATE)
{
// compute transfer fee, if any
auto const xferFee = amount.value() - divideRound(amount, lockedRate, amount.asset(), true);

View File

@@ -4,44 +4,13 @@
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/st.h>
#include <string_view>
namespace xrpl {
/**
* Broker cover preclaim precision guard (fixCleanup3_2_0).
*
* Prevents a "silent sub-ULP no-op" where a deposit, withdrawal, or clawback
* amount is so small that it rounds to zero at `sfCoverAvailable`'s scale.
* Without this guard, both the pseudo trust-line and `sfCoverAvailable` would
* identically absorb the rounded zero, resulting in a successful transaction
* (tesSUCCESS) where no funds actually moved.
*
* @param view Apply view (rules used for amendment gating).
* @param sleBroker The loan broker SLE (read-only).
* @param vaultAsset The underlying vault asset (the broker's cover asset).
* @param amount The effective subtraction/addition amount.
* @param j Journal for logging.
* @param logPrefix Transactor name for log diagnostics.
*
* @return `tecPRECISION_LOSS` if the request rounds to zero at cover scale.
* `tesSUCCESS` if the amendment is disabled, the amount is true zero,
* or the request is safely supra-ULP.
*/
[[nodiscard]] TER
canApplyToBrokerCover(
ReadView const& view,
SLE::const_ref sleBroker,
Asset const& vaultAsset,
STAmount const& amount,
beast::Journal j,
std::string_view logPrefix);
// Lending protocol has dependencies, so capture them here.
bool
checkLendingProtocolDependencies(Rules const& rules, STTx const& tx);
static constexpr std::uint32_t kSecondsInYear = 365 * 24 * 60 * 60;
static constexpr std::uint32_t kSECONDS_IN_YEAR = 365 * 24 * 60 * 60;
Number
loanPeriodicRate(TenthBips32 interestRate, std::uint32_t paymentInterval);
@@ -73,14 +42,14 @@ struct LoanPaymentParts
// The amount of principal paid that reduces the loan balance.
// This amount is subtracted from sfPrincipalOutstanding in the Loan object
// and paid to the Vault
Number principalPaid = kNumZero;
Number principalPaid = kNUM_ZERO;
// The total amount of interest paid to the Vault.
// This includes:
// - Tracked interest from the amortization schedule
// - Untracked interest (e.g., late payment penalty interest)
// This value is always non-negative.
Number interestPaid = kNumZero;
Number interestPaid = kNUM_ZERO;
// The change in the loan's total value outstanding.
// - If valueChange < 0: Loan value decreased
@@ -93,7 +62,7 @@ struct LoanPaymentParts
// - Late payments add penalty interest to the loan value
// - Early full payment may increase or decrease the loan value based on
// terms
Number valueChange = kNumZero;
Number valueChange = kNUM_ZERO;
/* The total amount of fees paid to the Broker.
* This includes:
@@ -101,7 +70,7 @@ struct LoanPaymentParts
* - Untracked fees (e.g., late payment fees, service fees, origination
* fees) This value is always non-negative.
*/
Number feePaid = kNumZero;
Number feePaid = kNUM_ZERO;
LoanPaymentParts&
operator+=(LoanPaymentParts const& other);
@@ -192,7 +161,7 @@ adjustImpreciseNumber(
{
value = roundToAsset(asset, value + adjustment, vaultScale);
if (*value < beast::kZero)
if (*value < beast::kZERO)
value = 0;
}
@@ -200,25 +169,10 @@ inline int
getAssetsTotalScale(SLE::const_ref vaultSle)
{
if (!vaultSle)
return Number::kMinExponent - 1; // LCOV_EXCL_LINE
return Number::kMIN_EXPONENT - 1; // LCOV_EXCL_LINE
return scale(vaultSle->at(sfAssetsTotal), vaultSle->at(sfAsset));
}
// Compute the minimum required broker cover, rounded consistently.
// DebtTotal is a broker-level aggregate maintained at vault scale, so the
// rounding must also use vault scale — never an individual loan's scale.
inline Number
minimumBrokerCover(
Asset const& asset,
Number const& debtTotal,
TenthBips32 coverRateMinimum,
SLE::const_ref vaultSle)
{
NumberRoundModeGuard const mg(Number::RoundingMode::Upward);
return roundToAsset(
asset, tenthBipsOfValue(debtTotal, coverRateMinimum), getAssetsTotalScale(vaultSle));
}
TER
checkLoanGuards(
Asset const& vaultAsset,
@@ -230,7 +184,6 @@ checkLoanGuards(
LoanState
computeTheoreticalLoanState(
Rules const& rules,
Number const& periodicPayment,
Number const& periodicRate,
std::uint32_t const paymentRemaining,
@@ -357,7 +310,7 @@ struct ExtendedPaymentComponents : public PaymentComponents
// borrower is sufficient to cover all components of the payment.
Number totalDue;
ExtendedPaymentComponents(PaymentComponents const& p, Number fee, Number interest = kNumZero)
ExtendedPaymentComponents(PaymentComponents const& p, Number fee, Number interest = kNUM_ZERO)
: PaymentComponents(p)
, untrackedManagementFee(fee)
, untrackedInterest(interest)
@@ -400,7 +353,6 @@ struct LoanStateDeltas
Expected<std::pair<LoanPaymentParts, LoanProperties>, TER>
tryOverpayment(
Rules const& rules,
Asset const& asset,
std::int32_t loanScale,
ExtendedPaymentComponents const& overpaymentComponents,
@@ -411,17 +363,11 @@ tryOverpayment(
TenthBips16 const managementFeeRate,
beast::Journal j);
[[nodiscard]] Number
computePowerMinusOne(Number const& periodicRate, std::uint32_t paymentsRemaining);
Number
computeRaisedRate(Number const& periodicRate, std::uint32_t paymentsRemaining);
[[nodiscard]] Number
computePowerMinusOneHybrid(Number const& periodicRate, std::uint32_t paymentsRemaining);
[[nodiscard]] Number
computePaymentFactor(
Rules const& rules,
Number const& periodicRate,
std::uint32_t paymentsRemaining);
Number
computePaymentFactor(Number const& periodicRate, std::uint32_t paymentsRemaining);
std::pair<Number, Number>
computeInterestAndFeeParts(
@@ -432,14 +378,12 @@ computeInterestAndFeeParts(
Number
loanPeriodicPayment(
Rules const& rules,
Number const& principalOutstanding,
Number const& periodicRate,
std::uint32_t paymentsRemaining);
Number
loanPrincipalFromPeriodicPayment(
Rules const& rules,
Number const& periodicPayment,
Number const& periodicRate,
std::uint32_t paymentsRemaining);
@@ -471,7 +415,6 @@ computeOverpaymentComponents(
PaymentComponents
computePaymentComponents(
Rules const& rules,
Asset const& asset,
std::int32_t scale,
Number const& totalValueOutstanding,
@@ -495,7 +438,6 @@ operator+(LoanState const& lhs, detail::LoanStateDeltas const& rhs);
LoanProperties
computeLoanProperties(
Rules const& rules,
Asset const& asset,
Number const& principalOutstanding,
TenthBips32 interestRate,
@@ -506,7 +448,6 @@ computeLoanProperties(
LoanProperties
computeLoanProperties(
Rules const& rules,
Asset const& asset,
Number const& principalOutstanding,
Number const& periodicRate,

View File

@@ -27,18 +27,14 @@ isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue);
isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue);
[[nodiscard]] bool
isFrozen(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue,
std::uint8_t depth = 0);
isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth = 0);
[[nodiscard]] bool
isAnyFrozen(
ReadView const& view,
std::initializer_list<AccountID> const& accounts,
MPTIssue const& mptIssue,
std::uint8_t depth = 0);
int depth = 0);
//------------------------------------------------------------------------------
//
@@ -92,7 +88,7 @@ requireAuth(
MPTIssue const& mptIssue,
AccountID const& account,
AuthType authType = AuthType::Legacy,
std::uint8_t depth = 0);
int depth = 0);
/** Enforce account has MPToken to match its authorization.
*
@@ -108,68 +104,22 @@ enforceMPTokenAuthorization(
XRPAmount const& priorBalance,
beast::Journal j);
/** Resolve the underlying asset of a vault share.
*
* Reads sfReferenceHolding from @p sleShareIssuance to determine which
* asset the vault wraps. @p sleHolding must be the SLE that
* sfReferenceHolding points to — either an ltMPTOKEN (returns its
* MPTIssue) or an ltRIPPLE_STATE (returns its low/high Issue).
*
* @pre Both SLEs must exist and @p sleHolding must be of type ltMPTOKEN
* or ltRIPPLE_STATE. Passing any other type is undefined behaviour.
* @param sleShareIssuance MPTokenIssuance SLE for the vault share token.
* @param sleHolding SLE referenced by sfReferenceHolding.
* @return The underlying Asset (MPTIssue or Issue).
*/
[[nodiscard]] Asset
assetOfHolding(SLE const& sleShareIssuance, SLE const& sleHolding);
/** Check whether @p to may receive the given MPT from @p from.
*
* The check passes when any of the following is true:
* - @p waive is WaiveMPTCanTransfer::Yes (recovery-path exemption), or
* - @p from or @p to is the issuer, or
* - lsfMPTCanTransfer is set on the MPTokenIssuance.
*
* For vault shares (MPTokenIssuances that carry sfReferenceHolding) the
* check recurses into the underlying asset's transferability. This
* recursion is defensive; vault-of-vault-shares is rejected at vault
* creation, so in practice depth never exceeds 1.
*
* @param view Ledger state to read from.
* @param mptIssue The MPT issuance being transferred.
* @param from Sending account.
* @param to Receiving account.
* @param waive WaiveMPTCanTransfer::Yes skips the lsfMPTCanTransfer
* check. Use for recovery paths (e.g. unwinding SAV or
* Lending Protocol positions after an issuer revokes
* transferability).
* @param depth Recursion depth; bounded at kMaxAssetCheckDepth.
* @return tesSUCCESS if the transfer is allowed, tecNO_AUTH otherwise.
/** Check if the destination account is allowed
* to receive MPT. Return tecNO_AUTH if it doesn't
* and tesSUCCESS otherwise.
*/
[[nodiscard]] TER
canTransfer(
ReadView const& view,
MPTIssue const& mptIssue,
AccountID const& from,
AccountID const& to,
WaiveMPTCanTransfer waive = WaiveMPTCanTransfer::No,
std::uint8_t depth = 0);
AccountID const& to);
/** Check whether @p asset may be traded on the DEX.
*
* For IOU assets the check delegates to the existing offer/AMM freeze
* logic. For MPT assets it checks lsfMPTCanTrade on the MPTokenIssuance.
* Vault shares recurse into the underlying asset's tradability via
* sfReferenceHolding; depth is bounded at kMaxAssetCheckDepth.
*
* @param view Ledger state to read from.
* @param asset The asset to check.
* @param depth Recursion depth; bounded at kMaxAssetCheckDepth.
* @return tesSUCCESS if trading is allowed, tecNO_PERMISSION otherwise.
/** Check if Asset can be traded on DEX. return tecNO_PERMISSION
* if it doesn't and tesSUCCESS otherwise.
*/
[[nodiscard]] TER
canTrade(ReadView const& view, Asset const& asset, std::uint8_t depth = 0);
canTrade(ReadView const& view, Asset const& asset);
//------------------------------------------------------------------------------
//

View File

@@ -93,7 +93,7 @@ isFrozen(ReadView const& view, AccountID const& account, Issue const& issue)
// Overload with depth parameter for uniformity with MPTIssue version.
// The depth parameter is ignored for IOUs since they don't have vault recursion.
[[nodiscard]] inline bool
isFrozen(ReadView const& view, AccountID const& account, Issue const& issue, std::uint8_t /*depth*/)
isFrozen(ReadView const& view, AccountID const& account, Issue const& issue, int /*depth*/)
{
return isFrozen(view, account, issue);
}
@@ -110,7 +110,7 @@ isDeepFrozen(
ReadView const& view,
AccountID const& account,
Issue const& issue,
std::uint8_t = 0 /*ignored*/)
int = 0 /*ignored*/)
{
return isDeepFrozen(view, account, issue.currency, issue.account);
}

View File

@@ -34,15 +34,6 @@ enum class WaiveTransferFee : bool { No = false, Yes };
/** Controls whether accountSend is allowed to overflow OutstandingAmount **/
enum class AllowMPTOverflow : bool { No = false, Yes };
/** Controls whether canTransfer enforces lsfMPTCanTransfer on MPTs.
*
* Default is No (enforce). Use Yes at call sites that must remain available
* even when an MPT issuer has cleared lsfMPTCanTransfer - for example,
* unwinding existing positions in SAV or the Lending Protocol. Has no
* effect on the IOU branch of canTransfer.
*/
enum class WaiveMPTCanTransfer : bool { No = false, Yes };
/* Check if MPToken (for MPT) or trust line (for IOU) exists:
* - StrongAuth - before checking if authorization is required
* - WeakAuth
@@ -72,11 +63,7 @@ isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const&
* purely defensive, as we currently do not allow such vaults to be created.
*/
[[nodiscard]] bool
isFrozen(
ReadView const& view,
AccountID const& account,
Asset const& asset,
std::uint8_t depth = 0);
isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0);
[[nodiscard]] TER
checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue);
@@ -98,14 +85,14 @@ isAnyFrozen(
ReadView const& view,
std::initializer_list<AccountID> const& accounts,
Asset const& asset,
std::uint8_t depth = 0);
int depth = 0);
[[nodiscard]] bool
isDeepFrozen(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptIssue,
std::uint8_t depth = 0);
int depth = 0);
/**
* isFrozen check is recursive for MPT shares in a vault, descending to
@@ -113,11 +100,7 @@ isDeepFrozen(
* purely defensive, as we currently do not allow such vaults to be created.
*/
[[nodiscard]] bool
isDeepFrozen(
ReadView const& view,
AccountID const& account,
Asset const& asset,
std::uint8_t depth = 0);
isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0);
[[nodiscard]] TER
checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue);
@@ -251,13 +234,7 @@ requireAuth(
AuthType authType = AuthType::Legacy);
[[nodiscard]] TER
canTransfer(
ReadView const& view,
Asset const& asset,
AccountID const& from,
AccountID const& to,
WaiveMPTCanTransfer waive = WaiveMPTCanTransfer::No,
std::uint8_t depth = 0);
canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, AccountID const& to);
//------------------------------------------------------------------------------
//

View File

@@ -1,7 +1,5 @@
#pragma once
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -45,14 +43,6 @@ sharesToAssetsDeposit(
/** Controls whether to truncate shares instead of rounding. */
enum class TruncateShares : bool { No = false, Yes = true };
/** Controls whether the withdraw conversion helpers
(assetsToSharesWithdraw and sharesToAssetsWithdraw) subtract
sfLossUnrealized from sfAssetsTotal before computing the exchange rate.
The default (No) applies the standard discounted rate; Yes is used when
the redeemer is the sole remaining shareholder.
*/
enum class WaiveUnrealizedLoss : bool { No = false, Yes = true };
/** From the perspective of a vault, return the number of shares to demand from
the depositor when they ask to withdraw a fixed amount of assets. Since
shares are MPT this number is integral, and it will be rounded to nearest
@@ -62,8 +52,6 @@ enum class WaiveUnrealizedLoss : bool { No = false, Yes = true };
@param issuance The MPTokenIssuance SLE for the vault's shares.
@param assets The amount of assets to convert.
@param truncate Whether to truncate instead of rounding.
@param waive Whether to waive the unrealized-loss discount when computing
the exchange rate.
@return The number of shares, or nullopt on error.
*/
@@ -72,8 +60,7 @@ assetsToSharesWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets,
TruncateShares truncate = TruncateShares::No,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
TruncateShares truncate = TruncateShares::No);
/** From the perspective of a vault, return the number of assets to give the
depositor when they redeem a fixed amount of shares. Note, since shares are
@@ -82,8 +69,6 @@ assetsToSharesWithdraw(
@param vault The vault SLE.
@param issuance The MPTokenIssuance SLE for the vault's shares.
@param shares The amount of shares to convert.
@param waive Whether to waive (i.e. not subtract) the vault's unrealized
loss when computing the exchange rate.
@return The number of assets, or nullopt on error.
*/
@@ -91,22 +76,6 @@ assetsToSharesWithdraw(
sharesToAssetsWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
/** Returns true iff `account` holds all of the vault's outstanding shares —
i.e. is the sole remaining shareholder. Returns false if the account
holds no shares or fewer than the total outstanding.
@param view The ledger view.
@param account The candidate sole shareholder.
@param issuance The MPTokenIssuance SLE for the vault's shares; provides
both the share MPTID and the outstanding-amount total.
*/
[[nodiscard]] bool
isSoleShareholder(
ReadView const& view,
AccountID const& account,
std::shared_ptr<SLE const> const& issuance);
STAmount const& shares);
} // namespace xrpl

View File

@@ -20,7 +20,7 @@ class HTTPClient
public:
explicit HTTPClient() = default;
static constexpr auto kMaxClientHeaderBytes = kilobytes(32);
static constexpr auto kMAX_CLIENT_HEADER_BYTES = kilobytes(32);
static void
initializeSSLContext(

View File

@@ -29,7 +29,7 @@ enum class NodeObjectType : std::uint32_t {
class NodeObject : public CountedObject<NodeObject>
{
public:
static constexpr std::size_t kKeyBytes = 32;
static constexpr std::size_t kKEY_BYTES = 32;
private:
// This hack is used to make the constructor effectively private

View File

@@ -6,16 +6,20 @@
namespace xrpl::NodeStore {
// This is only used to pre-allocate the array for
// batch objects and does not affect the amount written.
//
static constexpr auto kBatchWritePreallocationSize = 256;
// Need to be named before converting
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum {
// This is only used to pre-allocate the array for
// batch objects and does not affect the amount written.
//
BatchWritePreallocationSize = 256,
// This sets a limit on the maximum number of writes
// in a batch. Actual usage can be twice this since
// we have a new batch growing as we write the old.
//
static constexpr auto kBatchWriteLimitSize = 65536;
// This sets a limit on the maximum number of writes
// in a batch. Actual usage can be twice this since
// we have a new batch growing as we write the old.
//
BatchWriteLimitSize = 65536
};
/** Return codes from Backend operations. */
enum class Status {

View File

@@ -55,7 +55,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
using std::runtime_error;
using namespace nudb::detail;
std::pair<void const*, std::size_t> result;
std::array<std::uint8_t, varint_traits<std::size_t>::kMax> vi{};
std::array<std::uint8_t, varint_traits<std::size_t>::kMAX> vi{};
auto const n = writeVarint(vi.data(), inSize);
auto const outMax = LZ4_compressBound(inSize);
std::uint8_t* out = reinterpret_cast<std::uint8_t*>(bf(n + outMax));
@@ -254,12 +254,12 @@ nodeobjectCompress(void const* in, std::size_t inSize, BufferFactory&& bf)
}
}
std::array<std::uint8_t, varint_traits<std::size_t>::kMax> vi{};
std::array<std::uint8_t, varint_traits<std::size_t>::kMAX> vi{};
static constexpr std::size_t kCodecType = 1;
auto const vn = writeVarint(vi.data(), kCodecType);
constexpr std::size_t kCODEC_TYPE = 1;
auto const vn = writeVarint(vi.data(), kCODEC_TYPE);
std::pair<void const*, std::size_t> result;
switch (kCodecType)
switch (kCODEC_TYPE)
{
// case 0 was uncompressed data; we always compress now.
case 1: // lz4
@@ -275,7 +275,7 @@ nodeobjectCompress(void const* in, std::size_t inSize, BufferFactory&& bf)
break;
}
default:
Throw<std::logic_error>("nodeobject codec: unknown=" + std::to_string(kCodecType));
Throw<std::logic_error>("nodeobject codec: unknown=" + std::to_string(kCODEC_TYPE));
};
return result;
}

View File

@@ -25,7 +25,7 @@ struct varint_traits<T, true>
{
explicit varint_traits() = default;
static constexpr std::size_t kMax = (8 * sizeof(T) + 6) / 7;
static std::size_t constexpr kMAX = (8 * sizeof(T) + 6) / 7;
};
// Returns: Number of bytes consumed or 0 on error,

View File

@@ -8,21 +8,21 @@
namespace xrpl {
constexpr std::uint16_t kTradingFeeThreshold = 1000; // 1%
std::uint16_t constexpr kTRADING_FEE_THRESHOLD = 1000; // 1%
// Auction slot
constexpr std::uint32_t kTotalTimeSlotSecs = 24 * 3600;
constexpr std::uint16_t kAuctionSlotTimeIntervals = 20;
constexpr std::uint16_t kAuctionSlotMaxAuthAccounts = 4;
constexpr std::uint32_t kAuctionSlotFeeScaleFactor = 100000;
constexpr std::uint32_t kAuctionSlotDiscountedFeeFraction = 10;
constexpr std::uint32_t kAuctionSlotMinFeeFraction = 25;
constexpr std::uint32_t kAuctionSlotIntervalDuration =
kTotalTimeSlotSecs / kAuctionSlotTimeIntervals;
std::uint32_t constexpr kTOTAL_TIME_SLOT_SECS = 24 * 3600;
std::uint16_t constexpr kAUCTION_SLOT_TIME_INTERVALS = 20;
std::uint16_t constexpr kAUCTION_SLOT_MAX_AUTH_ACCOUNTS = 4;
std::uint32_t constexpr kAUCTION_SLOT_FEE_SCALE_FACTOR = 100000;
std::uint32_t constexpr kAUCTION_SLOT_DISCOUNTED_FEE_FRACTION = 10;
std::uint32_t constexpr kAUCTION_SLOT_MIN_FEE_FRACTION = 25;
std::uint32_t constexpr kAUCTION_SLOT_INTERVAL_DURATION =
kTOTAL_TIME_SLOT_SECS / kAUCTION_SLOT_TIME_INTERVALS;
// Votes
constexpr std::uint16_t kVoteMaxSlots = 8;
constexpr std::uint32_t kVoteWeightScaleFactor = 100000;
std::uint16_t constexpr kVOTE_MAX_SLOTS = 8;
std::uint32_t constexpr kVOTE_WEIGHT_SCALE_FACTOR = 100000;
class STObject;
class STAmount;
@@ -45,7 +45,6 @@ ammLPTIssue(Asset const& asset1, Asset const& asset2, AccountID const& ammAccoun
*/
NotTEC
invalidAMMAmount(
Rules const& rules,
STAmount const& amount,
std::optional<std::pair<Asset, Asset>> const& pair = std::nullopt,
bool validZero = false);
@@ -78,7 +77,7 @@ ammEnabled(Rules const&);
inline Number
getFee(std::uint16_t tfee)
{
return Number{tfee} / kAuctionSlotFeeScaleFactor;
return Number{tfee} / kAUCTION_SLOT_FEE_SCALE_FACTOR;
}
/** Get fee multiplier (1 - tfee)

View File

@@ -25,7 +25,7 @@ public:
} // namespace detail
/** A 160-bit unsigned that uniquely identifies an account. */
using AccountID = BaseUInt<160, detail::AccountIDTag>;
using AccountID = BaseUint<160, detail::AccountIDTag>;
/** Convert AccountID to base58 checked string */
std::string
@@ -69,7 +69,7 @@ toIssuer(AccountID&, std::string const&);
inline bool
isXRP(AccountID const& c)
{
return c == beast::kZero;
return c == beast::kZERO;
}
// DEPRECATED

View File

@@ -96,9 +96,9 @@ inline MPTAmount
toAmount<MPTAmount>(STAmount const& amt)
{
XRPL_ASSERT(
amt.holds<MPTIssue>() && amt.mantissa() <= kMaxMpTokenAmount && amt.exponent() == 0,
amt.holds<MPTIssue>() && amt.mantissa() <= kMAX_MP_TOKEN_AMOUNT && amt.exponent() == 0,
"xrpl::toAmount<MPTAmount> : maximum mantissa");
if (amt.mantissa() > kMaxMpTokenAmount || amt.exponent() != 0)
if (amt.mantissa() > kMAX_MP_TOKEN_AMOUNT || amt.exponent() != 0)
Throw<std::runtime_error>("toAmount<MPTAmount>: invalid mantissa or exponent");
bool const isNeg = amt.negative();
std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa();
@@ -167,8 +167,8 @@ toAmount(Asset const& asset, Number const& n, Number::RoundingMode mode = Number
}
else
{
static constexpr bool kAlwaysFalse = !std::is_same_v<T, T>;
static_assert(kAlwaysFalse, "Unsupported type for toAmount");
constexpr bool kALWAYS_FALSE = !std::is_same_v<T, T>;
static_assert(kALWAYS_FALSE, "Unsupported type for toAmount");
}
}
@@ -178,30 +178,30 @@ toMaxAmount(Asset const& asset)
{
if constexpr (std::is_same_v<IOUAmount, T>)
{
return IOUAmount(STAmount::kMaxValue, STAmount::kMaxOffset);
return IOUAmount(STAmount::kMAX_VALUE, STAmount::kMAX_OFFSET);
}
else if constexpr (std::is_same_v<XRPAmount, T>)
{
return XRPAmount(static_cast<std::int64_t>(STAmount::kMaxNativeN));
return XRPAmount(static_cast<std::int64_t>(STAmount::kMAX_NATIVE_N));
}
else if constexpr (std::is_same_v<MPTAmount, T>)
{
return MPTAmount(kMaxMpTokenAmount);
return MPTAmount(kMAX_MP_TOKEN_AMOUNT);
}
else if constexpr (std::is_same_v<STAmount, T>)
{
return asset.visit(
[](Issue const& issue) {
if (isXRP(issue))
return STAmount(issue, static_cast<std::int64_t>(STAmount::kMaxNativeN));
return STAmount(issue, STAmount::kMaxValue, STAmount::kMaxOffset);
return STAmount(issue, static_cast<std::int64_t>(STAmount::kMAX_NATIVE_N));
return STAmount(issue, STAmount::kMAX_VALUE, STAmount::kMAX_OFFSET);
},
[](MPTIssue const& issue) { return STAmount(issue, kMaxMpTokenAmount); });
[](MPTIssue const& issue) { return STAmount(issue, kMAX_MP_TOKEN_AMOUNT); });
}
else
{
static constexpr bool kAlwaysFalse = !std::is_same_v<T, T>;
static_assert(kAlwaysFalse, "Unsupported type for toMaxAmount");
constexpr bool kALWAYS_FALSE = !std::is_same_v<T, T>;
static_assert(kALWAYS_FALSE, "Unsupported type for toMaxAmount");
}
}
@@ -233,8 +233,8 @@ getAsset(T const& amt)
}
else
{
static constexpr bool kAlwaysFalse = !std::is_same_v<T, T>;
static_assert(kAlwaysFalse, "Unsupported type for getIssue");
constexpr bool kALWAYS_FALSE = !std::is_same_v<T, T>;
static_assert(kALWAYS_FALSE, "Unsupported type for getIssue");
}
}
@@ -260,8 +260,8 @@ get(STAmount const& a)
}
else
{
constexpr bool kAlwaysFalse = !std::is_same_v<T, T>;
static_assert(kAlwaysFalse, "Unsupported type for get");
constexpr bool kALWAYS_FALSE = !std::is_same_v<T, T>;
static_assert(kALWAYS_FALSE, "Unsupported type for get");
}
}

View File

@@ -35,49 +35,49 @@ namespace xrpl {
namespace RPC {
template <unsigned int Version>
static constexpr std::integral_constant<unsigned, Version> kApiVersion = {};
constexpr static std::integral_constant<unsigned, Version> kAPI_VERSION = {};
static constexpr auto kApiInvalidVersion = kApiVersion<0>;
static constexpr auto kApiMinimumSupportedVersion = kApiVersion<1>;
static constexpr auto kApiMaximumSupportedVersion = kApiVersion<2>;
static constexpr auto kApiVersionIfUnspecified = kApiVersion<1>;
static constexpr auto kApiCommandLineVersion = kApiVersion<1>; // TODO Bump to 2 later
static constexpr auto kApiBetaVersion = kApiVersion<3>;
static constexpr auto kApiMaximumValidVersion = kApiBetaVersion;
constexpr static auto kAPI_INVALID_VERSION = kAPI_VERSION<0>;
constexpr static auto kAPI_MINIMUM_SUPPORTED_VERSION = kAPI_VERSION<1>;
constexpr static auto kAPI_MAXIMUM_SUPPORTED_VERSION = kAPI_VERSION<2>;
constexpr static auto kAPI_VERSION_IF_UNSPECIFIED = kAPI_VERSION<1>;
constexpr static auto kAPI_COMMAND_LINE_VERSION = kAPI_VERSION<1>; // TODO Bump to 2 later
constexpr static auto kAPI_BETA_VERSION = kAPI_VERSION<3>;
constexpr static auto kAPI_MAXIMUM_VALID_VERSION = kAPI_BETA_VERSION;
static_assert(kApiInvalidVersion < kApiMinimumSupportedVersion);
static_assert(kAPI_INVALID_VERSION < kAPI_MINIMUM_SUPPORTED_VERSION);
static_assert(
kApiVersionIfUnspecified >= kApiMinimumSupportedVersion &&
kApiVersionIfUnspecified <= kApiMaximumSupportedVersion);
kAPI_VERSION_IF_UNSPECIFIED >= kAPI_MINIMUM_SUPPORTED_VERSION &&
kAPI_VERSION_IF_UNSPECIFIED <= kAPI_MAXIMUM_SUPPORTED_VERSION);
static_assert(
kApiCommandLineVersion >= kApiMinimumSupportedVersion &&
kApiCommandLineVersion <= kApiMaximumSupportedVersion);
static_assert(kApiMaximumSupportedVersion >= kApiMinimumSupportedVersion);
static_assert(kApiBetaVersion >= kApiMaximumSupportedVersion);
static_assert(kApiMaximumValidVersion >= kApiMaximumSupportedVersion);
kAPI_COMMAND_LINE_VERSION >= kAPI_MINIMUM_SUPPORTED_VERSION &&
kAPI_COMMAND_LINE_VERSION <= kAPI_MAXIMUM_SUPPORTED_VERSION);
static_assert(kAPI_MAXIMUM_SUPPORTED_VERSION >= kAPI_MINIMUM_SUPPORTED_VERSION);
static_assert(kAPI_BETA_VERSION >= kAPI_MAXIMUM_SUPPORTED_VERSION);
static_assert(kAPI_MAXIMUM_VALID_VERSION >= kAPI_MAXIMUM_SUPPORTED_VERSION);
inline void
setVersion(json::Value& parent, unsigned int apiVersion, bool betaEnabled)
{
XRPL_ASSERT(apiVersion != kApiInvalidVersion, "xrpl::RPC::setVersion : input is valid");
XRPL_ASSERT(apiVersion != kAPI_INVALID_VERSION, "xrpl::RPC::setVersion : input is valid");
auto& retObj = parent[jss::version] = json::ValueType::Object;
auto& retObj = parent[jss::version] = json::ObjectValue;
if (apiVersion == kApiVersionIfUnspecified)
if (apiVersion == kAPI_VERSION_IF_UNSPECIFIED)
{
// API version numbers used in API version 1
static beast::SemanticVersion const kFirstVersion{"1.0.0"};
static beast::SemanticVersion const kGoodVersion{"1.0.0"};
static beast::SemanticVersion const kLastVersion{"1.0.0"};
static beast::SemanticVersion const kFIRST_VERSION{"1.0.0"};
static beast::SemanticVersion const kGOOD_VERSION{"1.0.0"};
static beast::SemanticVersion const kLAST_VERSION{"1.0.0"};
retObj[jss::first] = kFirstVersion.print();
retObj[jss::good] = kGoodVersion.print();
retObj[jss::last] = kLastVersion.print();
retObj[jss::first] = kFIRST_VERSION.print();
retObj[jss::good] = kGOOD_VERSION.print();
retObj[jss::last] = kLAST_VERSION.print();
}
else
{
retObj[jss::first] = kApiMinimumSupportedVersion.value;
retObj[jss::last] = betaEnabled ? kApiBetaVersion : kApiMaximumSupportedVersion;
retObj[jss::first] = kAPI_MINIMUM_SUPPORTED_VERSION.value;
retObj[jss::last] = betaEnabled ? kAPI_BETA_VERSION : kAPI_MAXIMUM_SUPPORTED_VERSION;
}
}
@@ -98,9 +98,9 @@ setVersion(json::Value& parent, unsigned int apiVersion, bool betaEnabled)
inline unsigned int
getAPIVersionNumber(json::Value const& jv, bool betaEnabled)
{
static json::Value const kMinVersion(RPC::kApiMinimumSupportedVersion);
static json::Value const kMIN_VERSION(RPC::kAPI_MINIMUM_SUPPORTED_VERSION);
json::Value const maxVersion(
betaEnabled ? RPC::kApiBetaVersion : RPC::kApiMaximumSupportedVersion);
betaEnabled ? RPC::kAPI_BETA_VERSION : RPC::kAPI_MAXIMUM_SUPPORTED_VERSION);
if (jv.isObject())
{
@@ -109,18 +109,18 @@ getAPIVersionNumber(json::Value const& jv, bool betaEnabled)
auto const specifiedVersion = jv[jss::api_version];
if (!specifiedVersion.isInt() && !specifiedVersion.isUInt())
{
return RPC::kApiInvalidVersion;
return RPC::kAPI_INVALID_VERSION;
}
auto const specifiedVersionInt = specifiedVersion.asInt();
if (specifiedVersionInt < kMinVersion || specifiedVersionInt > maxVersion)
if (specifiedVersionInt < kMIN_VERSION || specifiedVersionInt > maxVersion)
{
return RPC::kApiInvalidVersion;
return RPC::kAPI_INVALID_VERSION;
}
return specifiedVersionInt;
}
}
return RPC::kApiVersionIfUnspecified;
return RPC::kAPI_VERSION_IF_UNSPECIFIED;
}
} // namespace RPC
@@ -128,33 +128,33 @@ getAPIVersionNumber(json::Value const& jv, bool betaEnabled)
template <unsigned MinVer, unsigned MaxVer, typename Fn, typename... Args>
void
forApiVersions(Fn const& fn, Args&&... args)
requires //
(MaxVer >= MinVer) && //
(MinVer >= RPC::kApiMinimumSupportedVersion) && //
(RPC::kApiMaximumValidVersion >= MaxVer) && requires {
requires //
(MaxVer >= MinVer) && //
(MinVer >= RPC::kAPI_MINIMUM_SUPPORTED_VERSION) && //
(RPC::kAPI_MAXIMUM_VALID_VERSION >= MaxVer) && requires {
fn(std::integral_constant<unsigned int, MinVer>{}, std::forward<Args>(args)...);
fn(std::integral_constant<unsigned int, MaxVer>{}, std::forward<Args>(args)...);
}
{
static constexpr auto kSize = MaxVer + 1 - MinVer;
constexpr auto kSIZE = MaxVer + 1 - MinVer;
[&]<std::size_t... Offset>(std::index_sequence<Offset...>) {
// NOLINTBEGIN(bugprone-use-after-move)
(((void)fn(
std::integral_constant<unsigned int, MinVer + Offset>{}, std::forward<Args>(args)...)),
...);
// NOLINTEND(bugprone-use-after-move)
}(std::make_index_sequence<kSize>{});
}(std::make_index_sequence<kSIZE>{});
}
template <typename Fn, typename... Args>
void
forAllApiVersions(Fn const& fn, Args&&... args)
requires requires {
forApiVersions<RPC::kApiMinimumSupportedVersion, RPC::kApiMaximumValidVersion>(
forApiVersions<RPC::kAPI_MINIMUM_SUPPORTED_VERSION, RPC::kAPI_MAXIMUM_VALID_VERSION>(
fn, std::forward<Args>(args)...);
}
{
forApiVersions<RPC::kApiMinimumSupportedVersion, RPC::kApiMaximumValidVersion>(
forApiVersions<RPC::kAPI_MINIMUM_SUPPORTED_VERSION, RPC::kAPI_MAXIMUM_VALID_VERSION>(
fn, std::forward<Args>(args)...);
}

View File

@@ -148,10 +148,10 @@ public:
};
template <ValidIssueType TIss>
constexpr bool kIsIssueV = std::is_same_v<TIss, Issue>;
constexpr bool kIS_ISSUE_V = std::is_same_v<TIss, Issue>;
template <ValidIssueType TIss>
constexpr bool kIsMptissueV = std::is_same_v<TIss, MPTIssue>;
constexpr bool kIS_MPTISSUE_V = std::is_same_v<TIss, MPTIssue>;
inline json::Value
toJson(Asset const& asset)
@@ -242,7 +242,7 @@ operator<=>(Asset const& lhs, Asset const& rhs)
{
return std::weak_ordering(lhs <=> rhs);
}
else if constexpr (kIsIssueV<TLhs> && kIsMptissueV<TRhs>)
else if constexpr (kIS_ISSUE_V<TLhs> && kIS_MPTISSUE_V<TRhs>)
{
return std::weak_ordering::greater;
}

Some files were not shown because too many files have changed in this diff Show More