diff --git a/.clang-tidy b/.clang-tidy index b23d7ccbff..2d72eae701 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -154,7 +154,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 +# readability-static-accessed-through-instance, # this check is probably unnecessary. It makes the code less readable # --- CheckOptions: diff --git a/.gersemi/definitions.cmake b/.gersemi/definitions.cmake index a16e330ffa..245f827f90 100644 --- a/.gersemi/definitions.cmake +++ b/.gersemi/definitions.cmake @@ -11,9 +11,6 @@ endfunction() function(create_symbolic_link target link) endfunction() -function(xrpl_add_test name) -endfunction() - macro(exclude_from_default target_) endmacro() diff --git a/.github/actions/build-deps/action.yml b/.github/actions/build-deps/action.yml index 0891d56dfa..044c264ef0 100644 --- a/.github/actions/build-deps/action.yml +++ b/.github/actions/build-deps/action.yml @@ -35,9 +35,8 @@ runs: LOG_VERBOSITY: ${{ inputs.log_verbosity }} SANITIZERS: ${{ inputs.sanitizers }} run: | - echo 'Installing dependencies.' conan install \ - --profile ci \ + --profile:all ci \ --build="${BUILD_OPTION}" \ --options:host='&:tests=True' \ --options:host='&:xrpld=True' \ diff --git a/.github/actions/set-compiler-env/action.yml b/.github/actions/set-compiler-env/action.yml new file mode 100644 index 0000000000..a16dde2b30 --- /dev/null +++ b/.github/actions/set-compiler-env/action.yml @@ -0,0 +1,34 @@ +name: Set compiler environment +description: "Set CC and CXX environment variables for the given compiler." + +inputs: + compiler: + description: 'The compiler to use ("gcc" or "clang").' + required: true + +runs: + using: composite + + steps: + - name: Set CC and CXX for gcc + if: ${{ inputs.compiler == 'gcc' }} + shell: bash + run: | + echo "CC=gcc" >>"${GITHUB_ENV}" + echo "CXX=g++" >>"${GITHUB_ENV}" + + - name: Set CC and CXX for clang + if: ${{ inputs.compiler == 'clang' }} + shell: bash + run: | + echo "CC=clang" >>"${GITHUB_ENV}" + echo "CXX=clang++" >>"${GITHUB_ENV}" + + - name: Fail on unknown compiler + if: ${{ inputs.compiler != 'gcc' && inputs.compiler != 'clang' }} + shell: bash + env: + COMPILER: ${{ inputs.compiler }} + run: | + echo "Unknown compiler: $COMPILER" >&2 + exit 1 diff --git a/.github/actions/setup-conan/action.yml b/.github/actions/setup-conan/action.yml index 9d834884d2..0dd22f0d92 100644 --- a/.github/actions/setup-conan/action.yml +++ b/.github/actions/setup-conan/action.yml @@ -15,32 +15,35 @@ runs: using: composite steps: - - name: Set up Conan configuration + - name: Apply custom configuration to global.conf shell: bash run: | - echo 'Installing configuration.' cat conan/global.conf ${{ runner.os == 'Linux' && '>>' || '>' }} $(conan config home)/global.conf - echo 'Conan configuration:' - conan config show '*' - - - name: Set up Conan profile + - name: Show global configuration + shell: bash + run: | + conan config show '*' + + - name: Install profiles shell: bash run: | - echo 'Installing profile.' conan config install conan/profiles/ -tf $(conan config home)/profiles/ - echo 'Conan profile:' + - name: Show CI profile + shell: bash + run: | conan profile show --profile ci - - name: Set up Conan remote + - name: Add a remote shell: bash env: REMOTE_NAME: ${{ inputs.remote_name }} REMOTE_URL: ${{ inputs.remote_url }} run: | - echo "Adding Conan remote '${REMOTE_NAME}' at '${REMOTE_URL}'." conan remote add --index 0 --force "${REMOTE_NAME}" "${REMOTE_URL}" - echo 'Listing Conan remotes.' + - name: List remotes + shell: bash + run: | conan remote list diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0e6b840fe7..da7a30dc77 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,40 +1,12 @@ version: 2 updates: - package-ecosystem: github-actions - directory: / - schedule: - interval: weekly - day: monday - time: "04:00" - timezone: Etc/GMT - commit-message: - prefix: "ci: [DEPENDABOT] " - target-branch: develop - - - package-ecosystem: github-actions - directory: .github/actions/build-deps/ - schedule: - interval: weekly - day: monday - time: "04:00" - timezone: Etc/GMT - commit-message: - prefix: "ci: [DEPENDABOT] " - target-branch: develop - - - package-ecosystem: github-actions - directory: .github/actions/generate-version/ - schedule: - interval: weekly - day: monday - time: "04:00" - timezone: Etc/GMT - commit-message: - prefix: "ci: [DEPENDABOT] " - target-branch: develop - - - package-ecosystem: github-actions - directory: .github/actions/setup-conan/ + directories: + - / + - .github/actions/build-deps/ + - .github/actions/generate-version/ + - .github/actions/set-compiler-env/ + - .github/actions/setup-conan/ schedule: interval: weekly day: monday diff --git a/.github/scripts/rename/cmake.sh b/.github/scripts/rename/cmake.sh index 28bf777fed..3539f563e0 100755 --- a/.github/scripts/rename/cmake.sh +++ b/.github/scripts/rename/cmake.sh @@ -43,9 +43,6 @@ pushd "${DIRECTORY}" # Rename the files. find cmake -type f -name 'Rippled*.cmake' -exec bash -c 'mv "${1}" "${1/Rippled/Xrpl}"' - {} \; find cmake -type f -name 'Ripple*.cmake' -exec bash -c 'mv "${1}" "${1/Ripple/Xrpl}"' - {} \; -if [ -e cmake/xrpl_add_test.cmake ]; then - mv cmake/xrpl_add_test.cmake cmake/XrplAddTest.cmake -fi if [ -e include/xrpl/proto/ripple.proto ]; then mv include/xrpl/proto/ripple.proto include/xrpl/proto/xrpl.proto fi @@ -60,7 +57,6 @@ find cmake -type f -name '*.cmake' | while read -r FILE; do done ${SED_COMMAND} -i -E 's/Rippled?/Xrpl/g' CMakeLists.txt ${SED_COMMAND} -i 's/ripple/xrpl/g' CMakeLists.txt -${SED_COMMAND} -i 's/include(xrpl_add_test)/include(XrplAddTest)/' src/tests/libxrpl/CMakeLists.txt ${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' include/xrpl/protocol/messages.h ${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md ${SED_COMMAND} -i 's/ripple.pb.h/xrpl.pb.h/' BUILD.md diff --git a/.github/scripts/strategy-matrix/generate.py b/.github/scripts/strategy-matrix/generate.py index 6eccfcc6be..aaf84a51d0 100755 --- a/.github/scripts/strategy-matrix/generate.py +++ b/.github/scripts/strategy-matrix/generate.py @@ -1,384 +1,281 @@ #!/usr/bin/env python3 import argparse +import dataclasses import itertools import json -from dataclasses import dataclass from pathlib import Path THIS_DIR = Path(__file__).parent.resolve() +_BASE_CMAKE_ARGS = ["-Dtests=ON", "-Dwerr=ON", "-Dxrpld=ON", "-Dwextra=ON"] -@dataclass -class Config: - architecture: list[dict] - os: list[dict] +# Maps sanitizer names (as used in cmake) to short config-name suffixes. +_SANITIZER_SUFFIX: dict[str, str] = { + "address": "asan", + "undefinedbehavior": "ubsan", + "thread": "tsan", +} + + +def get_cmake_args(build_type: str, extra_args: str) -> str: + """Get the full list of CMake arguments for a config.""" + args = _BASE_CMAKE_ARGS.copy() + if build_type == "Release": + args.append("-Dassert=ON") + if extra_args: + args.extend(extra_args.split()) + return " ".join(args) + + +# --------------------------------------------------------------------------- +# Input types — shapes of the JSON config files +# --------------------------------------------------------------------------- + + +@dataclasses.dataclass +class LinuxConfig: + """One entry in linux.json's 'configs' or 'package_configs' arrays.""" + + compiler: list[str] build_type: list[str] - cmake_args: list[str] + arch: list[str] + sanitizers: list[str] = dataclasses.field(default_factory=list) + suffix: str = "" + extra_cmake_args: str = "" + image: str = "" # only used by package_configs entries -""" -Generate a strategy matrix for GitHub Actions CI. +@dataclasses.dataclass +class LinuxFile: + """Shape of linux.json.""" -On each PR commit we will build a selection of Debian, RHEL, Ubuntu, MacOS, and -Windows configurations, while upon merge into the develop or release branches, -we will build all configurations, and test most of them. + image_tag: str + configs: dict[str, list[LinuxConfig]] # distro → configs + package_configs: dict[str, list[LinuxConfig]] # distro → packaging configs -We will further set additional CMake arguments as follows: -- All builds will have the `tests`, `werr`, and `xrpld` options. -- All builds will have the `wextra` option except for GCC 12 and Clang 16. -- All release builds will have the `assert` option. -- Certain Debian Bookworm configurations will change the reference fee, enable - codecov, and enable voidstar in PRs. -""" + @classmethod + def load(cls, path: Path) -> "LinuxFile": + data = json.loads(path.read_text()) + + def parse(section: dict) -> dict[str, list[LinuxConfig]]: + return { + distro: [LinuxConfig(**c) for c in cfgs] + for distro, cfgs in section.items() + } + + return cls( + image_tag=data["image_tag"], + configs=parse(data["configs"]), + package_configs=parse(data.get("package_configs", {})), + ) -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) +@dataclasses.dataclass +class PlatformConfig: + """One entry in macos.json's or windows.json's 'configs' array.""" + + build_type: list[str] + build_only: bool = False # if true, skip tests (e.g. macos/Windows Debug) + extra_cmake_args: str = "" + + def __post_init__(self) -> None: + if isinstance(self.build_type, str): + self.build_type = [self.build_type] -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. +@dataclasses.dataclass +class PlatformFile: + """Shape of macos.json and windows.json.""" + + platform: str # e.g. "macos/arm64" or "windows/amd64" + runner: list[str] # GitHub Actions runner labels + configs: list[PlatformConfig] + + @classmethod + def load(cls, path: Path) -> "PlatformFile": + data = json.loads(path.read_text()) + return cls( + platform=data["platform"], + runner=data["runner"], + configs=[PlatformConfig(**c) for c in data["configs"]], + ) + + +# --------------------------------------------------------------------------- +# Output types — shapes of the generated GitHub Actions matrix entries +# --------------------------------------------------------------------------- + + +@dataclasses.dataclass +class Architecture: + platform: str + runner: list[str] + + +@dataclasses.dataclass +class MatrixEntry: + """One entry in the generated build/test strategy matrix.""" + + config_name: str + cmake_args: str + cmake_target: str + build_only: bool + build_type: str + architecture: Architecture + sanitizers: str + image: str = "" # container image; empty for macOS/Windows (runs natively) + compiler: str = "" # compiler name ("gcc" or "clang"); empty for macOS/Windows + + +@dataclasses.dataclass +class PackagingEntry: + """One entry in the generated packaging strategy matrix.""" + + artifact_name: str + image: str + distro: str # e.g. "debian" or "rhel"; drives package-format-specific steps + + +# --------------------------------------------------------------------------- +# Matrix expansion +# --------------------------------------------------------------------------- + +_ARCHS: dict[str, Architecture] = { + "amd64": Architecture( + platform="linux/amd64", runner=["self-hosted", "Linux", "X64", "heavy"] + ), + "arm64": Architecture( + platform="linux/arm64", + runner=["self-hosted", "Linux", "ARM64", "heavy-arm64"], + ), +} + + +def expand_linux_matrix(linux: LinuxFile) -> list[MatrixEntry]: + """Expand a LinuxFile into a flat list of matrix entries. + + Each config entry is expanded over the cross-product of its + compiler, build_type, sanitizers, and architecture lists. """ - return [ - { - "artifact_name": f"xrpld-{build_config_name(os, 'linux/amd64', 'Release')}", - "os": os, - } - for os in config.os - if os.get("package", False) - ] + entries: list[MatrixEntry] = [] + for distro, configs in linux.configs.items(): + for cfg in configs: + # An empty sanitizers list means "one entry with no sanitizer". + effective_sanitizers = cfg.sanitizers or [""] + effective_archs = {arch: _ARCHS[arch] for arch in cfg.arch} -def generate_strategy_matrix(all: bool, config: Config) -> list[dict]: - configurations = [] - for architecture, os, build_type, cmake_args in itertools.product( - config.architecture, config.os, config.build_type, config.cmake_args - ): - # The default CMake target is 'all' for Linux and MacOS and 'install' - # for Windows, but it can get overridden for certain configurations. - cmake_target = "install" if os["distro_name"] == "windows" else "all" - - # We build and test all configurations by default, except for Windows in - # Debug, because it is too slow, as well as when code coverage is - # enabled as that mode already runs the tests. - build_only = False - if os["distro_name"] == "windows" and build_type == "Debug": - build_only = True - - # Only generate a subset of configurations in PRs. - if not all: - # Debian: - # - Bookworm using GCC 13: Debug on linux/amd64, set the reference - # fee to 500 and enable code coverage (which will be done below). - # - Bookworm using GCC 15: Debug on linux/amd64, enable Address and - # UB sanitizers (which will be done below). - # - Bookworm using Clang 16: Debug on linux/amd64, enable voidstar. - # - Bookworm using Clang 17: Release on linux/amd64, set the - # reference fee to 1000. - # - Bookworm using Clang 20: Debug on linux/amd64, enable Address - # and UB sanitizers (which will be done below). - if os["distro_name"] == "debian": - skip = True - if os["distro_version"] == "bookworm": - if ( - f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-13" - and build_type == "Debug" - and architecture["platform"] == "linux/amd64" - ): - cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}" - skip = False - if ( - f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15" - and build_type == "Release" - and architecture["platform"] == "linux/amd64" - ): - skip = False - if ( - f"{os['compiler_name']}-{os['compiler_version']}" == "clang-16" - and build_type == "Debug" - and architecture["platform"] == "linux/amd64" - ): - cmake_args = f"-Dvoidstar=ON {cmake_args}" - skip = False - if ( - f"{os['compiler_name']}-{os['compiler_version']}" == "clang-17" - and build_type == "Release" - and architecture["platform"] == "linux/amd64" - ): - 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" - and build_type == "Debug" - and architecture["platform"] == "linux/amd64" - ): - skip = False - if skip: - continue - - # RHEL: - # - 9 using GCC 12: Debug and Release on linux/amd64 - # (Release is required for RPM packaging). - # - 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 architecture["platform"] == "linux/amd64" - ): - skip = False - elif os["distro_version"] == "10": - if ( - f"{os['compiler_name']}-{os['compiler_version']}" == "clang-any" - and build_type == "Release" - and architecture["platform"] == "linux/amd64" - ): - skip = False - if skip: - continue - - # Ubuntu: - # - Jammy using GCC 12: Debug on linux/arm64, Release on - # linux/amd64 (Release is required for DEB packaging). - # - Noble using GCC 14: Release on linux/amd64. - # - Noble using Clang 18: Debug on linux/amd64. - # - Noble using Clang 19: Release on linux/arm64. - if os["distro_name"] == "ubuntu": - skip = True - if os["distro_version"] == "jammy": - if ( - f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" - and build_type == "Debug" - 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" - and build_type == "Release" - and architecture["platform"] == "linux/amd64" - ): - skip = False - if ( - f"{os['compiler_name']}-{os['compiler_version']}" == "clang-18" - and build_type == "Debug" - and architecture["platform"] == "linux/amd64" - ): - skip = False - if ( - f"{os['compiler_name']}-{os['compiler_version']}" == "clang-19" - and build_type == "Release" - and architecture["platform"] == "linux/arm64" - ): - skip = False - if skip: - continue - - # MacOS: - # - Debug on macos/arm64. - if os["distro_name"] == "macos" and not ( - build_type == "Debug" and architecture["platform"] == "macos/arm64" + for compiler, build_type, sanitizer, (arch, arch_info) in itertools.product( + cfg.compiler, + cfg.build_type, + effective_sanitizers, + effective_archs.items(), ): - continue + name = f"{distro}-{compiler}-{build_type.lower()}-{arch}" + suffix_parts = [ + s for s in [cfg.suffix, _SANITIZER_SUFFIX.get(sanitizer, "")] if s + ] + if suffix_parts: + name += "-" + "-".join(suffix_parts) - # Windows: - # - Release on windows/amd64. - if os["distro_name"] == "windows" and not ( - build_type == "Release" and architecture["platform"] == "windows/amd64" - ): - continue - - # Additional CMake arguments. - cmake_args = f"{cmake_args} -Dtests=ON -Dwerr=ON -Dxrpld=ON" - if not f"{os['compiler_name']}-{os['compiler_version']}" in [ - "gcc-12", - "clang-16", - ]: - cmake_args = f"{cmake_args} -Dwextra=ON" - if build_type == "Release": - cmake_args = f"{cmake_args} -Dassert=ON" - - # We skip all RHEL on arm64 due to a build failure that needs further - # investigation. - if os["distro_name"] == "rhel" and architecture["platform"] == "linux/arm64": - continue - - # 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 - and architecture["platform"] == "linux/arm64" - ): - continue - - # Enable code coverage for Debian Bookworm using GCC 13 in Debug on - # linux/amd64. - if ( - f"{os['distro_name']}-{os['distro_version']}" == "debian-bookworm" - and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-13" - and build_type == "Debug" - and architecture["platform"] == "linux/amd64" - ): - cmake_args = f"{cmake_args} -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0" - - # Enable unity build for Ubuntu Jammy using GCC 12 in Debug on - # linux/amd64. - if ( - f"{os['distro_name']}-{os['distro_version']}" == "ubuntu-jammy" - and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12" - and build_type == "Debug" - and architecture["platform"] == "linux/amd64" - ): - cmake_args = f"{cmake_args} -Dunity=ON" - - # 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) - if "-Dcoverage=ON" in cmake_args: - config_name += "-coverage" - if "-Dunity=ON" in cmake_args: - config_name += "-unity" - - # Add the configuration to the list, with the most unique fields first, - # so that they are easier to identify in the GitHub Actions UI, as long - # names get truncated. - # 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 - configurations.append( - { - "config_name": config_name + "-asan", - "cmake_args": cmake_args, - "cmake_target": cmake_target, - "build_only": build_only, - "build_type": build_type, - "os": os, - "architecture": architecture, - "sanitizers": "address", - } - ) - configurations.append( - { - "config_name": config_name + "-ubsan", - "cmake_args": cmake_args, - "cmake_target": cmake_target, - "build_only": build_only, - "build_type": build_type, - "os": os, - "architecture": architecture, - "sanitizers": "undefinedbehavior", - } - ) - # TSAN is deactivated due to seg faults with latest compilers. - activate_tsan = False - if activate_tsan: - configurations.append( - { - "config_name": config_name + "-tsan-ubsan", - "cmake_args": cmake_args, - "cmake_target": cmake_target, - "build_only": build_only, - "build_type": build_type, - "os": os, - "architecture": architecture, - "sanitizers": "thread,undefinedbehavior", - } + entries.append( + MatrixEntry( + config_name=name, + image=f"ghcr.io/xrplf/xrpld/nix-{distro}:{linux.image_tag}", + cmake_args=get_cmake_args(build_type, cfg.extra_cmake_args), + cmake_target="all", + build_only=False, + build_type=build_type, + architecture=arch_info, + sanitizers=sanitizer, + compiler=compiler, + ) + ) + + return entries + + +def expand_linux_packaging(linux: LinuxFile) -> list[PackagingEntry]: + """Generate the packaging matrix from a LinuxFile's package_configs section. + + Packaging uses vanilla distro images (debian:bookworm, ubi9, …) instead of + the nix-based build images, because deb/rpm tooling (debhelper, rpm-build) + is taken from the distro's archive rather than from nixpkgs. Each config + entry carries its own 'image'. + """ + entries = [] + for distro, configs in linux.package_configs.items(): + for cfg in configs: + for compiler, build_type in itertools.product(cfg.compiler, cfg.build_type): + entries.append( + PackagingEntry( + artifact_name=f"xrpld-{distro}-{compiler}-{build_type.lower()}-amd64", + image=cfg.image, + distro=distro, + ) + ) + + return entries + + +def expand_platform_matrix(pf: PlatformFile) -> list[MatrixEntry]: + """Expand a PlatformFile (macOS or Windows) into matrix entries.""" + platform_name, arch = pf.platform.split("/") + is_windows = platform_name == "windows" + + entries: list[MatrixEntry] = [] + for cfg in pf.configs: + for build_type in cfg.build_type: + entries.append( + MatrixEntry( + config_name=f"{platform_name}-{arch}-{build_type.lower()}", + cmake_args=get_cmake_args(build_type, cfg.extra_cmake_args), + cmake_target="install" if is_windows else "all", + build_only=cfg.build_only, + build_type=build_type, + architecture=Architecture(platform=pf.platform, runner=pf.runner), + sanitizers="", ) - else: - configurations.append( - { - "config_name": config_name, - "cmake_args": cmake_args, - "cmake_target": cmake_target, - "build_only": build_only, - "build_type": build_type, - "os": os, - "architecture": architecture, - "sanitizers": "", - } ) - - return configurations + return entries -def read_config(file: Path) -> Config: - config = json.loads(file.read_text()) - if ( - config["architecture"] is None - or config["os"] is None - or config["build_type"] is None - or config["cmake_args"] is None - ): - raise Exception("Invalid configuration file.") - - return Config(**config) +# --------------------------------------------------------------------------- +# Entry point +# --------------------------------------------------------------------------- if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument( - "-a", - "--all", - help="Set to generate all configurations (generally used when merging a PR) or leave unset to generate a subset of configurations (generally used when committing to a PR).", - action="store_true", + parser = argparse.ArgumentParser( + description="Generate a CI strategy matrix for all platforms or a specific one." ) parser.add_argument( "-c", "--config", - help="Path to the JSON file containing the strategy matrix configurations.", - required=False, - type=Path, + help="Platform to generate for ('linux', 'macos', or 'windows'). Defaults to all platforms.", + choices=["linux", "macos", "windows"], + default=None, ) parser.add_argument( "-p", "--packaging", - help="Emit the packaging matrix (derived from the 'package' field on os entries) instead of the build/test matrix.", + help="Emit the Linux packaging matrix 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 == "": - matrix += generate_strategy_matrix( - args.all, read_config(THIS_DIR / "linux.json") - ) - matrix += generate_strategy_matrix( - args.all, read_config(THIS_DIR / "macos.json") - ) - matrix += generate_strategy_matrix( - args.all, read_config(THIS_DIR / "windows.json") - ) - else: - matrix += generate_strategy_matrix(args.all, read_config(args.config)) + matrix: list[MatrixEntry] | list[PackagingEntry] = [] - # Generate the strategy matrix. - print(f"matrix={json.dumps({'include': matrix})}") + if args.packaging: + matrix = expand_linux_packaging(LinuxFile.load(THIS_DIR / "linux.json")) + else: + if args.config in ("linux", None): + matrix += expand_linux_matrix(LinuxFile.load(THIS_DIR / "linux.json")) + if args.config in ("macos", None): + matrix += expand_platform_matrix(PlatformFile.load(THIS_DIR / "macos.json")) + if args.config in ("windows", None): + matrix += expand_platform_matrix( + PlatformFile.load(THIS_DIR / "windows.json") + ) + + print(f"matrix={json.dumps({'include': [dataclasses.asdict(e) for e in matrix]})}") diff --git a/.github/scripts/strategy-matrix/linux.json b/.github/scripts/strategy-matrix/linux.json index 4f090a81a3..edacdbde4c 100644 --- a/.github/scripts/strategy-matrix/linux.json +++ b/.github/scripts/strategy-matrix/linux.json @@ -1,221 +1,83 @@ { - "architecture": [ - { - "platform": "linux/amd64", - "runner": ["self-hosted", "Linux", "X64", "heavy"] - }, - { - "platform": "linux/arm64", - "runner": ["self-hosted", "Linux", "ARM64", "heavy-arm64"] - } - ], - "os": [ - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "gcc", - "compiler_version": "12", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "gcc", - "compiler_version": "13", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "gcc", - "compiler_version": "14", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "gcc", - "compiler_version": "15", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "clang", - "compiler_version": "16", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "clang", - "compiler_version": "17", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "clang", - "compiler_version": "18", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "clang", - "compiler_version": "19", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "bookworm", - "compiler_name": "clang", - "compiler_version": "20", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "trixie", - "compiler_name": "gcc", - "compiler_version": "14", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "trixie", - "compiler_name": "gcc", - "compiler_version": "15", - "image_sha": "4c086b9" - }, - { - "distro_name": "debian", - "distro_version": "trixie", - "compiler_name": "clang", - "compiler_version": "20", - "image_sha": "4c086b9" - }, - { - "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" - }, - { - "distro_name": "rhel", - "distro_version": "8", - "compiler_name": "gcc", - "compiler_version": "14", - "image_sha": "4c086b9" - }, - { - "distro_name": "rhel", - "distro_version": "8", - "compiler_name": "clang", - "compiler_version": "any", - "image_sha": "4c086b9" - }, - { - "distro_name": "rhel", - "distro_version": "9", - "compiler_name": "gcc", - "compiler_version": "12", - "image_sha": "4c086b9", - "package": true - }, - { - "distro_name": "rhel", - "distro_version": "9", - "compiler_name": "gcc", - "compiler_version": "13", - "image_sha": "4c086b9" - }, - { - "distro_name": "rhel", - "distro_version": "9", - "compiler_name": "gcc", - "compiler_version": "14", - "image_sha": "4c086b9" - }, - { - "distro_name": "rhel", - "distro_version": "9", - "compiler_name": "clang", - "compiler_version": "any", - "image_sha": "4c086b9" - }, - { - "distro_name": "rhel", - "distro_version": "10", - "compiler_name": "gcc", - "compiler_version": "14", - "image_sha": "4c086b9" - }, - { - "distro_name": "rhel", - "distro_version": "10", - "compiler_name": "clang", - "compiler_version": "any", - "image_sha": "4c086b9" - }, - { - "distro_name": "ubuntu", - "distro_version": "jammy", - "compiler_name": "gcc", - "compiler_version": "12", - "image_sha": "4c086b9", - "package": true - }, - { - "distro_name": "ubuntu", - "distro_version": "noble", - "compiler_name": "gcc", - "compiler_version": "13", - "image_sha": "4c086b9" - }, - { - "distro_name": "ubuntu", - "distro_version": "noble", - "compiler_name": "gcc", - "compiler_version": "14", - "image_sha": "4c086b9" - }, - { - "distro_name": "ubuntu", - "distro_version": "noble", - "compiler_name": "clang", - "compiler_version": "16", - "image_sha": "4c086b9" - }, - { - "distro_name": "ubuntu", - "distro_version": "noble", - "compiler_name": "clang", - "compiler_version": "17", - "image_sha": "4c086b9" - }, - { - "distro_name": "ubuntu", - "distro_version": "noble", - "compiler_name": "clang", - "compiler_version": "18", - "image_sha": "4c086b9" - }, - { - "distro_name": "ubuntu", - "distro_version": "noble", - "compiler_name": "clang", - "compiler_version": "19", - "image_sha": "4c086b9" - } - ], - "build_type": ["Debug", "Release"], - "cmake_args": [""] + "image_tag": "sha-63ffdc3", + "configs": { + "ubuntu": [ + { + "compiler": ["gcc", "clang"], + "build_type": ["Debug", "Release"], + "arch": ["amd64", "arm64"] + }, + + { + "compiler": ["gcc", "clang"], + "build_type": ["Debug"], + "arch": ["amd64"], + "sanitizers": ["address", "undefinedbehavior"] + }, + + { + "compiler": ["gcc"], + "build_type": ["Debug"], + "arch": ["amd64"], + "suffix": "coverage", + "extra_cmake_args": "-DUNIT_TEST_REFERENCE_FEE=500 -Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0" + }, + { + "compiler": ["clang"], + "build_type": ["Debug"], + "arch": ["amd64"], + "suffix": "voidstar", + "extra_cmake_args": "-Dvoidstar=ON" + }, + { + "compiler": ["clang"], + "build_type": ["Release"], + "arch": ["amd64"], + "suffix": "reffee", + "extra_cmake_args": "-DUNIT_TEST_REFERENCE_FEE=1000" + }, + { + "compiler": ["gcc"], + "build_type": ["Debug"], + "arch": ["amd64"], + "suffix": "unity", + "extra_cmake_args": "-Dunity=ON" + } + ], + + "debian": [ + { + "compiler": ["gcc"], + "build_type": ["Release"], + "arch": ["amd64"] + } + ], + + "rhel": [ + { + "compiler": ["gcc"], + "build_type": ["Release"], + "arch": ["amd64"] + } + ] + }, + "package_configs": { + "debian": [ + { + "compiler": ["gcc"], + "build_type": ["Release"], + "arch": ["amd64"], + "image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-63ffdc3" + } + ], + + "rhel": [ + { + "compiler": ["gcc"], + "build_type": ["Release"], + "arch": ["amd64"], + "image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-63ffdc3" + } + ] + } } diff --git a/.github/scripts/strategy-matrix/macos.json b/.github/scripts/strategy-matrix/macos.json index 6fc44d0f80..5b9e32f88e 100644 --- a/.github/scripts/strategy-matrix/macos.json +++ b/.github/scripts/strategy-matrix/macos.json @@ -1,19 +1,15 @@ { - "architecture": [ + "platform": "macos/arm64", + "runner": ["self-hosted", "macOS", "ARM64", "mac-runner-m1"], + "configs": [ { - "platform": "macos/arm64", - "runner": ["self-hosted", "macOS", "ARM64", "mac-runner-m1"] - } - ], - "os": [ + "build_type": "Release", + "extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5" + }, { - "distro_name": "macos", - "distro_version": "", - "compiler_name": "", - "compiler_version": "", - "image_sha": "" + "build_type": "Debug", + "extra_cmake_args": "-DCMAKE_POLICY_VERSION_MINIMUM=3.5", + "build_only": true } - ], - "build_type": ["Debug", "Release"], - "cmake_args": ["-DCMAKE_POLICY_VERSION_MINIMUM=3.5"] + ] } diff --git a/.github/scripts/strategy-matrix/windows.json b/.github/scripts/strategy-matrix/windows.json index 8c536c70f2..e4678b60db 100644 --- a/.github/scripts/strategy-matrix/windows.json +++ b/.github/scripts/strategy-matrix/windows.json @@ -1,19 +1,8 @@ { - "architecture": [ - { - "platform": "windows/amd64", - "runner": ["self-hosted", "Windows", "devbox"] - } - ], - "os": [ - { - "distro_name": "windows", - "distro_version": "", - "compiler_name": "", - "compiler_version": "", - "image_sha": "" - } - ], - "build_type": ["Debug", "Release"], - "cmake_args": [""] + "platform": "windows/amd64", + "runner": ["self-hosted", "Windows", "devbox"], + "configs": [ + { "build_type": "Release" }, + { "build_type": "Debug", "build_only": true } + ] } diff --git a/.github/workflows/build-nix-image.yml b/.github/workflows/build-nix-image.yml deleted file mode 100644 index bae4cfd437..0000000000 --- a/.github/workflows/build-nix-image.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Build Nix Docker image - -on: - push: - branches: - - develop - paths: - - ".github/workflows/build-nix-image.yml" - - ".github/workflows/reusable-build-docker-image.yml" - - "docker/**" - - "flake.nix" - - "flake.lock" - - "nix/**" - pull_request: - paths: - - ".github/workflows/build-nix-image.yml" - - ".github/workflows/reusable-build-docker-image.yml" - - "docker/**" - - "flake.nix" - - "flake.lock" - - "nix/**" - workflow_dispatch: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -defaults: - run: - shell: bash - -jobs: - build: - name: Build ${{ matrix.distro.name }} (${{ matrix.target.platform }}) - permissions: - contents: read - packages: write - strategy: - fail-fast: false - matrix: - # The base images are the oldest supported version of each distro - # that we want to build images for. - distro: - - name: nixos - base_image: nixos/nix:latest - - name: ubuntu - base_image: ubuntu:20.04 - - name: rhel - base_image: registry.access.redhat.com/ubi9/ubi:latest - - name: debian - base_image: debian:bookworm - target: - - platform: linux/amd64 - runner: ubuntu-latest - - platform: linux/arm64 - runner: ubuntu-24.04-arm - uses: ./.github/workflows/reusable-build-docker-image.yml - with: - image_name: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro.name }} - dockerfile: docker/nix.Dockerfile - base_image: ${{ matrix.distro.base_image }} - platform: ${{ matrix.target.platform }} - runner: ${{ matrix.target.runner }} - push: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }} - - merge: - name: Merge ${{ matrix.distro }} manifest - needs: build - if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }} - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - strategy: - fail-fast: false - matrix: - distro: [nixos, ubuntu, rhel, debian] - env: - IMAGE_NAME: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro }} - - steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - - - name: Docker metadata - id: meta - uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 - with: - images: ${{ env.IMAGE_NAME }} - tags: | - type=sha,prefix=sha-,format=short - type=raw,value=latest - - - name: Login to GitHub Container Registry - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Create multi-arch manifests - run: | - for tag in $(jq -cr '.tags[]' <<<"$DOCKER_METADATA_OUTPUT_JSON"); do - docker buildx imagetools create -t "$tag" "${tag}-amd64" "${tag}-arm64" - done - - - name: Inspect image - run: | - docker buildx imagetools inspect "${IMAGE_NAME}:${{ steps.meta.outputs.version }}" diff --git a/.github/workflows/build-nix-images.yml b/.github/workflows/build-nix-images.yml new file mode 100644 index 0000000000..24f069902d --- /dev/null +++ b/.github/workflows/build-nix-images.yml @@ -0,0 +1,54 @@ +name: Build Nix Docker images + +on: + push: + branches: + - develop + paths: + - ".github/workflows/build-nix-images.yml" + - "flake.nix" + - "flake.lock" + - "nix/**" + pull_request: + paths: + - ".github/workflows/build-nix-images.yml" + - "flake.nix" + - "flake.lock" + - "nix/**" + workflow_dispatch: + +concurrency: + # Read `on-trigger.yml` for the rationale behind this concurrency group name. + group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + build-merge: + name: Build and push nix-${{ matrix.distro.name }} + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + # The base images are the oldest supported version of each distro + # that we want to build images for. + distro: + - name: nixos + base_image: nixos/nix:latest + - name: ubuntu + base_image: ubuntu:20.04 + - name: debian + base_image: debian:bookworm + - name: rhel + base_image: registry.access.redhat.com/ubi9/ubi:latest + uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@c1b480188519e0cad040e6aa70db1cbc5a797e07 + with: + image_name: ghcr.io/xrplf/xrpld/nix-${{ matrix.distro.name }} + dockerfile: nix/docker/Dockerfile + base_image: ${{ matrix.distro.base_image }} + push: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }} diff --git a/.github/workflows/build-packaging-images.yml b/.github/workflows/build-packaging-images.yml new file mode 100644 index 0000000000..d6dabb0f95 --- /dev/null +++ b/.github/workflows/build-packaging-images.yml @@ -0,0 +1,46 @@ +name: Build packaging Docker images + +on: + push: + branches: + - develop + paths: + - ".github/workflows/build-packaging-images.yml" + - "package/Dockerfile" + - "package/install-packaging-tools.sh" + pull_request: + paths: + - ".github/workflows/build-packaging-images.yml" + - "package/Dockerfile" + - "package/install-packaging-tools.sh" + workflow_dispatch: + +concurrency: + # Read `on-trigger.yml` for the rationale behind this concurrency group name. + group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash + +jobs: + build-merge: + name: Build and push packaging-${{ matrix.distro.name }} + permissions: + contents: read + packages: write + strategy: + fail-fast: false + matrix: + distro: + - name: debian + base_image: debian:bookworm + - name: rhel + base_image: registry.access.redhat.com/ubi9/ubi:latest + uses: XRPLF/actions/.github/workflows/build-multiarch-image.yml@c1b480188519e0cad040e6aa70db1cbc5a797e07 + with: + image_name: ghcr.io/xrplf/xrpld/packaging-${{ matrix.distro.name }} + dockerfile: package/Dockerfile + base_image: ${{ matrix.distro.base_image }} + push: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' }} diff --git a/.github/workflows/check-pr-description.yml b/.github/workflows/check-pr-description.yml index ff28220171..a60b83738a 100644 --- a/.github/workflows/check-pr-description.yml +++ b/.github/workflows/check-pr-description.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Write PR body to file env: diff --git a/.github/workflows/on-pr.yml b/.github/workflows/on-pr.yml index db3c8667e5..4b2edeb93d 100644 --- a/.github/workflows/on-pr.yml +++ b/.github/workflows/on-pr.yml @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Determine changed files # This step checks whether any files have changed that should # cause the next jobs to run. We do it this way rather than diff --git a/.github/workflows/on-tag.yml b/.github/workflows/on-tag.yml index b7517ccf11..42d5827cab 100644 --- a/.github/workflows/on-tag.yml +++ b/.github/workflows/on-tag.yml @@ -33,7 +33,6 @@ jobs: with: ccache_enabled: false os: ${{ matrix.os }} - strategy_matrix: minimal secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/on-trigger.yml b/.github/workflows/on-trigger.yml index 803ba3c87b..74bca82019 100644 --- a/.github/workflows/on-trigger.yml +++ b/.github/workflows/on-trigger.yml @@ -88,7 +88,6 @@ jobs: # not identical to a regular compilation. ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release') }} os: ${{ matrix.os }} - strategy_matrix: ${{ github.event_name == 'schedule' && 'all' || 'minimal' }} secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index de6a4f40b4..aecf0c2a8b 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -14,7 +14,7 @@ on: jobs: # Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks. run-hooks: - uses: XRPLF/actions/.github/workflows/pre-commit.yml@cba1f0891650baf1a9c88624dc2d72573be2eb81 + uses: XRPLF/actions/.github/workflows/pre-commit.yml@312aaab296060ff89d7f798dcab59f019bea6e02 with: runs_on: ubuntu-latest container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }' diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index d619be5543..bcf5968384 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -41,13 +41,13 @@ env: jobs: build: runs-on: ubuntu-latest - container: ghcr.io/xrplf/ci/tools-rippled-documentation:sha-a8c7be1 + container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-63ffdc3 steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab + uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8 with: enable_ccache: false @@ -57,19 +57,11 @@ jobs: with: subtract: ${{ env.NPROC_SUBTRACT }} - - name: Check configuration - run: | - echo 'Checking path.' - echo ${PATH} | tr ':' '\n' + - name: Print build environment + uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574 - echo 'Checking environment variables.' - env | sort - - echo 'Checking CMake version.' - cmake --version - - echo 'Checking Doxygen version.' - doxygen --version + - name: Check Doxygen version + run: doxygen --version - name: Build documentation env: diff --git a/.github/workflows/reusable-build-docker-image.yml b/.github/workflows/reusable-build-docker-image.yml deleted file mode 100644 index c3795e56fa..0000000000 --- a/.github/workflows/reusable-build-docker-image.yml +++ /dev/null @@ -1,89 +0,0 @@ -# Build a single-platform Docker image. On push, the image is pushed to -# GHCR with arch-suffixed tags (e.g. `:latest-amd64`, `:sha-abc-amd64`) -# so the calling workflow can stitch per-arch builds into a multi-arch -# manifest without needing to pass digests around. -name: Reusable build Docker image (single platform) - -on: - workflow_call: - inputs: - image_name: - description: "Full image name without tag (e.g. 'ghcr.io/xrplf/xrpld/nix-ubuntu')" - required: true - type: string - dockerfile: - description: "Path to the Dockerfile, relative to the repository root" - required: true - type: string - base_image: - description: "Value passed to the Dockerfile as the BASE_IMAGE build arg" - required: true - type: string - platform: - description: "Docker platform string, e.g. linux/amd64" - required: true - type: string - runner: - description: "GitHub Actions runner label to build on" - required: true - type: string - push: - description: "Whether to push the image to GHCR" - required: true - type: boolean - -defaults: - run: - shell: bash - -jobs: - build: - name: Build (${{ inputs.platform }}) - runs-on: ${{ inputs.runner }} - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Determine arch - id: vars - env: - PLATFORM: ${{ inputs.platform }} - run: | - echo "arch=${PLATFORM##*/}" >>$GITHUB_OUTPUT - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 - - - name: Login to GitHub Container Registry - if: inputs.push - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Docker metadata - id: meta - uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 - with: - images: ${{ inputs.image_name }} - tags: | - type=sha,prefix=sha-,format=short - type=raw,value=latest - flavor: | - suffix=-${{ steps.vars.outputs.arch }},onlatest=true - - - name: Build and push - uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0 - with: - context: . - file: ${{ inputs.dockerfile }} - platforms: ${{ inputs.platform }} - push: ${{ inputs.push }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: BASE_IMAGE=${{ inputs.base_image }} diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 31457bb892..d53cf97a39 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -57,6 +57,12 @@ on: type: string default: "" + compiler: + description: 'The compiler to use ("gcc" or "clang"). Leave empty for macOS/Windows (uses system default).' + required: false + type: string + default: "" + secrets: CODECOV_TOKEN: description: "The Codecov token to use for uploading coverage reports." @@ -104,10 +110,10 @@ jobs: uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4 - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab + uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8 with: enable_ccache: ${{ inputs.ccache_enabled }} @@ -124,6 +130,12 @@ jobs: with: subtract: ${{ inputs.nproc_subtract }} + - name: Set compiler environment (Linux) + if: ${{ runner.os == 'Linux' }} + uses: ./.github/actions/set-compiler-env + with: + compiler: ${{ inputs.compiler }} + - name: Setup Conan env: SANITIZERS: ${{ inputs.sanitizers }} @@ -191,6 +203,21 @@ jobs: --parallel "${BUILD_NPROC}" \ --target "${CMAKE_TARGET}" + # This step is needed to allow running in non-Nix environments + - name: Patch binary to use default loader and remove rpath (Linux) + if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }} + run: | + loader="$(/tmp/loader-path.sh)" + patchelf --set-interpreter "${loader}" --remove-rpath "${{ env.BUILD_DIR }}/xrpld" + + # We're only running aarch64 Linux builds in Ubuntu-based images, so this is kept simple + - name: Install libatomic (Linux aarch64) + if: ${{ runner.os == 'Linux' && runner.arch == 'ARM64' }} + run: | + apt update --yes + apt install -y --no-install-recommends \ + libatomic1 + - name: Show ccache statistics if: ${{ inputs.ccache_enabled }} run: | @@ -209,6 +236,15 @@ jobs: retention-days: 3 if-no-files-found: error + - name: Upload the test binary (Linux) + if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: xrpl_tests-${{ inputs.config_name }} + path: ${{ env.BUILD_DIR }}/xrpl_tests + retention-days: 3 + if-no-files-found: error + - name: Export server definitions if: ${{ runner.os != 'Windows' && !inputs.build_only && env.VOIDSTAR_ENABLED != 'true' }} working-directory: ${{ env.BUILD_DIR }} @@ -217,7 +253,7 @@ jobs: ./xrpld --definitions | python3 -m json.tool >server_definitions.json - name: Upload server definitions - if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'debian-bookworm-gcc-13-amd64-release' }} + if: ${{ github.event.repository.visibility == 'public' && inputs.config_name == 'debian-gcc-release-amd64' }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: server-definitions @@ -259,16 +295,8 @@ jobs: - name: Run the separate tests if: ${{ !inputs.build_only }} - working-directory: ${{ env.BUILD_DIR }} - # Windows locks some of the build files while running tests, and parallel jobs can collide - env: - BUILD_TYPE: ${{ inputs.build_type }} - PARALLELISM: ${{ runner.os == 'Windows' && '1' || steps.nproc.outputs.nproc }} - run: | - ctest \ - --output-on-failure \ - -C "${BUILD_TYPE}" \ - -j "${PARALLELISM}" + working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }} + run: ./xrpl_tests - name: Run the embedded tests if: ${{ !inputs.build_only }} @@ -279,7 +307,25 @@ jobs: set -o pipefail # Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness [ "$COVERAGE_ENABLED" = "true" ] && BUILD_NPROC=$((BUILD_NPROC - 2)) - ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log + + # The resolver/preload workaround is only correct for the ASan build: + # a regular build doesn't hit the __dn_expand interceptor bug, and must + # NOT have libasan injected. So only preload when xrpld is ASan-built. + # + # libresolv hosts getaddrinfo's resolver helpers (dn_expand, res_*). Under ASan + # these are intercepted via dlsym(RTLD_NEXT, ...), which yields a NULL pointer + # and crashes DNS resolution if libresolv isn't loaded. Linking it guarantees + # the symbols are present; it's a harmless no-op on glibc >= 2.34 (merged into + # libc) and is what the compiler driver already does for sanitizer builds. + # https://github.com/llvm/llvm-project/issues/59007 + # https://github.com/google/sanitizers/issues/1592 + if ldd ./xrpld | grep -q libasan; then + PRELOAD="$(gcc -print-file-name=libasan.so):/usr/lib/x86_64-linux-gnu/libresolv.so.2" + else + PRELOAD="" + fi + + LD_PRELOAD="$PRELOAD" ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log - name: Show test failure summary if: ${{ failure() && !inputs.build_only }} @@ -324,7 +370,7 @@ jobs: - name: Upload coverage report if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }} - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: disable_search: true disable_telem: true diff --git a/.github/workflows/reusable-build-test.yml b/.github/workflows/reusable-build-test.yml index 0086cbbfb5..4b64c53521 100644 --- a/.github/workflows/reusable-build-test.yml +++ b/.github/workflows/reusable-build-test.yml @@ -19,13 +19,6 @@ on: required: true type: string - strategy_matrix: - # TODO: Support additional strategies, e.g. "ubuntu" for generating all Ubuntu configurations. - description: 'The strategy matrix to use for generating the configurations ("minimal", "all").' - required: false - type: string - default: "minimal" - secrets: CODECOV_TOKEN: description: "The Codecov token to use for uploading coverage reports." @@ -37,7 +30,6 @@ jobs: uses: ./.github/workflows/reusable-strategy-matrix.yml with: os: ${{ inputs.os }} - strategy_matrix: ${{ inputs.strategy_matrix }} # Build and test the binary for each configuration. build-test-config: @@ -47,7 +39,6 @@ jobs: strategy: fail-fast: ${{ github.event_name == 'merge_group' }} matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} - max-parallel: 10 with: build_only: ${{ matrix.build_only }} build_type: ${{ matrix.build_type }} @@ -55,8 +46,9 @@ jobs: cmake_args: ${{ matrix.cmake_args }} cmake_target: ${{ matrix.cmake_target }} runs_on: ${{ toJSON(matrix.architecture.runner) }} - image: ${{ contains(matrix.architecture.platform, 'linux') && 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) || '' }} + image: ${{ matrix.image || '' }} config_name: ${{ matrix.config_name }} sanitizers: ${{ matrix.sanitizers }} + compiler: ${{ matrix.compiler || '' }} secrets: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/reusable-check-levelization.yml b/.github/workflows/reusable-check-levelization.yml index b5d57a177a..813c0e1e36 100644 --- a/.github/workflows/reusable-check-levelization.yml +++ b/.github/workflows/reusable-check-levelization.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Check levelization run: python .github/scripts/levelization/generate.py - name: Check for differences diff --git a/.github/workflows/reusable-check-rename.yml b/.github/workflows/reusable-check-rename.yml index 7aa5b80594..5002cc7f40 100644 --- a/.github/workflows/reusable-check-rename.yml +++ b/.github/workflows/reusable-check-rename.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Check definitions run: .github/scripts/rename/definitions.sh . - name: Check copyright notices diff --git a/.github/workflows/reusable-clang-tidy.yml b/.github/workflows/reusable-clang-tidy.yml index 8be1db5fb2..9f10711b6f 100644 --- a/.github/workflows/reusable-clang-tidy.yml +++ b/.github/workflows/reusable-clang-tidy.yml @@ -29,23 +29,23 @@ jobs: if: ${{ inputs.check_only_changed }} permissions: contents: read - uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@224f3c48d3014d082a1129237b8291ff0b0a331f + uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@312aaab296060ff89d7f798dcab59f019bea6e02 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" + container: "ghcr.io/xrplf/xrpld/nix-debian:sha-63ffdc3" permissions: contents: read issues: write steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab + uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8 with: enable_ccache: false @@ -56,6 +56,11 @@ jobs: uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf id: nproc + - name: Set compiler environment + uses: ./.github/actions/set-compiler-env + with: + compiler: clang + - name: Setup Conan uses: ./.github/actions/setup-conan diff --git a/.github/workflows/reusable-package.yml b/.github/workflows/reusable-package.yml index 2a3ed8a33e..0e3f657006 100644 --- a/.github/workflows/reusable-package.yml +++ b/.github/workflows/reusable-package.yml @@ -1,8 +1,7 @@ # 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. +# Discovers which configurations to package from linux.json (configs in +# "package_configs") and fans out one job per distro. Only linux/amd64 is +# supported; the runner is hardcoded in the job below. name: Package on: @@ -28,18 +27,17 @@ jobs: matrix: ${{ steps.generate.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Set up Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: - python-version: 3.13 + 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}" + run: ./generate.py --packaging >>"${GITHUB_OUTPUT}" generate-version: runs-on: ubuntu-latest @@ -47,7 +45,7 @@ jobs: version: ${{ steps.version.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: sparse-checkout: | .github/actions/generate-version @@ -66,12 +64,12 @@ jobs: 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) }} + container: ${{ matrix.image }} timeout-minutes: 30 steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Download pre-built binary uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 diff --git a/.github/workflows/reusable-strategy-matrix.yml b/.github/workflows/reusable-strategy-matrix.yml index 62d65ad3fa..ea134b43b2 100644 --- a/.github/workflows/reusable-strategy-matrix.yml +++ b/.github/workflows/reusable-strategy-matrix.yml @@ -4,15 +4,9 @@ on: workflow_call: inputs: os: - description: 'The operating system to use for the build ("linux", "macos", "windows").' + description: 'The operating system to use for the build ("linux", "macos", "windows", or empty for all).' required: false type: string - strategy_matrix: - # TODO: Support additional strategies, e.g. "ubuntu" for generating all Ubuntu configurations. - description: 'The strategy matrix to use for generating the configurations ("minimal", "all").' - required: false - type: string - default: "minimal" outputs: matrix: description: "The generated strategy matrix." @@ -29,17 +23,16 @@ jobs: matrix: ${{ steps.generate.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Set up Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: - python-version: 3.13 + python-version: "3.13" - name: Generate strategy matrix working-directory: .github/scripts/strategy-matrix id: generate env: - GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}.json', inputs.os) || '' }} - GENERATE_OPTION: ${{ inputs.strategy_matrix == 'all' && '--all' || '' }} - run: ./generate.py ${GENERATE_OPTION} ${GENERATE_CONFIG} >>"${GITHUB_OUTPUT}" + GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}', inputs.os) || '' }} + run: ./generate.py ${GENERATE_CONFIG} >>"${GITHUB_OUTPUT}" diff --git a/.github/workflows/reusable-upload-recipe.yml b/.github/workflows/reusable-upload-recipe.yml index d3fe0f356b..1c90fb0e72 100644 --- a/.github/workflows/reusable-upload-recipe.yml +++ b/.github/workflows/reusable-upload-recipe.yml @@ -40,10 +40,10 @@ defaults: jobs: upload: runs-on: ubuntu-latest - container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13-sha-5dd7158 + container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-63ffdc3 steps: - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Generate build version number id: version diff --git a/.github/workflows/upload-conan-deps.yml b/.github/workflows/upload-conan-deps.yml index 34dce28334..1a52ceee63 100644 --- a/.github/workflows/upload-conan-deps.yml +++ b/.github/workflows/upload-conan-deps.yml @@ -48,8 +48,6 @@ jobs: # Generate the strategy matrix to be used by the following job. generate-matrix: uses: ./.github/workflows/reusable-strategy-matrix.yml - with: - strategy_matrix: ${{ github.event_name == 'pull_request' && 'minimal' || 'all' }} # Build and upload the dependencies for each configuration. run-upload-conan-deps: @@ -58,19 +56,18 @@ jobs: strategy: fail-fast: false matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} - max-parallel: 10 runs-on: ${{ matrix.architecture.runner }} - container: ${{ contains(matrix.architecture.platform, 'linux') && 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) || null }} + container: ${{ matrix.image || null }} steps: - name: Cleanup workspace (macOS and Windows) if: ${{ runner.os == 'macOS' || runner.os == 'Windows' }} uses: XRPLF/actions/cleanup-workspace@c7d9ce5ebb03c752a354889ecd870cadfc2b1cd4 - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Prepare runner - uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab + uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8 with: enable_ccache: false @@ -83,6 +80,12 @@ jobs: with: subtract: ${{ env.NPROC_SUBTRACT }} + - name: Set compiler environment (Linux) + if: ${{ runner.os == 'Linux' }} + uses: ./.github/actions/set-compiler-env + with: + compiler: ${{ matrix.compiler }} + - name: Setup Conan env: SANITIZERS: ${{ matrix.sanitizers }} diff --git a/cmake/XrplAddTest.cmake b/cmake/XrplAddTest.cmake deleted file mode 100644 index 2f1209e03c..0000000000 --- a/cmake/XrplAddTest.cmake +++ /dev/null @@ -1,22 +0,0 @@ -include(isolate_headers) - -function(xrpl_add_test name) - set(target ${PROJECT_NAME}.test.${name}) - - file( - GLOB_RECURSE sources - CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp" - ) - add_executable(${target} ${ARGN} ${sources}) - - isolate_headers( - ${target} - "${CMAKE_SOURCE_DIR}" - "${CMAKE_SOURCE_DIR}/tests/${name}" - PRIVATE - ) - - add_test(NAME ${target} COMMAND ${target}) -endfunction() diff --git a/cmake/XrplCompiler.cmake b/cmake/XrplCompiler.cmake index 0b77ff3525..9af8e962d0 100644 --- a/cmake/XrplCompiler.cmake +++ b/cmake/XrplCompiler.cmake @@ -145,13 +145,39 @@ else() INTERFACE -rdynamic $<$:-Wl,-z,relro,-z,now,--build-id> - # link to static libc/c++ iff: * static option set and * NOT APPLE (AppleClang does not support static - # libc/c++) and * NOT SANITIZERS (sanitizers typically don't work with static libc/c++) - $<$,$>,$>>: + # link to static libc/c++ if: + # * static option set and + # * NOT APPLE (AppleClang does not support static libc/c++) + $<$,$>>: -static-libstdc++ -static-libgcc > ) + + # Keep -stdlib=libstdc++ off the compile commands, but preserve it for linking. + # + # Conan turns `compiler.libcxx=libstdc++` into `-stdlib=libstdc++` and puts it in + # CMAKE_CXX_FLAGS, which CMake passes to BOTH compile and link steps. On a normal Clang + # the compile step consumes it while choosing the C++ stdlib include paths. The Nixpkgs + # Clang wrapper supplies those paths itself (via -nostdinc++), so at compile time the + # flag is unused -> Clang errors under our -Werror. At link time the flag IS consumed + # (it selects the C++ runtime), so we move it there instead of dropping it entirely. + get_filename_component(_cxx_real "${CMAKE_CXX_COMPILER}" REALPATH) + if( + _cxx_real MATCHES "^/nix/store/" + AND is_linux + AND is_clang + AND CMAKE_CXX_FLAGS MATCHES "stdlib=libstdc" + ) + string( + REPLACE "-stdlib=libstdc++" + "" + CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS}" + ) + string(STRIP "${CMAKE_CXX_FLAGS}" CMAKE_CXX_FLAGS) + add_link_options($<$:-stdlib=libstdc++>) + endif() endif() # Antithesis instrumentation will only be built and deployed using machines running Linux. diff --git a/cmake/XrplCov.cmake b/cmake/XrplCov.cmake index d81d7e689f..86ba534a88 100644 --- a/cmake/XrplCov.cmake +++ b/cmake/XrplCov.cmake @@ -47,7 +47,7 @@ setup_target_for_coverage_gcovr( "include/xrpl/beast/test" "include/xrpl/beast/unit_test" "${CMAKE_BINARY_DIR}/pb-xrpl.libpb" - DEPENDENCIES xrpld xrpl.tests + DEPENDENCIES xrpld xrpl_tests ) add_code_coverage_to_target(opts INTERFACE) diff --git a/conan/profiles/ci b/conan/profiles/ci index ae93187026..9422addfe3 100644 --- a/conan/profiles/ci +++ b/conan/profiles/ci @@ -1 +1,8 @@ +{% set os = detect_api.detect_os() %} include(sanitizers) + +[conf] +{% if os == "Linux" %} +user.package:libc_version=2.31 +tools.info.package_id:confs+=["user.package:libc_version"] +{% endif %} diff --git a/cspell.config.yaml b/cspell.config.yaml index da5dc9b072..cab2fc3da6 100644 --- a/cspell.config.yaml +++ b/cspell.config.yaml @@ -50,6 +50,7 @@ words: - AMMXRP - amt - amts + - archs - asnode - asynchrony - attestation diff --git a/docker/install-sanitizer-libs.sh b/docker/install-sanitizer-libs.sh deleted file mode 100755 index a28efeab3f..0000000000 --- a/docker/install-sanitizer-libs.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/bash -# Install sanitizer runtime libraries required to run binaries compiled with: -# -fsanitize=address → libasan.so.8 -# -fsanitize=thread → libtsan.so.2 -# -fsanitize=undefined → libubsan.so.1 -# -# The exact SONAMEs required depend on the compiler toolchain used to build the -# test binaries (see nix/ci-env.nix). If the toolchain is bumped and SONAMEs -# change, update the list below (or detect them from the binaries). -# -# Supported base images: -# debian:bookworm -# ubuntu:20.04 -# rhel:9 -# nixos/nix — tests are skipped; this script is not called - -set -euo pipefail - -if [ ! -f /etc/os-release ]; then - echo "ERROR: /etc/os-release not found; cannot detect OS" >&2 - exit 1 -fi - -# shellcheck source=/dev/null -. /etc/os-release - -echo "Detected OS: ${ID} ${VERSION_ID:-}" - -case "${ID}" in - debian) - apt-get update -y - apt-get install -y --no-install-recommends \ - libasan8 \ - libtsan2 \ - libubsan1 - - apt-get clean - rm -rf /var/lib/apt/lists/* - ;; - - ubuntu) - apt-get update -y - apt-get install -y --no-install-recommends \ - gnupg \ - software-properties-common - add-apt-repository -y ppa:ubuntu-toolchain-r/test - apt-get update -y - apt-get install -y --no-install-recommends \ - libasan8 \ - libtsan2 \ - libubsan1 - - apt-get clean - rm -rf /var/lib/apt/lists/* - ;; - - rhel | centos | rocky | almalinux) - dnf install -y \ - libasan8 \ - libtsan2 \ - libubsan - - dnf clean -y all - rm -rf /var/cache/dnf/* - ;; - - *) - echo "ERROR: unsupported OS '${ID}'. Supported: debian, ubuntu, rhel-family" >&2 - exit 1 - ;; -esac - -# Verify that every expected library is now resolvable by the dynamic linker. -missing=0 -for lib in libasan.so.8 libtsan.so.2 libubsan.so.1; do - if ldconfig -p | grep -q "${lib}"; then - echo "OK: ${lib} found" - else - echo "ERROR: ${lib} not found after installation" >&2 - missing=$((missing + 1)) - fi -done - -if [ "${missing}" -ne 0 ]; then - echo "ERROR: ${missing} library/libraries missing" >&2 - exit 1 -fi - -echo "All sanitizer runtime libraries installed successfully." diff --git a/include/xrpl/net/HTTPClient.h b/include/xrpl/net/HTTPClient.h index f059b19047..456f769922 100644 --- a/include/xrpl/net/HTTPClient.h +++ b/include/xrpl/net/HTTPClient.h @@ -53,7 +53,7 @@ public: boost::system::error_code const& ecResult, int iStatus, std::string const& strData)> complete, - beast::Journal& j); + beast::Journal const& j); static void get(bool bSSL, @@ -67,7 +67,7 @@ public: boost::system::error_code const& ecResult, int iStatus, std::string const& strData)> complete, - beast::Journal& j); + beast::Journal const& j); static void request( @@ -82,7 +82,7 @@ public: boost::system::error_code const& ecResult, int iStatus, std::string const& strData)> complete, - beast::Journal& j); + beast::Journal const& j); }; } // namespace xrpl diff --git a/include/xrpl/nodestore/detail/varint.h b/include/xrpl/nodestore/detail/varint.h index e6b78fcf08..0c49274d70 100644 --- a/include/xrpl/nodestore/detail/varint.h +++ b/include/xrpl/nodestore/detail/varint.h @@ -25,7 +25,7 @@ struct varint_traits { explicit varint_traits() = default; - static constexpr std::size_t kMax = (8 * sizeof(T) + 6) / 7; + static constexpr std::size_t kMax = ((8 * sizeof(T)) + 6) / 7; }; // Returns: Number of bytes consumed or 0 on error, diff --git a/include/xrpl/shamap/SHAMap.h b/include/xrpl/shamap/SHAMap.h index 32e87b64c6..3d08318cf6 100644 --- a/include/xrpl/shamap/SHAMap.h +++ b/include/xrpl/shamap/SHAMap.h @@ -161,7 +161,7 @@ public: setLedgerSeq(std::uint32_t lseq); bool - fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter); + fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter const* filter); // normal hash access functions @@ -248,7 +248,7 @@ public: @param return The nodes known to be missing */ std::vector> - getMissingNodes(int maxNodes, SHAMapSyncFilter* filter); + getMissingNodes(int maxNodes, SHAMapSyncFilter const* filter); bool getNodeFat( @@ -281,9 +281,9 @@ public: serializeRoot(Serializer& s) const; SHAMapAddNode - addRootNode(SHAMapHash const& hash, Slice const& rootNode, SHAMapSyncFilter* filter); + addRootNode(SHAMapHash const& hash, Slice const& rootNode, SHAMapSyncFilter const* filter); SHAMapAddNode - addKnownNode(SHAMapNodeID const& nodeID, Slice const& rawNode, SHAMapSyncFilter* filter); + addKnownNode(SHAMapNodeID const& nodeID, Slice const& rawNode, SHAMapSyncFilter const* filter); // status functions void @@ -343,11 +343,11 @@ private: SHAMapTreeNodePtr fetchNodeNT(SHAMapHash const& hash) const; SHAMapTreeNodePtr - fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter* filter) const; + fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter const* filter) const; SHAMapTreeNodePtr fetchNode(SHAMapHash const& hash) const; SHAMapTreeNodePtr - checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const; + checkFilter(SHAMapHash const& hash, SHAMapSyncFilter const* filter) const; /** Update hashes up to the root */ void @@ -411,7 +411,7 @@ private: descendAsync( SHAMapInnerNode* parent, int branch, - SHAMapSyncFilter* filter, + SHAMapSyncFilter const* filter, bool& pending, descendCallback&&) const; @@ -420,7 +420,7 @@ private: SHAMapInnerNode* parent, SHAMapNodeID const& parentID, int branch, - SHAMapSyncFilter* filter) const; + SHAMapSyncFilter const* filter) const; // Non-storing // Does not hook the returned node to its parent @@ -461,7 +461,7 @@ private: // basic parameters int max; - SHAMapSyncFilter* filter; + SHAMapSyncFilter const* filter; int const maxDefer; std::uint32_t generation; @@ -500,7 +500,11 @@ private: // reads std::map resumes; - MissingNodes(int max, SHAMapSyncFilter* filter, int maxDefer, std::uint32_t generation) + MissingNodes( + int max, + SHAMapSyncFilter const* filter, + int maxDefer, + std::uint32_t generation) : max(max), filter(filter), maxDefer(maxDefer), generation(generation), deferred(0) { missingNodes.reserve(max); diff --git a/docker/nix.Dockerfile b/nix/docker/Dockerfile similarity index 90% rename from docker/nix.Dockerfile rename to nix/docker/Dockerfile index 6248708417..e6df48e18c 100644 --- a/docker/nix.Dockerfile +++ b/nix/docker/Dockerfile @@ -56,7 +56,7 @@ ENV GIT_SSL_CAINFO="/nix/ci-env/etc/ssl/certs/ca-bundle.crt" # Externally-built dynamically-linked ELF binaries hard-code the loader path # (e.g. /lib64/ld-linux-x86-64.so.2) in their PT_INTERP header. Install it # from the Nix store when the base image doesn't already provide one. -COPY docker/loader-path.sh /tmp/loader-path.sh +COPY nix/docker/loader-path.sh /tmp/loader-path.sh RUN <&2 + exit 1 +fi + +# shellcheck source=/dev/null +. /etc/os-release + +echo "Detected OS: ${ID} ${VERSION_ID:-}" + +case "${ID}" in + ubuntu | debian | rhel | centos | rocky | almalinux) + echo "Supported OS detected: ${ID}" + ;; + *) + echo "ERROR: unsupported OS '${ID}'. Supported: debian, ubuntu, rhel-family" >&2 + exit 1 + ;; +esac + +function preinstall() { + case "${ID}" in + ubuntu) + apt-get update -y + apt-get install -y --no-install-recommends \ + gnupg \ + software-properties-common + add-apt-repository -y ppa:ubuntu-toolchain-r/test + ;; + esac +} + +function install() { + case "${ID}" in + debian | ubuntu) + apt-get update -y + apt-get install -y --no-install-recommends \ + libasan8 \ + libtsan2 \ + libubsan1 + ;; + + rhel | centos | rocky | almalinux) + dnf install -y \ + libasan8 \ + libtsan2 \ + libubsan + ;; + esac +} + +function postinstall() { + # Don't clear cache in non-CI environments + if [ -z "${CI:-}" ]; then + echo "Not running in CI environment; skipping cache cleanup" + return + fi + + case "${ID}" in + debian | ubuntu) + apt-get clean + rm -rf /var/lib/apt/lists/* + ;; + + rhel | centos | rocky | almalinux) + dnf clean -y all + rm -rf /var/cache/dnf/* + ;; + esac +} + +function verify() { + # Verify that every expected library is now resolvable by the dynamic linker. + missing=0 + for lib in libasan.so.8 libtsan.so.2 libubsan.so.1; do + if ldconfig -p | grep -q "${lib}"; then + echo "OK: ${lib} found" + else + echo "ERROR: ${lib} not found after installation" >&2 + missing=$((missing + 1)) + fi + done + + if [ "${missing}" -ne 0 ]; then + echo "ERROR: ${missing} library/libraries missing" >&2 + exit 1 + fi +} + +preinstall +install +postinstall +verify + +echo "All sanitizer runtime libraries installed successfully." diff --git a/docker/loader-path.sh b/nix/docker/loader-path.sh similarity index 100% rename from docker/loader-path.sh rename to nix/docker/loader-path.sh diff --git a/docker/test_files/compile-cpp-sources.sh b/nix/docker/test_files/compile-cpp-sources.sh similarity index 100% rename from docker/test_files/compile-cpp-sources.sh rename to nix/docker/test_files/compile-cpp-sources.sh diff --git a/docker/test_files/cpp_sources/asan.cpp b/nix/docker/test_files/cpp_sources/asan.cpp similarity index 100% rename from docker/test_files/cpp_sources/asan.cpp rename to nix/docker/test_files/cpp_sources/asan.cpp diff --git a/docker/test_files/cpp_sources/regular.cpp b/nix/docker/test_files/cpp_sources/regular.cpp similarity index 100% rename from docker/test_files/cpp_sources/regular.cpp rename to nix/docker/test_files/cpp_sources/regular.cpp diff --git a/docker/test_files/cpp_sources/tsan.cpp b/nix/docker/test_files/cpp_sources/tsan.cpp similarity index 100% rename from docker/test_files/cpp_sources/tsan.cpp rename to nix/docker/test_files/cpp_sources/tsan.cpp diff --git a/docker/test_files/cpp_sources/ubsan.cpp b/nix/docker/test_files/cpp_sources/ubsan.cpp similarity index 100% rename from docker/test_files/cpp_sources/ubsan.cpp rename to nix/docker/test_files/cpp_sources/ubsan.cpp diff --git a/docker/test_files/run-test-binaries.sh b/nix/docker/test_files/run-test-binaries.sh similarity index 100% rename from docker/test_files/run-test-binaries.sh rename to nix/docker/test_files/run-test-binaries.sh diff --git a/nix/packages.nix b/nix/packages.nix index f282c15df9..d40472634b 100644 --- a/nix/packages.nix +++ b/nix/packages.nix @@ -12,8 +12,10 @@ in cmake conan curlMinimal # needed for codecov/codecov-action + doxygen gcovr git + git-cliff gnumake gnupg # needed for signing commits & codecov/codecov-action llvmPackages_22.clang-tools diff --git a/package/Dockerfile b/package/Dockerfile new file mode 100644 index 0000000000..6cb2a09933 --- /dev/null +++ b/package/Dockerfile @@ -0,0 +1,14 @@ +ARG BASE_IMAGE=debian:bookworm + +FROM ${BASE_IMAGE} + +# Packaging runs in a vanilla distro image, so the tooling has to come +# from the distro's archive: debhelper for deb, rpm-build (and the +# systemd / find-debuginfo macros it depends on) for rpm. +# The container also uses git (real history) for +# build_pkg.sh's SOURCE_DATE_EPOCH; otherwise it falls back to a tarball +# download and the timestamp comes from wall-clock time. + +COPY package/install-packaging-tools.sh /tmp/install-packaging-tools.sh + +RUN /tmp/install-packaging-tools.sh diff --git a/package/README.md b/package/README.md index 867ca273b4..9a1f76c597 100644 --- a/package/README.md +++ b/package/README.md @@ -22,25 +22,24 @@ package/ Packaging targets and their container images are declared in [`.github/scripts/strategy-matrix/linux.json`](../.github/scripts/strategy-matrix/linux.json) -via a `"package": true` field on specific os entries. Today only -`linux/amd64` is emitted; the architecture is hardcoded in `generate.py` -and the workflow runner. The package format +inside `package_configs` configurations. Today only +`linux/amd64` is emitted. The package format (deb or rpm) is inferred at build time from the container's package manager (`apt-get` -> deb, `dnf`/`yum` -> rpm). The image tag is composed as -`ghcr.io/xrplf/ci/{distro}-{version}:{compiler}-{cver}-sha-{image_sha}` — +`ghcr.io/xrplf/xrpld/packaging-:sha-` — the same scheme used by `reusable-build-test.yml`. Bump `image_sha` in `linux.json` and both CI and local builds pick up the new image with no workflow edits. | Package type | Image (derived from `linux.json`) | Tool required | | ------------ | ---------------------------------------------------- | --------------------------------------------------------------- | -| RPM | `ghcr.io/xrplf/ci/rhel-9:gcc-12-sha-` | `rpmbuild` | -| DEB | `ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12-sha-` | `dpkg-buildpackage`, `debhelper (>= 13)`, `dh-sequence-systemd` | +| RPM | `ghcr.io/xrplf/xrpld/packaging-rhel:sha-` | `rpmbuild` | +| DEB | `ghcr.io/xrplf/xrpld/packaging-debian:sha-` | `dpkg-buildpackage`, `debhelper (>= 13)`, `dh-sequence-systemd` | To print the exact image tags for the current `linux.json`: ```bash -./.github/scripts/strategy-matrix/generate.py --packaging --config=.github/scripts/strategy-matrix/linux.json +./.github/scripts/strategy-matrix/generate.py --packaging ``` ## Building packages diff --git a/package/install-packaging-tools.sh b/package/install-packaging-tools.sh new file mode 100755 index 0000000000..a26159a204 --- /dev/null +++ b/package/install-packaging-tools.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +set -euo pipefail + +if [ ! -f /etc/os-release ]; then + echo "ERROR: /etc/os-release not found; cannot detect OS" >&2 + exit 1 +fi + +# shellcheck source=/dev/null +. /etc/os-release + +echo "Detected OS: ${ID} ${VERSION_ID:-}" + +case "${ID}" in + ubuntu | debian | rhel | centos | rocky | almalinux) + echo "Supported OS detected: ${ID}" + ;; + *) + echo "ERROR: unsupported OS '${ID}'. Supported: debian, ubuntu, rhel-family" >&2 + exit 1 + ;; +esac + +function install() { + case "${ID}" in + debian | ubuntu) + apt-get update -y + apt-get install -y --no-install-recommends \ + ca-certificates \ + debhelper \ + debhelper-compat \ + dpkg-dev \ + git + ;; + + rhel | centos | rocky | almalinux) + dnf install -y --setopt=install_weak_deps=False \ + git \ + rpm-build \ + redhat-rpm-config \ + systemd-rpm-macros + ;; + esac +} + +function postinstall() { + # Don't clear cache in non-CI environments + if [ -z "${CI:-}" ]; then + echo "Not running in CI environment; skipping cache cleanup" + return + fi + + case "${ID}" in + debian | ubuntu) + apt-get clean + rm -rf /var/lib/apt/lists/* + ;; + + rhel | centos | rocky | almalinux) + dnf clean -y all + rm -rf /var/cache/dnf/* + ;; + esac +} + +install +postinstall diff --git a/src/libxrpl/basics/Log.cpp b/src/libxrpl/basics/Log.cpp index 1079f91280..d1e54a515f 100644 --- a/src/libxrpl/basics/Log.cpp +++ b/src/libxrpl/basics/Log.cpp @@ -61,7 +61,8 @@ Logs::File::open(boost::filesystem::path const& path) bool wasOpened = false; // VFALCO TODO Make this work with Unicode file paths - std::unique_ptr stream(new std::ofstream(path.c_str(), std::fstream::app)); + std::unique_ptr stream = + std::make_unique(path.c_str(), std::fstream::app); if (stream->good()) { diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index 275d82d8c9..23e913bbdc 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -1241,9 +1241,11 @@ root(Number f, unsigned d) } // Quadratic least squares curve fit of f^(1/d) in the range [0, 1] - auto const D = (((6 * di + 11) * di + 6) * di) + 1; // NOLINT(readability-identifier-naming) - auto const a0 = 3 * di * ((2 * di - 3) * di + 1); - auto const a1 = 24 * di * (2 * di - 1); + + // NOLINTNEXTLINE(readability-identifier-naming) + auto const D = (((((6 * di) + 11) * di) + 6) * di) + 1; + auto const a0 = 3 * di * ((((2 * di) - 3) * di) + 1); + auto const a1 = 24 * di * ((2 * di) - 1); auto const a2 = -30 * (di - 1) * di; Number r = ((Number{a2} * f + Number{a1}) * f + Number{a0}) / Number{D}; if (neg) diff --git a/src/libxrpl/beast/core/CurrentThreadName.cpp b/src/libxrpl/beast/core/CurrentThreadName.cpp index 52d9063179..628fec5b7a 100644 --- a/src/libxrpl/beast/core/CurrentThreadName.cpp +++ b/src/libxrpl/beast/core/CurrentThreadName.cpp @@ -71,7 +71,6 @@ setCurrentThreadNameImpl(std::string_view name) #if BOOST_OS_LINUX #include -#include #include // IWYU pragma: keep namespace beast::detail { diff --git a/src/libxrpl/net/HTTPClient.cpp b/src/libxrpl/net/HTTPClient.cpp index 78ee5eb577..4b9cc9d6e6 100644 --- a/src/libxrpl/net/HTTPClient.cpp +++ b/src/libxrpl/net/HTTPClient.cpp @@ -64,7 +64,7 @@ public: boost::asio::io_context& ioContext, unsigned short const port, std::size_t maxResponseSize, - beast::Journal& j) + beast::Journal const& j) : socket_( ioContext, gHttpClientSslContext->context()) // NOLINT(bugprone-unchecked-optional-access) @@ -552,7 +552,7 @@ HTTPClient::get( std::function< bool(boost::system::error_code const& ecResult, int iStatus, std::string const& strData)> complete, - beast::Journal& j) + beast::Journal const& j) { auto client = std::make_shared(ioContext, port, responseMax, j); client->get(bSSL, deqSites, strPath, timeout, complete); @@ -570,7 +570,7 @@ HTTPClient::get( std::function< bool(boost::system::error_code const& ecResult, int iStatus, std::string const& strData)> complete, - beast::Journal& j) + beast::Journal const& j) { std::deque const deqSites(1, strSite); @@ -590,7 +590,7 @@ HTTPClient::request( std::function< bool(boost::system::error_code const& ecResult, int iStatus, std::string const& strData)> complete, - beast::Journal& j) + beast::Journal const& j) { std::deque const deqSites(1, strSite); diff --git a/src/libxrpl/server/Port.cpp b/src/libxrpl/server/Port.cpp index 00c10b2b55..b3fd7a1526 100644 --- a/src/libxrpl/server/Port.cpp +++ b/src/libxrpl/server/Port.cpp @@ -26,8 +26,8 @@ namespace xrpl { bool Port::secure() const { - return protocol.count("peer") > 0 || protocol.count("https") > 0 || protocol.count("wss") > 0 || - protocol.count("wss2") > 0; + return protocol.contains("peer") || protocol.contains("https") || protocol.contains("wss") || + protocol.contains("wss2"); } std::string diff --git a/src/libxrpl/shamap/SHAMap.cpp b/src/libxrpl/shamap/SHAMap.cpp index 4aad255d81..8a521f6a47 100644 --- a/src/libxrpl/shamap/SHAMap.cpp +++ b/src/libxrpl/shamap/SHAMap.cpp @@ -206,7 +206,7 @@ SHAMap::finishFetch(SHAMapHash const& hash, std::shared_ptr const& o // See if a sync filter has a node SHAMapTreeNodePtr -SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const +SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter const* filter) const { if (auto nodeData = filter->getNode(hash)) { @@ -232,7 +232,7 @@ SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter* filter) const // Get a node without throwing // Used on maps where missing nodes are expected SHAMapTreeNodePtr -SHAMap::fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter* filter) const +SHAMap::fetchNodeNT(SHAMapHash const& hash, SHAMapSyncFilter const* filter) const { auto node = cacheLookup(hash); if (node) @@ -345,7 +345,7 @@ SHAMap::descend( SHAMapInnerNode* parent, SHAMapNodeID const& parentID, int branch, - SHAMapSyncFilter* filter) const + SHAMapSyncFilter const* filter) const { XRPL_ASSERT(parent->isInner(), "xrpl::SHAMap::descend : valid parent input"); XRPL_ASSERT( @@ -374,7 +374,7 @@ SHAMapTreeNode* SHAMap::descendAsync( SHAMapInnerNode* parent, int branch, - SHAMapSyncFilter* filter, + SHAMapSyncFilter const* filter, bool& pending, descendCallback&& callback) const { @@ -885,7 +885,7 @@ SHAMap::updateGiveItem(SHAMapNodeType type, boost::intrusive_ptrgetHash()) return true; diff --git a/src/libxrpl/shamap/SHAMapSync.cpp b/src/libxrpl/shamap/SHAMapSync.cpp index 0601bfefda..1f38049abe 100644 --- a/src/libxrpl/shamap/SHAMapSync.cpp +++ b/src/libxrpl/shamap/SHAMapSync.cpp @@ -305,7 +305,7 @@ SHAMap::gmnProcessDeferredReads(MissingNodes& mn) nodes that are not permanently stored locally */ std::vector> -SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) +SHAMap::getMissingNodes(int max, SHAMapSyncFilter const* filter) { XRPL_ASSERT(root_->getHash().isNonZero(), "xrpl::SHAMap::getMissingNodes : nonzero root hash"); XRPL_ASSERT(max > 0, "xrpl::SHAMap::getMissingNodes : valid max input"); @@ -507,7 +507,7 @@ SHAMap::serializeRoot(Serializer& s) const } SHAMapAddNode -SHAMap::addRootNode(SHAMapHash const& hash, Slice const& rootNode, SHAMapSyncFilter* filter) +SHAMap::addRootNode(SHAMapHash const& hash, Slice const& rootNode, SHAMapSyncFilter const* filter) { // we already have a root_ node if (root_->getHash().isNonZero()) @@ -542,7 +542,7 @@ SHAMap::addRootNode(SHAMapHash const& hash, Slice const& rootNode, SHAMapSyncFil } SHAMapAddNode -SHAMap::addKnownNode(SHAMapNodeID const& node, Slice const& rawNode, SHAMapSyncFilter* filter) +SHAMap::addKnownNode(SHAMapNodeID const& node, Slice const& rawNode, SHAMapSyncFilter const* filter) { XRPL_ASSERT(!node.isRoot(), "xrpl::SHAMap::addKnownNode : valid node input"); diff --git a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp index cfcf79fdba..05dcfea506 100644 --- a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp @@ -300,7 +300,7 @@ VaultWithdraw::doApply() << "VaultWithdraw: " // "Cannot burn all outstanding shares while unrealized loss is non-zero"; return tefINTERNAL; - // LCOV_EXCL_END + // LCOV_EXCL_STOP } STAmount const allAvailable{vaultAsset, *assetsAvailable}; diff --git a/src/test/app/AccountDelete_test.cpp b/src/test/app/AccountDelete_test.cpp index 951f99919b..65ff9ed839 100644 --- a/src/test/app/AccountDelete_test.cpp +++ b/src/test/app/AccountDelete_test.cpp @@ -813,7 +813,7 @@ public: env.close(); // alice create DepositPreauth Object - env(deposit::authCredentials(alice, {{carol, credType}})); + env(deposit::authCredentials(alice, {{.issuer = carol, .credType = credType}})); env.close(); // becky attempts to delete her account, but alice won't take her diff --git a/src/test/app/Batch_test.cpp b/src/test/app/Batch_test.cpp index 8755fe9f9c..791bb5a4d6 100644 --- a/src/test/app/Batch_test.cpp +++ b/src/test/app/Batch_test.cpp @@ -1017,7 +1017,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -1059,7 +1063,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -1101,7 +1109,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -1143,7 +1155,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -1185,7 +1201,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -1520,9 +1540,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1552,7 +1584,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); @@ -1581,7 +1617,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); @@ -1610,7 +1650,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); @@ -1662,10 +1706,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tecUNFUNDED_PAYMENT", txIDs[0], batchID}, - {2, "Payment", "tecUNFUNDED_PAYMENT", txIDs[1], batchID}, - {3, "Payment", "tecUNFUNDED_PAYMENT", txIDs[2], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[2], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1695,9 +1755,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tecUNFUNDED_PAYMENT", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1727,8 +1799,16 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1758,8 +1838,16 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1789,8 +1877,16 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1826,11 +1922,31 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "OfferCreate", "tecKILLED", txIDs[0], batchID}, - {2, "OfferCreate", "tecKILLED", txIDs[1], batchID}, - {3, "OfferCreate", "tecKILLED", txIDs[2], batchID}, - {4, "Payment", "tesSUCCESS", txIDs[3], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "OfferCreate", + .result = "tecKILLED", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "OfferCreate", + .result = "tecKILLED", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "OfferCreate", + .result = "tecKILLED", + .txHash = txIDs[2], + .batchID = batchID}, + {.index = 4, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[3], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1878,8 +1994,16 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tecUNFUNDED_PAYMENT", txIDs[0], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[0], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1909,11 +2033,31 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "Payment", "tesSUCCESS", txIDs[2], batchID}, - {4, "Payment", "tesSUCCESS", txIDs[3], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[2], + .batchID = batchID}, + {.index = 4, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[3], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1944,10 +2088,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "Payment", "tecUNFUNDED_PAYMENT", txIDs[2], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[2], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -1978,9 +2138,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2011,9 +2183,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2044,10 +2228,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "OfferCreate", "tecKILLED", txIDs[2], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "OfferCreate", + .result = "tecKILLED", + .txHash = txIDs[2], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2095,11 +2295,31 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tecUNFUNDED_PAYMENT", txIDs[1], batchID}, - {3, "Payment", "tecUNFUNDED_PAYMENT", txIDs[2], batchID}, - {4, "Payment", "tesSUCCESS", txIDs[3], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[2], + .batchID = batchID}, + {.index = 4, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[3], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2130,11 +2350,31 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "Payment", "tecUNFUNDED_PAYMENT", txIDs[2], batchID}, - {4, "Payment", "tesSUCCESS", txIDs[3], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tecUNFUNDED_PAYMENT", + .txHash = txIDs[2], + .batchID = batchID}, + {.index = 4, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[3], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2165,10 +2405,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "Payment", "tesSUCCESS", txIDs[3], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[3], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2199,10 +2455,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "Payment", "tesSUCCESS", txIDs[3], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[3], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2232,10 +2504,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "OfferCreate", "tecKILLED", txIDs[2], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "OfferCreate", + .result = "tecKILLED", + .txHash = txIDs[2], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2454,9 +2742,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "AccountSet", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "AccountSet", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2503,9 +2803,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "AccountSet", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "AccountSet", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2558,9 +2870,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "AccountDelete", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "AccountDelete", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2601,10 +2925,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "AccountDelete", "tecHAS_OBLIGATIONS", txIDs[1], batchID}, - {3, "Payment", "tesSUCCESS", txIDs[2], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "AccountDelete", + .result = "tecHAS_OBLIGATIONS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[2], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2642,7 +2982,11 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); @@ -2876,9 +3220,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "CheckCreate", "tesSUCCESS", txIDs[0], batchID}, - {2, "CheckCash", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "CheckCreate", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "CheckCash", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2922,9 +3278,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "CheckCreate", "tecDST_TAG_NEEDED", txIDs[0], batchID}, - {2, "CheckCash", "tecNO_ENTRY", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "CheckCreate", + .result = "tecDST_TAG_NEEDED", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "CheckCash", + .result = "tecNO_ENTRY", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -2987,10 +3355,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "TicketCreate", "tesSUCCESS", txIDs[0], batchID}, - {2, "CheckCreate", "tesSUCCESS", txIDs[1], batchID}, - {3, "CheckCash", "tesSUCCESS", txIDs[2], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "TicketCreate", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "CheckCreate", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "CheckCash", + .result = "tesSUCCESS", + .txHash = txIDs[2], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -3047,9 +3431,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "CheckCreate", "tesSUCCESS", txIDs[0], batchID}, - {2, "CheckCash", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "CheckCreate", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "CheckCash", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -3099,9 +3495,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -3147,9 +3555,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -3196,9 +3616,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -3257,9 +3689,21 @@ class Batch_test : public beast::unit_test::Suite { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -3268,7 +3712,11 @@ class Batch_test : public beast::unit_test::Suite { // next ledger contains noop txn std::vector const testCases = { - {0, "AccountSet", "tesSUCCESS", noopTxnID, std::nullopt}, + {.index = 0, + .txType = "AccountSet", + .result = "tesSUCCESS", + .txHash = noopTxnID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -3301,9 +3749,21 @@ class Batch_test : public beast::unit_test::Suite { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -3340,9 +3800,21 @@ class Batch_test : public beast::unit_test::Suite { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -3382,10 +3854,26 @@ class Batch_test : public beast::unit_test::Suite { std::vector const testCases = { - {0, "AccountSet", "tesSUCCESS", noopTxnID, std::nullopt}, - {1, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {2, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {3, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "AccountSet", + .result = "tesSUCCESS", + .txHash = noopTxnID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -3442,9 +3930,21 @@ class Batch_test : public beast::unit_test::Suite { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -3489,9 +3989,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -3552,10 +4064,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "CheckCreate", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "CheckCash", "tesSUCCESS", objTxnID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "CheckCreate", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "CheckCash", + .result = "tesSUCCESS", + .txHash = objTxnID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -3601,10 +4129,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "CheckCreate", "tesSUCCESS", objTxnID, std::nullopt}, - {1, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {2, "CheckCash", "tesSUCCESS", txIDs[0], batchID}, - {3, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "CheckCreate", + .result = "tesSUCCESS", + .txHash = objTxnID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 2, + .txType = "CheckCash", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -3646,10 +4190,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); { std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "CheckCreate", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, - {3, "CheckCash", "tesSUCCESS", objTxnID, std::nullopt}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "CheckCreate", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, + {.index = 3, + .txType = "CheckCash", + .result = "tesSUCCESS", + .txHash = objTxnID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -3742,10 +4302,26 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Payment", "tesSUCCESS", payTxn1ID, std::nullopt}, - {1, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {2, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {3, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = payTxn1ID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 3, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -3753,7 +4329,11 @@ class Batch_test : public beast::unit_test::Suite { // next ledger includes the payment txn std::vector const testCases = { - {0, "Payment", "tesSUCCESS", payTxn2ID, std::nullopt}, + {.index = 0, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = payTxn2ID, + .batchID = std::nullopt}, }; validateClosedLedger(env, testCases); } @@ -3965,9 +4545,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -4014,9 +4606,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "Payment", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -4064,9 +4668,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "AccountSet", "tesSUCCESS", txIDs[0], batchID}, - {2, "Payment", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "AccountSet", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "Payment", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); @@ -4126,9 +4742,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "MPTokenIssuanceSet", "tesSUCCESS", txIDs[0], batchID}, - {2, "MPTokenIssuanceSet", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "MPTokenIssuanceSet", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "MPTokenIssuanceSet", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -4167,9 +4795,21 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "TrustSet", "tesSUCCESS", txIDs[0], batchID}, - {2, "TrustSet", "tesSUCCESS", txIDs[1], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "TrustSet", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, + {.index = 2, + .txType = "TrustSet", + .result = "tesSUCCESS", + .txHash = txIDs[1], + .batchID = batchID}, }; validateClosedLedger(env, testCases); } @@ -4207,8 +4847,16 @@ class Batch_test : public beast::unit_test::Suite env.close(); std::vector const testCases = { - {0, "Batch", "tesSUCCESS", batchID, std::nullopt}, - {1, "TrustSet", "tesSUCCESS", txIDs[0], batchID}, + {.index = 0, + .txType = "Batch", + .result = "tesSUCCESS", + .txHash = batchID, + .batchID = std::nullopt}, + {.index = 1, + .txType = "TrustSet", + .result = "tesSUCCESS", + .txHash = txIDs[0], + .batchID = batchID}, // jv2 fails with terNO_DELEGATE_PERMISSION. }; validateClosedLedger(env, testCases); diff --git a/src/test/app/Credentials_test.cpp b/src/test/app/Credentials_test.cpp index 9416ca222f..456a53bc01 100644 --- a/src/test/app/Credentials_test.cpp +++ b/src/test/app/Credentials_test.cpp @@ -1078,7 +1078,7 @@ struct Credentials_test : public beast::unit_test::Suite } // Create DepositPreauth - env(deposit::authCredentials(becky, {{subject, credType}})); + env(deposit::authCredentials(becky, {{.issuer = subject, .credType = credType}})); env.close(); // env(); auto jtx = env.jt(pay(subject, becky, XRP(100)), credentials::Ids({credIdx})); @@ -1087,7 +1087,7 @@ struct Credentials_test : public beast::unit_test::Suite auto const stx = std::make_shared(*jtx.stx); // Create PermissionedDomain - env(pdomain::setTx(becky, {{issuer, credType}})); + env(pdomain::setTx(becky, {{.issuer = issuer, .credType = credType}})); env.close(); auto const objects = pdomain::getObjects(becky, env); if (!BEAST_EXPECT(!objects.empty())) diff --git a/src/test/app/CrossingLimitsMPT_test.cpp b/src/test/app/CrossingLimitsMPT_test.cpp index 4a016f31dc..8bd0c767f7 100644 --- a/src/test/app/CrossingLimitsMPT_test.cpp +++ b/src/test/app/CrossingLimitsMPT_test.cpp @@ -270,7 +270,7 @@ public: env.require(Balance(alice, usd(2'503))); env.require(Balance(alice, eur(1'100))); - auto const numAOffers = 2'000 + 100 + 1'000 + 1 - (2 * 100 + 2 * 199 + 1 + 1); + auto const numAOffers = 2'000 + 100 + 1'000 + 1 - ((2 * 100) + (2 * 199) + 1 + 1); env.require(offers(alice, numAOffers)); env.require(Owners(alice, numAOffers + 2)); @@ -358,7 +358,7 @@ public: env.require(Balance(alice, usd(2'494))); env.require(Balance(alice, eur(1'100))); auto const numAOffers = - 1 + 2'000 + 100 + 1'000 + 1 - (1 + 2 * 100 + 2 * 199 + 1 + 1); + 1 + 2'000 + 100 + 1'000 + 1 - (1 + (2 * 100) + (2 * 199) + 1 + 1); env.require(offers(alice, numAOffers)); env.require(Owners(alice, numAOffers + 2)); diff --git a/src/test/app/CrossingLimits_test.cpp b/src/test/app/CrossingLimits_test.cpp index 3cf8f50990..c48892f04e 100644 --- a/src/test/app/CrossingLimits_test.cpp +++ b/src/test/app/CrossingLimits_test.cpp @@ -258,7 +258,7 @@ public: env.require(Balance(alice, usd(2503))); env.require(Balance(alice, eur(1100))); - auto const numAOffers = 2000 + 100 + 1000 + 1 - (2 * 100 + 2 * 199 + 1 + 1); + auto const numAOffers = 2000 + 100 + 1000 + 1 - ((2 * 100) + (2 * 199) + 1 + 1); env.require(offers(alice, numAOffers)); env.require(Owners(alice, numAOffers + 2)); @@ -329,7 +329,7 @@ public: env.require(Balance(alice, usd(2494))); env.require(Balance(alice, eur(1100))); - auto const numAOffers = 1 + 2000 + 100 + 1000 + 1 - (1 + 2 * 100 + 2 * 199 + 1 + 1); + auto const numAOffers = 1 + 2000 + 100 + 1000 + 1 - (1 + (2 * 100) + (2 * 199) + 1 + 1); env.require(offers(alice, numAOffers)); env.require(Owners(alice, numAOffers + 2)); diff --git a/src/test/app/DepositAuth_test.cpp b/src/test/app/DepositAuth_test.cpp index 98597a175f..3496e67b54 100644 --- a/src/test/app/DepositAuth_test.cpp +++ b/src/test/app/DepositAuth_test.cpp @@ -614,7 +614,8 @@ struct DepositPreauth_test : public beast::unit_test::Suite TER const expectTer(!supportsCredentials ? TER(temDISABLED) : TER(tesSUCCESS)); - env(deposit::authCredentials(becky, {{carol, credType}}), Ter(expectTer)); + env(deposit::authCredentials(becky, {{.issuer = carol, .credType = credType}}), + Ter(expectTer)); env.close(); // gw accept credentials @@ -744,7 +745,8 @@ struct DepositPreauth_test : public beast::unit_test::Suite env.close(); // Setup DepositPreauth object failed - amendent is not supported - env(deposit::authCredentials(bob, {{issuer, credType}}), Ter(temDISABLED)); + env(deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}}), + Ter(temDISABLED)); env.close(); // But can create old DepositPreauth @@ -782,10 +784,11 @@ struct DepositPreauth_test : public beast::unit_test::Suite // Bob will accept payments from accounts with credentials signed // by 'issuer' - env(deposit::authCredentials(bob, {{issuer, credType}})); + env(deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}})); env.close(); - auto const jDP = ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + auto const jDP = + ledgerEntryDepositPreauth(env, bob, {{.issuer = issuer, .credType = credType}}); BEAST_EXPECT( jDP.isObject() && jDP.isMember(jss::result) && !jDP[jss::result].isMember(jss::error) && jDP[jss::result].isMember(jss::node) && @@ -858,11 +861,14 @@ struct DepositPreauth_test : public beast::unit_test::Suite } // Bob setup DepositPreauth object, duplicates is not allowed - env(deposit::authCredentials(bob, {{issuer, credType}, {issuer, credType}}), + env(deposit::authCredentials( + bob, + {{.issuer = issuer, .credType = credType}, + {.issuer = issuer, .credType = credType}}), Ter(temMALFORMED)); // Bob setup DepositPreauth object - env(deposit::authCredentials(bob, {{issuer, credType}})); + env(deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}})); env.close(); { @@ -928,35 +934,37 @@ struct DepositPreauth_test : public beast::unit_test::Suite { // both included [AuthorizeCredentials UnauthorizeCredentials] - auto jv = deposit::authCredentials(bob, {{issuer, credType}}); + auto jv = deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}}); jv[sfUnauthorizeCredentials.jsonName] = json::ValueType::Array; env(jv, Ter(temMALFORMED)); } { // both included [Unauthorize, AuthorizeCredentials] - auto jv = deposit::authCredentials(bob, {{issuer, credType}}); + auto jv = deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}}); jv[sfUnauthorize.jsonName] = issuer.human(); env(jv, Ter(temMALFORMED)); } { // both included [Authorize, AuthorizeCredentials] - auto jv = deposit::authCredentials(bob, {{issuer, credType}}); + auto jv = deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}}); jv[sfAuthorize.jsonName] = issuer.human(); env(jv, Ter(temMALFORMED)); } { // both included [Unauthorize, UnauthorizeCredentials] - auto jv = deposit::unauthCredentials(bob, {{issuer, credType}}); + auto jv = + deposit::unauthCredentials(bob, {{.issuer = issuer, .credType = credType}}); jv[sfUnauthorize.jsonName] = issuer.human(); env(jv, Ter(temMALFORMED)); } { // both included [Authorize, UnauthorizeCredentials] - auto jv = deposit::unauthCredentials(bob, {{issuer, credType}}); + auto jv = + deposit::unauthCredentials(bob, {{.issuer = issuer, .credType = credType}}); jv[sfAuthorize.jsonName] = issuer.human(); env(jv, Ter(temMALFORMED)); } @@ -983,7 +991,7 @@ struct DepositPreauth_test : public beast::unit_test::Suite { // empty credential type - auto jv = deposit::authCredentials(bob, {{issuer, {}}}); + auto jv = deposit::authCredentials(bob, {{.issuer = issuer, .credType = {}}}); env(jv, Ter(temMALFORMED)); } @@ -993,14 +1001,23 @@ struct DepositPreauth_test : public beast::unit_test::Suite i("i"); auto const& z = credType; auto jv = deposit::authCredentials( - bob, {{a, z}, {b, z}, {c, z}, {d, z}, {e, z}, {f, z}, {g, z}, {h, z}, {i, z}}); + bob, + {{.issuer = a, .credType = z}, + {.issuer = b, .credType = z}, + {.issuer = c, .credType = z}, + {.issuer = d, .credType = z}, + {.issuer = e, .credType = z}, + {.issuer = f, .credType = z}, + {.issuer = g, .credType = z}, + {.issuer = h, .credType = z}, + {.issuer = i, .credType = z}}); env(jv, Ter(temARRAY_TOO_LARGE)); } { // Can't create with non-existing issuer Account const rick{"rick"}; - auto jv = deposit::authCredentials(bob, {{rick, credType}}); + auto jv = deposit::authCredentials(bob, {{.issuer = rick, .credType = credType}}); env(jv, Ter(tecNO_ISSUER)); env.close(); } @@ -1010,21 +1027,24 @@ struct DepositPreauth_test : public beast::unit_test::Suite Account const john{"john"}; env.fund(env.current()->fees().accountReserve(0), john); env.close(); - auto jv = deposit::authCredentials(john, {{issuer, credType}}); + auto jv = + deposit::authCredentials(john, {{.issuer = issuer, .credType = credType}}); env(jv, Ter(tecINSUFFICIENT_RESERVE)); } { // NO deposit object exists - env(deposit::unauthCredentials(bob, {{issuer, credType}}), Ter(tecNO_ENTRY)); + env(deposit::unauthCredentials(bob, {{.issuer = issuer, .credType = credType}}), + Ter(tecNO_ENTRY)); } // Create DepositPreauth object { - env(deposit::authCredentials(bob, {{issuer, credType}})); + env(deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}})); env.close(); - auto const jDP = ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + auto const jDP = + ledgerEntryDepositPreauth(env, bob, {{.issuer = issuer, .credType = credType}}); BEAST_EXPECT( jDP.isObject() && jDP.isMember(jss::result) && !jDP[jss::result].isMember(jss::error) && @@ -1045,14 +1065,16 @@ struct DepositPreauth_test : public beast::unit_test::Suite } // can't create duplicate - env(deposit::authCredentials(bob, {{issuer, credType}}), Ter(tecDUPLICATE)); + env(deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}}), + Ter(tecDUPLICATE)); } // Delete DepositPreauth object { - env(deposit::unauthCredentials(bob, {{issuer, credType}})); + env(deposit::unauthCredentials(bob, {{.issuer = issuer, .credType = credType}})); env.close(); - auto const jDP = ledgerEntryDepositPreauth(env, bob, {{issuer, credType}}); + auto const jDP = + ledgerEntryDepositPreauth(env, bob, {{.issuer = issuer, .credType = credType}}); BEAST_EXPECT( jDP.isObject() && jDP.isMember(jss::result) && jDP[jss::result].isMember(jss::error) && @@ -1119,7 +1141,10 @@ struct DepositPreauth_test : public beast::unit_test::Suite env(fset(bob, asfDepositAuth)); env.close(); // Bob setup DepositPreauth object - env(deposit::authCredentials(bob, {{issuer, credType}, {issuer, credType2}})); + env(deposit::authCredentials( + bob, + {{.issuer = issuer, .credType = credType}, + {.issuer = issuer, .credType = credType2}})); env.close(); { @@ -1228,7 +1253,7 @@ struct DepositPreauth_test : public beast::unit_test::Suite env(fset(bob, asfDepositAuth)); env.close(); // Bob setup DepositPreauth object - env(deposit::authCredentials(bob, {{issuer, credType}})); + env(deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}})); env.close(); auto const seq = env.seq(alice); @@ -1286,14 +1311,14 @@ struct DepositPreauth_test : public beast::unit_test::Suite env.fund(XRP(5000), stock, alice, bob); std::vector credentials = { - {"a", "a"}, - {"b", "b"}, - {"c", "c"}, - {"d", "d"}, - {"e", "e"}, - {"f", "f"}, - {"g", "g"}, - {"h", "h"}}; + {.issuer = "a", .credType = "a"}, + {.issuer = "b", .credType = "b"}, + {.issuer = "c", .credType = "c"}, + {.issuer = "d", .credType = "d"}, + {.issuer = "e", .credType = "e"}, + {.issuer = "f", .credType = "f"}, + {.issuer = "g", .credType = "g"}, + {.issuer = "h", .credType = "h"}}; for (auto const& c : credentials) env.fund(XRP(5000), c.issuer); diff --git a/src/test/app/Escrow_test.cpp b/src/test/app/Escrow_test.cpp index 3e76524cf1..5623bc4443 100644 --- a/src/test/app/Escrow_test.cpp +++ b/src/test/app/Escrow_test.cpp @@ -1544,7 +1544,7 @@ struct Escrow_test : public beast::unit_test::Suite credentials::Ids({credIdx}), Ter(tecNO_PERMISSION)); - env(deposit::authCredentials(bob, {{zelda, credType}})); + env(deposit::authCredentials(bob, {{.issuer = zelda, .credType = credType}})); env.close(); // Success @@ -1601,7 +1601,7 @@ struct Escrow_test : public beast::unit_test::Suite // Bob require pre-authorization env(fset(bob, asfDepositAuth)); env.close(); - env(deposit::authCredentials(bob, {{zelda, credType}})); + env(deposit::authCredentials(bob, {{.issuer = zelda, .credType = credType}})); env.close(); // Use any valid credentials if account == dst diff --git a/src/test/app/LedgerReplay_test.cpp b/src/test/app/LedgerReplay_test.cpp index 1978d04fe1..810d93e6e1 100644 --- a/src/test/app/LedgerReplay_test.cpp +++ b/src/test/app/LedgerReplay_test.cpp @@ -549,7 +549,7 @@ struct LedgerServer while (senders.contains(fromIdx)) fromIdx = (fromIdx + 1) % fundedAccounts; senders.insert(fromIdx); - toIdx = (toIdx + r * 2) % fundedAccounts; + toIdx = (toIdx + (r * 2)) % fundedAccounts; if (toIdx == fromIdx) toIdx = (toIdx + 1) % fundedAccounts; }; diff --git a/src/test/app/PayStrand_test.cpp b/src/test/app/PayStrand_test.cpp index 67a37833b2..471c641f36 100644 --- a/src/test/app/PayStrand_test.cpp +++ b/src/test/app/PayStrand_test.cpp @@ -632,7 +632,13 @@ struct PayStrand_test : public beast::unit_test::Suite // Insert implied account test( - env, usd, std::nullopt, STPath(), tesSUCCESS, D{alice, gw, usdC}, D{gw, bob, usdC}); + env, + usd, + std::nullopt, + STPath(), + tesSUCCESS, + D{.src = alice, .dst = gw, .currency = usdC}, + D{.src = gw, .dst = bob, .currency = usdC}); env.trust(eur(1000), alice, bob); // Insert implied offer @@ -642,9 +648,9 @@ struct PayStrand_test : public beast::unit_test::Suite usd, STPath(), tesSUCCESS, - D{alice, gw, usdC}, + D{.src = alice, .dst = gw, .currency = usdC}, B{usd, eur, std::nullopt}, - D{gw, bob, eurC}); + D{.src = gw, .dst = bob, .currency = eurC}); // Path with explicit offer test( @@ -653,9 +659,9 @@ struct PayStrand_test : public beast::unit_test::Suite usd, STPath({ipe(eur)}), tesSUCCESS, - D{alice, gw, usdC}, + D{.src = alice, .dst = gw, .currency = usdC}, B{usd, eur, std::nullopt}, - D{gw, bob, eurC}); + D{.src = gw, .dst = bob, .currency = eurC}); // Path with offer that changes issuer only env.trust(carol["USD"](1000), bob); @@ -665,9 +671,9 @@ struct PayStrand_test : public beast::unit_test::Suite usd, STPath({iape(carol)}), tesSUCCESS, - D{alice, gw, usdC}, + D{.src = alice, .dst = gw, .currency = usdC}, B{usd, carol["USD"], std::nullopt}, - D{carol, bob, usdC}); + D{.src = carol, .dst = bob, .currency = usdC}); // Path with XRP src currency test( @@ -678,7 +684,7 @@ struct PayStrand_test : public beast::unit_test::Suite tesSUCCESS, XRPS{alice}, B{XRP, usd, std::nullopt}, - D{gw, bob, usdC}); + D{.src = gw, .dst = bob, .currency = usdC}); // Path with XRP dst currency. test( @@ -688,7 +694,7 @@ struct PayStrand_test : public beast::unit_test::Suite STPath({STPathElement{ STPathElement::TypeCurrency, xrpAccount(), xrpCurrency(), xrpAccount()}}), tesSUCCESS, - D{alice, gw, usdC}, + D{.src = alice, .dst = gw, .currency = usdC}, B{usd, XRP, std::nullopt}, XRPS{bob}); @@ -699,10 +705,10 @@ struct PayStrand_test : public beast::unit_test::Suite usd, STPath({cpe(xrpCurrency())}), tesSUCCESS, - D{alice, gw, usdC}, + D{.src = alice, .dst = gw, .currency = usdC}, B{usd, XRP, std::nullopt}, B{XRP, eur, std::nullopt}, - D{gw, bob, eurC}); + D{.src = gw, .dst = bob, .currency = eurC}); // XRP -> XRP transaction can't include a path test(env, XRP, std::nullopt, STPath({ape(carol)}), temBAD_PATH); diff --git a/src/test/app/PermissionedDEX_test.cpp b/src/test/app/PermissionedDEX_test.cpp index a88cbaa868..d534f20248 100644 --- a/src/test/app/PermissionedDEX_test.cpp +++ b/src/test/app/PermissionedDEX_test.cpp @@ -704,7 +704,8 @@ class PermissionedDEX_test : public beast::unit_test::Suite env.close(); auto const badCredType = "badCred"; - pdomain::Credentials const credentials{{badDomainOwner, badCredType}}; + pdomain::Credentials const credentials{ + {.issuer = badDomainOwner, .credType = badCredType}}; env(pdomain::setTx(badDomainOwner, credentials)); auto objects = pdomain::getObjects(badDomainOwner, env); @@ -1222,7 +1223,8 @@ class PermissionedDEX_test : public beast::unit_test::Suite env.close(); auto const badCredType = "badCred"; - pdomain::Credentials const credentials{{badDomainOwner, badCredType}}; + pdomain::Credentials const credentials{ + {.issuer = badDomainOwner, .credType = badCredType}}; env(pdomain::setTx(badDomainOwner, credentials)); auto objects = pdomain::getObjects(badDomainOwner, env); diff --git a/src/test/app/PermissionedDomains_test.cpp b/src/test/app/PermissionedDomains_test.cpp index 0857a4bdef..f2d7bce152 100644 --- a/src/test/app/PermissionedDomains_test.cpp +++ b/src/test/app/PermissionedDomains_test.cpp @@ -62,7 +62,7 @@ class PermissionedDomains_test : public beast::unit_test::Suite Account const alice("alice"); Env env(*this, features); env.fund(XRP(1000), alice); - pdomain::Credentials const credentials{{alice, "first credential"}}; + pdomain::Credentials const credentials{{.issuer = alice, .credType = "first credential"}}; env(pdomain::setTx(alice, credentials)); BEAST_EXPECT(env.ownerCount(alice) == 1); auto objects = pdomain::getObjects(alice, env); @@ -84,7 +84,7 @@ class PermissionedDomains_test : public beast::unit_test::Suite Account const alice("alice"); Env env(*this, amendments); env.fund(XRP(1000), alice); - pdomain::Credentials const credentials{{alice, "first credential"}}; + pdomain::Credentials const credentials{{.issuer = alice, .credType = "first credential"}}; env(pdomain::setTx(alice, credentials), Ter(temDISABLED)); } @@ -96,7 +96,7 @@ class PermissionedDomains_test : public beast::unit_test::Suite Account const alice("alice"); Env env(*this, testableAmendments() - featurePermissionedDomains); env.fund(XRP(1000), alice); - pdomain::Credentials const credentials{{alice, "first credential"}}; + pdomain::Credentials const credentials{{.issuer = alice, .credType = "first credential"}}; env(pdomain::setTx(alice, credentials), Ter(temDISABLED)); env(pdomain::deleteTx(alice, uint256(75)), Ter(temDISABLED)); } @@ -124,40 +124,40 @@ class PermissionedDomains_test : public beast::unit_test::Suite // Test 11 credentials. pdomain::Credentials const credentials11{ - {alice2, "credential1"}, - {alice3, "credential2"}, - {alice4, "credential3"}, - {alice5, "credential4"}, - {alice6, "credential5"}, - {alice7, "credential6"}, - {alice8, "credential7"}, - {alice9, "credential8"}, - {alice10, "credential9"}, - {alice11, "credential10"}, - {alice12, "credential11"}}; + {.issuer = alice2, .credType = "credential1"}, + {.issuer = alice3, .credType = "credential2"}, + {.issuer = alice4, .credType = "credential3"}, + {.issuer = alice5, .credType = "credential4"}, + {.issuer = alice6, .credType = "credential5"}, + {.issuer = alice7, .credType = "credential6"}, + {.issuer = alice8, .credType = "credential7"}, + {.issuer = alice9, .credType = "credential8"}, + {.issuer = alice10, .credType = "credential9"}, + {.issuer = alice11, .credType = "credential10"}, + {.issuer = alice12, .credType = "credential11"}}; BEAST_EXPECT(credentials11.size() == kMaxPermissionedDomainCredentialsArraySize + 1); env(pdomain::setTx(account, credentials11, domain), Ter(temARRAY_TOO_LARGE)); // Test credentials including non-existent issuer. Account const nobody("nobody"); pdomain::Credentials const credentialsNon{ - {alice2, "credential1"}, - {alice3, "credential2"}, - {alice4, "credential3"}, - {nobody, "credential4"}, - {alice5, "credential5"}, - {alice6, "credential6"}, - {alice7, "credential7"}}; + {.issuer = alice2, .credType = "credential1"}, + {.issuer = alice3, .credType = "credential2"}, + {.issuer = alice4, .credType = "credential3"}, + {.issuer = nobody, .credType = "credential4"}, + {.issuer = alice5, .credType = "credential5"}, + {.issuer = alice6, .credType = "credential6"}, + {.issuer = alice7, .credType = "credential7"}}; env(pdomain::setTx(account, credentialsNon, domain), Ter(tecNO_ISSUER)); // Test bad fee env(pdomain::setTx(account, credentials11, domain), Fee(1, true), Ter(temBAD_FEE)); pdomain::Credentials const credentials4{ - {alice2, "credential1"}, - {alice3, "credential2"}, - {alice4, "credential3"}, - {alice5, "credential4"}, + {.issuer = alice2, .credType = "credential1"}, + {.issuer = alice3, .credType = "credential2"}, + {.issuer = alice4, .credType = "credential3"}, + {.issuer = alice5, .credType = "credential4"}, }; auto txJsonMutable = pdomain::setTx(account, credentials4, domain); auto const credentialOrig = txJsonMutable["AcceptedCredentials"][2u]; @@ -192,11 +192,11 @@ class PermissionedDomains_test : public beast::unit_test::Suite // permissioned domains, so transactions should return errors { pdomain::Credentials const credentialsDup{ - {alice7, "credential6"}, - {alice2, "credential1"}, - {alice3, "credential2"}, - {alice2, "credential1"}, - {alice5, "credential4"}, + {.issuer = alice7, .credType = "credential6"}, + {.issuer = alice2, .credType = "credential1"}, + {.issuer = alice3, .credType = "credential2"}, + {.issuer = alice2, .credType = "credential1"}, + {.issuer = alice5, .credType = "credential4"}, }; std::unordered_map human2Acc; @@ -230,11 +230,11 @@ class PermissionedDomains_test : public beast::unit_test::Suite // sort correctly. { pdomain::Credentials const credentialsSame{ - {alice2, "credential3"}, - {alice3, "credential2"}, - {alice2, "credential9"}, - {alice5, "credential4"}, - {alice2, "credential6"}, + {.issuer = alice2, .credType = "credential3"}, + {.issuer = alice3, .credType = "credential2"}, + {.issuer = alice2, .credType = "credential9"}, + {.issuer = alice5, .credType = "credential4"}, + {.issuer = alice2, .credType = "credential6"}, }; std::unordered_map human2Acc; for (auto const& c : credentialsSame) @@ -290,7 +290,7 @@ class PermissionedDomains_test : public beast::unit_test::Suite env.fund(XRP(1000), alice[i]); // Create new from existing account with a single credential. - pdomain::Credentials const credentials1{{alice[2], "credential1"}}; + pdomain::Credentials const credentials1{{.issuer = alice[2], .credType = "credential1"}}; { env(pdomain::setTx(alice[0], credentials1)); BEAST_EXPECT(env.ownerCount(alice[0]) == 1); @@ -314,7 +314,7 @@ class PermissionedDomains_test : public beast::unit_test::Suite "89"; static_assert(kLongCredentialType.size() == kMaxCredentialTypeLength); pdomain::Credentials const longCredentials{ - {alice[1], std::string(kLongCredentialType)}}; + {.issuer = alice[1], .credType = std::string(kLongCredentialType)}}; env(pdomain::setTx(alice[0], longCredentials)); @@ -345,16 +345,16 @@ class PermissionedDomains_test : public beast::unit_test::Suite // Create new from existing account with 10 credentials. // Last credential describe domain owner itself pdomain::Credentials const credentials10{ - {alice[2], "credential1"}, - {alice[3], "credential2"}, - {alice[4], "credential3"}, - {alice[5], "credential4"}, - {alice[6], "credential5"}, - {alice[7], "credential6"}, - {alice[8], "credential7"}, - {alice[9], "credential8"}, - {alice[10], "credential9"}, - {alice[0], "credential10"}, + {.issuer = alice[2], .credType = "credential1"}, + {.issuer = alice[3], .credType = "credential2"}, + {.issuer = alice[4], .credType = "credential3"}, + {.issuer = alice[5], .credType = "credential4"}, + {.issuer = alice[6], .credType = "credential5"}, + {.issuer = alice[7], .credType = "credential6"}, + {.issuer = alice[8], .credType = "credential7"}, + {.issuer = alice[9], .credType = "credential8"}, + {.issuer = alice[10], .credType = "credential9"}, + {.issuer = alice[0], .credType = "credential10"}, }; uint256 domain2; { @@ -434,7 +434,7 @@ class PermissionedDomains_test : public beast::unit_test::Suite env.fund(XRP(1000), alice); auto const setFee(drops(env.current()->fees().increment)); - pdomain::Credentials const credentials{{alice, "first credential"}}; + pdomain::Credentials const credentials{{.issuer = alice, .credType = "first credential"}}; env(pdomain::setTx(alice, credentials)); env.close(); @@ -498,7 +498,7 @@ class PermissionedDomains_test : public beast::unit_test::Suite BEAST_EXPECT(env.ownerCount(alice) == 0); // alice does not have enough XRP to cover the reserve. - pdomain::Credentials const credentials{{alice, "first credential"}}; + pdomain::Credentials const credentials{{.issuer = alice, .credType = "first credential"}}; env(pdomain::setTx(alice, credentials), Ter(tecINSUFFICIENT_RESERVE)); BEAST_EXPECT(env.ownerCount(alice) == 0); BEAST_EXPECT(pdomain::getObjects(alice, env).empty()); diff --git a/src/test/app/TxQ_test.cpp b/src/test/app/TxQ_test.cpp index 8333fce3b3..dc28388de4 100644 --- a/src/test/app/TxQ_test.cpp +++ b/src/test/app/TxQ_test.cpp @@ -1228,7 +1228,7 @@ public: // Try to replace a middle item in the queue // with enough fee to bankrupt bob and make the // later transactions unable to pay their fees - std::int64_t bobFee = env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - (9 * 10 - 1); + std::int64_t bobFee = env.le(bob)->getFieldAmount(sfBalance).xrp().drops() - ((9 * 10) - 1); env(noop(bob), Seq(bobSeq + 5), Fee(bobFee), Ter(telCAN_NOT_QUEUE_BALANCE)); checkMetrics(*this, env, 10, 12, 7, 6); diff --git a/src/test/app/ValidatorList_test.cpp b/src/test/app/ValidatorList_test.cpp index 20a3557db5..80483446a2 100644 --- a/src/test/app/ValidatorList_test.cpp +++ b/src/test/app/ValidatorList_test.cpp @@ -632,7 +632,11 @@ private: checkResult( trustedKeys->applyLists( - manifest1, version, {{expiredblob, expiredSig, {}}, {blob2, sig2, {}}}, siteUri), + manifest1, + version, + {{.blob = expiredblob, .signature = expiredSig, .manifest = {}}, + {.blob = blob2, .signature = sig2, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Expired, ListDisposition::Accepted); @@ -665,7 +669,11 @@ private: checkResult( trustedKeys->applyLists( - manifest1, version2, {{blob7, sig7, {}}, {blob8, sig8, {}}}, siteUri), + manifest1, + version2, + {{.blob = blob7, .signature = sig7, .manifest = {}}, + {.blob = blob8, .signature = sig8, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Pending, ListDisposition::Pending); @@ -697,7 +705,11 @@ private: checkResult( trustedKeys->applyLists( - manifest1, version, {{blob6a, sig6a, {}}, {blob6, sig6, {}}}, siteUri), + manifest1, + version, + {{.blob = blob6a, .signature = sig6a, .manifest = {}}, + {.blob = blob6, .signature = sig6, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Pending, ListDisposition::Pending); @@ -709,7 +721,11 @@ private: checkResult( trustedKeys->applyLists( - manifest1, version, {{blob7, sig7, {}}, {blob6, sig6, {}}}, siteUri), + manifest1, + version, + {{.blob = blob7, .signature = sig7, .manifest = {}}, + {.blob = blob6, .signature = sig6, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::KnownSequence, ListDisposition::KnownSequence); @@ -720,7 +736,12 @@ private: // try empty or mangled manifest checkResult( - trustedKeys->applyLists("", version, {{blob7, sig7, {}}, {blob6, sig6, {}}}, siteUri), + trustedKeys->applyLists( + "", + version, + {{.blob = blob7, .signature = sig7, .manifest = {}}, + {.blob = blob6, .signature = sig6, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Invalid, ListDisposition::Invalid); @@ -729,7 +750,8 @@ private: trustedKeys->applyLists( base64Encode("not a manifest"), version, - {{blob7, sig7, {}}, {blob6, sig6, {}}}, + {{.blob = blob7, .signature = sig7, .manifest = {}}, + {.blob = blob6, .signature = sig6, .manifest = {}}}, siteUri), publisherPublic, ListDisposition::Invalid, @@ -740,7 +762,11 @@ private: randomMasterKey(), publisherSecret, pubSigningKeys1.first, pubSigningKeys1.second, 1)); checkResult( - trustedKeys->applyLists(untrustedManifest, version, {{blob2, sig2, {}}}, siteUri), + trustedKeys->applyLists( + untrustedManifest, + version, + {{.blob = blob2, .signature = sig2, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Untrusted, ListDisposition::Untrusted); @@ -748,7 +774,11 @@ private: // do not use list with unhandled version auto const badVersion = 666; checkResult( - trustedKeys->applyLists(manifest1, badVersion, {{blob2, sig2, {}}}, siteUri), + trustedKeys->applyLists( + manifest1, + badVersion, + {{.blob = blob2, .signature = sig2, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::UnsupportedVersion, ListDisposition::UnsupportedVersion); @@ -759,7 +789,8 @@ private: auto const sig3 = signList(blob3, pubSigningKeys1); checkResult( - trustedKeys->applyLists(manifest1, version, {{blob3, sig3, {}}}, siteUri), + trustedKeys->applyLists( + manifest1, version, {{.blob = blob3, .signature = sig3, .manifest = {}}}, siteUri), publisherPublic, ListDisposition::Accepted, ListDisposition::Accepted); @@ -780,7 +811,11 @@ private: // do not re-apply lists with past or current sequence numbers checkResult( trustedKeys->applyLists( - manifest1, version, {{blob2, sig2, {}}, {blob3, sig3, {}}}, siteUri), + manifest1, + version, + {{.blob = blob2, .signature = sig2, .manifest = {}}, + {.blob = blob3, .signature = sig3, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Stale, ListDisposition::SameSequence); @@ -799,7 +834,9 @@ private: trustedKeys->applyLists( manifest2, version, - {{blob2, sig2, manifest1}, {blob3, sig3, manifest1}, {blob4, sig4, {}}}, + {{.blob = blob2, .signature = sig2, .manifest = manifest1}, + {.blob = blob3, .signature = sig3, .manifest = manifest1}, + {.blob = blob4, .signature = sig4, .manifest = {}}}, siteUri), publisherPublic, ListDisposition::Stale, @@ -820,7 +857,11 @@ private: auto const blob5 = makeList(lists.at(5), sequence5, validUntil.time_since_epoch().count()); auto const badSig = signList(blob5, pubSigningKeys1); checkResult( - trustedKeys->applyLists(manifest1, version, {{blob5, badSig, {}}}, siteUri), + trustedKeys->applyLists( + manifest1, + version, + {{.blob = blob5, .signature = badSig, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Invalid, ListDisposition::Invalid); @@ -833,7 +874,11 @@ private: // Reprocess the pending list, but the signature is no longer valid checkResult( trustedKeys->applyLists( - manifest1, version, {{blob7, sig7, {}}, {blob8, sig8, {}}}, siteUri), + manifest1, + version, + {{.blob = blob7, .signature = sig7, .manifest = {}}, + {.blob = blob8, .signature = sig8, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Invalid, ListDisposition::Invalid); @@ -884,7 +929,11 @@ private: checkResult( trustedKeys->applyLists( - manifest2, version, {{blob8, sig8, manifest1}, {blob8, sig82, {}}}, siteUri), + manifest2, + version, + {{.blob = blob8, .signature = sig8, .manifest = manifest1}, + {.blob = blob8, .signature = sig82, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Invalid, ListDisposition::SameSequence); @@ -903,7 +952,11 @@ private: auto const sig9 = signList(blob9, signingKeysMax); checkResult( - trustedKeys->applyLists(maxManifest, version, {{blob9, sig9, {}}}, siteUri), + trustedKeys->applyLists( + maxManifest, + version, + {{.blob = blob9, .signature = sig9, .manifest = {}}}, + siteUri), publisherPublic, ListDisposition::Untrusted, ListDisposition::Untrusted); @@ -1900,7 +1953,9 @@ private: return PreparedList{ .publisherPublic = publisherPublic, .manifest = manifest, - .blobs = {{blob1, sig1, {}}, {blob2, sig2, {}}}, + .blobs = + {{.blob = blob1, .signature = sig1, .manifest = {}}, + {.blob = blob2, .signature = sig2, .manifest = {}}}, .version = version, .expirations = {expiration1, expiration2}}; }; diff --git a/src/test/app/ValidatorSite_test.cpp b/src/test/app/ValidatorSite_test.cpp index f7f805faa2..e3e3ec27df 100644 --- a/src/test/app/ValidatorSite_test.cpp +++ b/src/test/app/ValidatorSite_test.cpp @@ -380,226 +380,333 @@ public: for (auto ssl : {true, false}) { // fetch single site - testFetchList(good, {{"/validators", "", ssl}}); - testFetchList(good, {{"/validators2", "", ssl}}); + testFetchList(good, {{.path = "/validators", .msg = "", .ssl = ssl}}); + testFetchList(good, {{.path = "/validators2", .msg = "", .ssl = ssl}}); // fetch multiple sites - testFetchList(good, {{"/validators", "", ssl}, {"/validators", "", ssl}}); - testFetchList(good, {{"/validators", "", ssl}, {"/validators2", "", ssl}}); - testFetchList(good, {{"/validators2", "", ssl}, {"/validators", "", ssl}}); - testFetchList(good, {{"/validators2", "", ssl}, {"/validators2", "", ssl}}); + testFetchList( + good, + {{.path = "/validators", .msg = "", .ssl = ssl}, + {.path = "/validators", .msg = "", .ssl = ssl}}); + testFetchList( + good, + {{.path = "/validators", .msg = "", .ssl = ssl}, + {.path = "/validators2", .msg = "", .ssl = ssl}}); + testFetchList( + good, + {{.path = "/validators2", .msg = "", .ssl = ssl}, + {.path = "/validators", .msg = "", .ssl = ssl}}); + testFetchList( + good, + {{.path = "/validators2", .msg = "", .ssl = ssl}, + {.path = "/validators2", .msg = "", .ssl = ssl}}); // fetch single site with single redirects - testFetchList(good, {{"/redirect_once/301", "", ssl}}); - testFetchList(good, {{"/redirect_once/302", "", ssl}}); - testFetchList(good, {{"/redirect_once/307", "", ssl}}); - testFetchList(good, {{"/redirect_once/308", "", ssl}}); + testFetchList(good, {{.path = "/redirect_once/301", .msg = "", .ssl = ssl}}); + testFetchList(good, {{.path = "/redirect_once/302", .msg = "", .ssl = ssl}}); + testFetchList(good, {{.path = "/redirect_once/307", .msg = "", .ssl = ssl}}); + testFetchList(good, {{.path = "/redirect_once/308", .msg = "", .ssl = ssl}}); // one redirect, one not - testFetchList(good, {{"/validators", "", ssl}, {"/redirect_once/302", "", ssl}}); - testFetchList(good, {{"/validators2", "", ssl}, {"/redirect_once/302", "", ssl}}); + testFetchList( + good, + {{.path = "/validators", .msg = "", .ssl = ssl}, + {.path = "/redirect_once/302", .msg = "", .ssl = ssl}}); + testFetchList( + good, + {{.path = "/validators2", .msg = "", .ssl = ssl}, + {.path = "/redirect_once/302", .msg = "", .ssl = ssl}}); // UNLs with a "gap" between validUntil of one and validFrom of the // next testFetchList( good, - {{"/validators2", - "", - ssl, - false, - false, - 1, - detail::kDefaultExpires, - std::chrono::seconds{-90}}}); + {{.path = "/validators2", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = detail::kDefaultExpires, + .effectiveOverlap = std::chrono::seconds{-90}}}); // fetch single site with unending redirect (fails to load) testFetchList( - good, {{"/redirect_forever/301", "Exceeded max redirects", ssl, true, true}}); + good, + {{.path = "/redirect_forever/301", + .msg = "Exceeded max redirects", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // two that redirect forever testFetchList( good, - {{"/redirect_forever/307", "Exceeded max redirects", ssl, true, true}, - {"/redirect_forever/308", "Exceeded max redirects", ssl, true, true}}); + {{.path = "/redirect_forever/307", + .msg = "Exceeded max redirects", + .ssl = ssl, + .failFetch = true, + .failApply = true}, + {.path = "/redirect_forever/308", + .msg = "Exceeded max redirects", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // one unending redirect, one not testFetchList( good, - {{"/validators", "", ssl}, - {"/redirect_forever/302", "Exceeded max redirects", ssl, true, true}}); + {{.path = "/validators", .msg = "", .ssl = ssl}, + {.path = "/redirect_forever/302", + .msg = "Exceeded max redirects", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // one unending redirect, one not testFetchList( good, - {{"/validators2", "", ssl}, - {"/redirect_forever/302", "Exceeded max redirects", ssl, true, true}}); + {{.path = "/validators2", .msg = "", .ssl = ssl}, + {.path = "/redirect_forever/302", + .msg = "Exceeded max redirects", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // invalid redir Location testFetchList( good, - {{"/redirect_to/ftp://invalid-url/302", - "Invalid redirect location", - ssl, - true, - true}}); + {{.path = "/redirect_to/ftp://invalid-url/302", + .msg = "Invalid redirect location", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); testFetchList( good, - {{"/redirect_to/file://invalid-url/302", - "Invalid redirect location", - ssl, - true, - true}}); + {{.path = "/redirect_to/file://invalid-url/302", + .msg = "Invalid redirect location", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // invalid json testFetchList( - good, {{"/validators/bad", "Unable to parse JSON response", ssl, true, true}}); + good, + {{.path = "/validators/bad", + .msg = "Unable to parse JSON response", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); testFetchList( - good, {{"/validators2/bad", "Unable to parse JSON response", ssl, true, true}}); + good, + {{.path = "/validators2/bad", + .msg = "Unable to parse JSON response", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // error status returned - testFetchList(good, {{"/bad-resource", "returned bad status", ssl, true, true}}); + testFetchList( + good, + {{.path = "/bad-resource", + .msg = "returned bad status", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // location field missing testFetchList( good, - {{"/redirect_nolo/308", "returned a redirect with no Location", ssl, true, true}}); + {{.path = "/redirect_nolo/308", + .msg = "returned a redirect with no Location", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // json fields missing testFetchList( good, - {{"/validators/missing", "Missing fields in JSON response", ssl, true, true}}); + {{.path = "/validators/missing", + .msg = "Missing fields in JSON response", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); testFetchList( good, - {{"/validators2/missing", "Missing fields in JSON response", ssl, true, true}}); + {{.path = "/validators2/missing", + .msg = "Missing fields in JSON response", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // timeout - testFetchList(good, {{"/sleep/13", "took too long", ssl, true, true}}); + testFetchList( + good, + {{.path = "/sleep/13", + .msg = "took too long", + .ssl = ssl, + .failFetch = true, + .failApply = true}}); // bad manifest format using known versions // * Retrieves a v1 formatted list claiming version 2 - testFetchList(good, {{"/validators", "Missing fields", ssl, true, true, 2}}); + testFetchList( + good, + {{.path = "/validators", + .msg = "Missing fields", + .ssl = ssl, + .failFetch = true, + .failApply = true, + .serverVersion = 2}}); // * Retrieves a v2 formatted list claiming version 1 - testFetchList(good, {{"/validators2", "Missing fields", ssl, true, true, 0}}); + testFetchList( + good, + {{.path = "/validators2", + .msg = "Missing fields", + .ssl = ssl, + .failFetch = true, + .failApply = true, + .serverVersion = 0}}); // bad manifest version // Because versions other than 1 are treated as v2, the v1 // list won't have the blobs_v2 fields, and thus will claim to have // missing fields - testFetchList(good, {{"/validators", "Missing fields", ssl, true, true, 4}}); - testFetchList(good, {{"/validators2", "1 unsupported version", ssl, false, true, 4}}); + testFetchList( + good, + {{.path = "/validators", + .msg = "Missing fields", + .ssl = ssl, + .failFetch = true, + .failApply = true, + .serverVersion = 4}}); + testFetchList( + good, + {{.path = "/validators2", + .msg = "1 unsupported version", + .ssl = ssl, + .failFetch = false, + .failApply = true, + .serverVersion = 4}}); using namespace std::chrono_literals; // get expired validator list testFetchList( good, - {{"/validators", "Applied 1 expired validator list(s)", ssl, false, false, 1, 0s}}); + {{.path = "/validators", + .msg = "Applied 1 expired validator list(s)", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = 0s}}); testFetchList( good, - {{"/validators2", - "Applied 1 expired validator list(s)", - ssl, - false, - false, - 1, - 0s, - -1s}}); + {{.path = "/validators2", + .msg = "Applied 1 expired validator list(s)", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = 0s, + .effectiveOverlap = -1s}}); // force an out-of-range validUntil value testFetchList( good, - {{"/validators", - "1 invalid validator list(s)", - ssl, - false, - true, - 1, - std::chrono::seconds{json::Value::kMinInt}}}); + {{.path = "/validators", + .msg = "1 invalid validator list(s)", + .ssl = ssl, + .failFetch = false, + .failApply = true, + .serverVersion = 1, + .expiresFromNow = std::chrono::seconds{json::Value::kMinInt}}}); // force an out-of-range validUntil value on the future list // The first list is accepted. The second fails. The parser // returns the "best" result, so this looks like a success. testFetchList( good, - {{"/validators2", - "", - ssl, - false, - false, - 1, - std::chrono::seconds{json::Value::kMaxInt - 300}, - 299s}}); + {{.path = "/validators2", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = std::chrono::seconds{json::Value::kMaxInt - 300}, + .effectiveOverlap = 299s}}); // force an out-of-range validFrom value // The first list is accepted. The second fails. The parser // returns the "best" result, so this looks like a success. testFetchList( good, - {{"/validators2", - "", - ssl, - false, - false, - 1, - std::chrono::seconds{json::Value::kMaxInt - 300}, - 301s}}); + {{.path = "/validators2", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = std::chrono::seconds{json::Value::kMaxInt - 300}, + .effectiveOverlap = 301s}}); // force an out-of-range validUntil value on _both_ lists testFetchList( good, - {{"/validators2", - "2 invalid validator list(s)", - ssl, - false, - true, - 1, - std::chrono::seconds{json::Value::kMinInt}, - std::chrono::seconds{json::Value::kMaxInt - 6000}}}); + {{.path = "/validators2", + .msg = "2 invalid validator list(s)", + .ssl = ssl, + .failFetch = false, + .failApply = true, + .serverVersion = 1, + .expiresFromNow = std::chrono::seconds{json::Value::kMinInt}, + .effectiveOverlap = std::chrono::seconds{json::Value::kMaxInt - 6000}}}); // verify refresh intervals are properly clamped testFetchList( good, - {{"/validators/refresh/0", - "", - ssl, - false, - false, - 1, - detail::kDefaultExpires, - detail::kDefaultEffectiveOverlap, - 1}}); // minimum of 1 minute + {{.path = "/validators/refresh/0", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = detail::kDefaultExpires, + .effectiveOverlap = detail::kDefaultEffectiveOverlap, + .expectedRefreshMin = 1}}); // minimum of 1 minute testFetchList( good, - {{"/validators2/refresh/0", - "", - ssl, - false, - false, - 1, - detail::kDefaultExpires, - detail::kDefaultEffectiveOverlap, - 1}}); // minimum of 1 minute + {{.path = "/validators2/refresh/0", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = detail::kDefaultExpires, + .effectiveOverlap = detail::kDefaultEffectiveOverlap, + .expectedRefreshMin = 1}}); // minimum of 1 minute testFetchList( good, - {{"/validators/refresh/10", - "", - ssl, - false, - false, - 1, - detail::kDefaultExpires, - detail::kDefaultEffectiveOverlap, - 10}}); // 10 minutes is fine + {{.path = "/validators/refresh/10", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = detail::kDefaultExpires, + .effectiveOverlap = detail::kDefaultEffectiveOverlap, + .expectedRefreshMin = 10}}); // 10 minutes is fine testFetchList( good, - {{"/validators2/refresh/10", - "", - ssl, - false, - false, - 1, - detail::kDefaultExpires, - detail::kDefaultEffectiveOverlap, - 10}}); // 10 minutes is fine + {{.path = "/validators2/refresh/10", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = detail::kDefaultExpires, + .effectiveOverlap = detail::kDefaultEffectiveOverlap, + .expectedRefreshMin = 10}}); // 10 minutes is fine testFetchList( good, - {{"/validators/refresh/2000", - "", - ssl, - false, - false, - 1, - detail::kDefaultExpires, - detail::kDefaultEffectiveOverlap, - 60 * 24}}); // max of 24 hours + {{.path = "/validators/refresh/2000", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = detail::kDefaultExpires, + .effectiveOverlap = detail::kDefaultEffectiveOverlap, + .expectedRefreshMin = 60 * 24}}); // max of 24 hours testFetchList( good, - {{"/validators2/refresh/2000", - "", - ssl, - false, - false, - 1, - detail::kDefaultExpires, - detail::kDefaultEffectiveOverlap, - 60 * 24}}); // max of 24 hours + {{.path = "/validators2/refresh/2000", + .msg = "", + .ssl = ssl, + .failFetch = false, + .failApply = false, + .serverVersion = 1, + .expiresFromNow = detail::kDefaultExpires, + .effectiveOverlap = detail::kDefaultEffectiveOverlap, + .expectedRefreshMin = 60 * 24}}); // max of 24 hours } using namespace boost::filesystem; for (auto const& file : directory_iterator(good.subdir())) diff --git a/src/test/basics/PerfLog_test.cpp b/src/test/basics/PerfLog_test.cpp index c370c241c5..41b5f81f5d 100644 --- a/src/test/basics/PerfLog_test.cpp +++ b/src/test/basics/PerfLog_test.cpp @@ -619,7 +619,7 @@ public: // Total queued duration is triangle number of (i + 1). BEAST_EXPECT( - jsonToUInt64(total[jss::queued_duration_us]) == (((i * i) + 3 * i + 2) / 2)); + jsonToUInt64(total[jss::queued_duration_us]) == (((i * i) + (3 * i) + 2) / 2)); BEAST_EXPECT(total[jss::running_duration_us] == "0"); } diff --git a/src/test/beast/aged_associative_container_test.cpp b/src/test/beast/aged_associative_container_test.cpp index f2ce72b584..d7f74aaa7d 100644 --- a/src/test/beast/aged_associative_container_test.cpp +++ b/src/test/beast/aged_associative_container_test.cpp @@ -414,11 +414,11 @@ public: // unordered template - std::enable_if_t::type::is_unordered::value> + std::enable_if_t::is_unordered::value> checkUnorderedContentsRefRef(C&& c, Values const& v); template - std::enable_if_t::type::is_unordered::value> + std::enable_if_t::is_unordered::value> checkUnorderedContentsRefRef(C&&, Values const&) { } @@ -641,7 +641,7 @@ AgedAssociativeContainerTestBase::checkMapContents(Container& c, Values const& v // unordered template -std::enable_if_t::type::is_unordered::value> +std::enable_if_t::is_unordered::value> AgedAssociativeContainerTestBase::checkUnorderedContentsRefRef(C&& c, Values const& v) { using Cont = std::remove_reference_t; diff --git a/src/test/core/Config_test.cpp b/src/test/core/Config_test.cpp index ce6774827e..92f59fe644 100644 --- a/src/test/core/Config_test.cpp +++ b/src/test/core/Config_test.cpp @@ -1457,14 +1457,14 @@ r.ripple.com:51235 }; std::vector const units = { - {"seconds", 1, 15 * 60, false}, - {"minutes", 60, 14, false}, - {"minutes", 60, 15, true}, - {"hours", 3600, 10, true}, - {"days", 86400, 10, true}, - {"weeks", 604800, 2, true}, - {"months", 2592000, 1, false}, - {"years", 31536000, 1, false}}; + {.unit = "seconds", .numSeconds = 1, .configVal = 15 * 60, .shouldPass = false}, + {.unit = "minutes", .numSeconds = 60, .configVal = 14, .shouldPass = false}, + {.unit = "minutes", .numSeconds = 60, .configVal = 15, .shouldPass = true}, + {.unit = "hours", .numSeconds = 3600, .configVal = 10, .shouldPass = true}, + {.unit = "days", .numSeconds = 86400, .configVal = 10, .shouldPass = true}, + {.unit = "weeks", .numSeconds = 604800, .configVal = 2, .shouldPass = true}, + {.unit = "months", .numSeconds = 2592000, .configVal = 1, .shouldPass = false}, + {.unit = "years", .numSeconds = 31536000, .configVal = 1, .shouldPass = false}}; std::string space; for (auto& [unit, sec, val, shouldPass] : units) diff --git a/src/test/jtx/impl/WSClient.cpp b/src/test/jtx/impl/WSClient.cpp index 551fd1404b..6d069523d2 100644 --- a/src/test/jtx/impl/WSClient.cpp +++ b/src/test/jtx/impl/WSClient.cpp @@ -70,7 +70,7 @@ class WSClientImpl : public WSClient continue; ParsedPort pp; parsePort(pp, cfg[name], log); - if (pp.protocol.count(ps) == 0) + if (!pp.protocol.contains(ps)) continue; using namespace boost::asio::ip; if (pp.ip && pp.ip->is_unspecified()) diff --git a/src/test/jtx/impl/permissioned_dex.cpp b/src/test/jtx/impl/permissioned_dex.cpp index 5c059e9e80..a6b24d7ac6 100644 --- a/src/test/jtx/impl/permissioned_dex.cpp +++ b/src/test/jtx/impl/permissioned_dex.cpp @@ -26,7 +26,7 @@ setupDomain( env.fund(XRP(100000), domainOwner); env.close(); - pdomain::Credentials const credentials{{domainOwner, credType}}; + pdomain::Credentials const credentials{{.issuer = domainOwner, .credType = credType}}; env(pdomain::setTx(domainOwner, credentials)); auto const objects = pdomain::getObjects(domainOwner, env); diff --git a/src/test/jtx/impl/permissioned_domains.cpp b/src/test/jtx/impl/permissioned_domains.cpp index 690451c7d8..385008be43 100644 --- a/src/test/jtx/impl/permissioned_domains.cpp +++ b/src/test/jtx/impl/permissioned_domains.cpp @@ -130,7 +130,9 @@ credentialsFromJson( auto const& credentialType = obj["CredentialType"]; // NOLINTNEXTLINE(bugprone-unchecked-optional-access): used only in tests auto blob = strUnHex(credentialType.asString()).value(); - ret.push_back({human2Acc.at(issuer.asString()), std::string(blob.begin(), blob.end())}); + ret.push_back( + {.issuer = human2Acc.at(issuer.asString()), + .credType = std::string(blob.begin(), blob.end())}); } return ret; } diff --git a/src/test/nodestore/import_test.cpp b/src/test/nodestore/import_test.cpp index a80b5ccc93..de99edd655 100644 --- a/src/test/nodestore/import_test.cpp +++ b/src/test/nodestore/import_test.cpp @@ -297,17 +297,17 @@ public: auto const args = parseArgs(arg()); bool usage = args.empty(); - if (!usage && args.find("from") == args.end()) + if (!usage && !args.contains("from")) { log << "Missing parameter: from"; usage = true; } - if (!usage && args.find("to") == args.end()) + if (!usage && !args.contains("to")) { log << "Missing parameter: to"; usage = true; } - if (!usage && args.find("buffer") == args.end()) + if (!usage && !args.contains("buffer")) { log << "Missing parameter: buffer"; usage = true; diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 4307b7ab7f..31b20b37d4 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -692,11 +692,11 @@ public: { std::string const credentialType1 = "credential1"; - Account issuer("issuer"); + Account const issuer("issuer"); env.fund(XRP(5000), issuer); // gw creates an PermissionedDomain. - env(pdomain::setTx(gw, {{issuer, credentialType1}})); + env(pdomain::setTx(gw, {{.issuer = issuer, .credType = credentialType1}})); env.close(); // Find the PermissionedDomain. diff --git a/src/test/rpc/DepositAuthorized_test.cpp b/src/test/rpc/DepositAuthorized_test.cpp index 89053557a7..e6720602c9 100644 --- a/src/test/rpc/DepositAuthorized_test.cpp +++ b/src/test/rpc/DepositAuthorized_test.cpp @@ -324,7 +324,7 @@ public: env.close(); // becky authorize any account recognized by carol to make a payment - env(deposit::authCredentials(becky, {{carol, credType}})); + env(deposit::authCredentials(becky, {{.issuer = carol, .credType = credType}})); env.close(); { @@ -507,7 +507,7 @@ public: env.close(); // becky authorize any account recognized by carol to make a payment - env(deposit::authCredentials(becky, {{carol, credType2}})); + env(deposit::authCredentials(becky, {{.issuer = carol, .credType = credType2}})); env.close(); { diff --git a/src/test/rpc/LedgerEntry_test.cpp b/src/test/rpc/LedgerEntry_test.cpp index d231a2d4a0..dd9eb1c119 100644 --- a/src/test/rpc/LedgerEntry_test.cpp +++ b/src/test/rpc/LedgerEntry_test.cpp @@ -784,8 +784,8 @@ class LedgerEntry_test : public beast::unit_test::Suite env, jss::amm, { - {jss::asset, "malformedRequest"}, - {jss::asset2, "malformedRequest"}, + {.fieldName = jss::asset, .malformedErrorMsg = "malformedRequest"}, + {.fieldName = jss::asset2, .malformedErrorMsg = "malformedRequest"}, }); }; auto getIOU = [&](Env& env) -> PrettyAsset { return alice["USD"]; }; @@ -900,9 +900,9 @@ class LedgerEntry_test : public beast::unit_test::Suite env, jss::credential, { - {jss::subject, "malformedRequest"}, - {jss::issuer, "malformedRequest"}, - {jss::credential_type, "malformedRequest"}, + {.fieldName = jss::subject, .malformedErrorMsg = "malformedRequest"}, + {.fieldName = jss::issuer, .malformedErrorMsg = "malformedRequest"}, + {.fieldName = jss::credential_type, .malformedErrorMsg = "malformedRequest"}, }); } } @@ -954,8 +954,8 @@ class LedgerEntry_test : public beast::unit_test::Suite env, jss::delegate, { - {jss::account, "malformedAddress"}, - {jss::authorize, "malformedAddress"}, + {.fieldName = jss::account, .malformedErrorMsg = "malformedAddress"}, + {.fieldName = jss::authorize, .malformedErrorMsg = "malformedAddress"}, }); } } @@ -1011,8 +1011,10 @@ class LedgerEntry_test : public beast::unit_test::Suite env, jss::deposit_preauth, { - {jss::owner, "malformedOwner"}, - {jss::authorized, "malformedAuthorized", false}, + {.fieldName = jss::owner, .malformedErrorMsg = "malformedOwner"}, + {.fieldName = jss::authorized, + .malformedErrorMsg = "malformedAuthorized", + .required = false}, }); } } @@ -1037,7 +1039,7 @@ class LedgerEntry_test : public beast::unit_test::Suite // Setup Bob with DepositAuth env(fset(bob, asfDepositAuth)); env.close(); - env(deposit::authCredentials(bob, {{issuer, credType}})); + env(deposit::authCredentials(bob, {{.issuer = issuer, .credType = credType}})); env.close(); } @@ -1458,7 +1460,10 @@ class LedgerEntry_test : public beast::unit_test::Suite { // Malformed escrow fields runLedgerEntryTest( - env, jss::escrow, {{jss::owner, "malformedOwner"}, {jss::seq, "malformedSeq"}}); + env, + jss::escrow, + {{.fieldName = jss::owner, .malformedErrorMsg = "malformedOwner"}, + {.fieldName = jss::seq, .malformedErrorMsg = "malformedSeq"}}); } } @@ -1667,7 +1672,8 @@ class LedgerEntry_test : public beast::unit_test::Suite runLedgerEntryTest( env, jss::offer, - {{jss::account, "malformedAddress"}, {jss::seq, "malformedRequest"}}); + {{.fieldName = jss::account, .malformedErrorMsg = "malformedAddress"}, + {.fieldName = jss::seq, .malformedErrorMsg = "malformedRequest"}}); } } @@ -1774,8 +1780,8 @@ class LedgerEntry_test : public beast::unit_test::Suite env, fieldName, { - {jss::accounts, "malformedRequest"}, - {jss::currency, "malformedCurrency"}, + {.fieldName = jss::accounts, .malformedErrorMsg = "malformedRequest"}, + {.fieldName = jss::currency, .malformedErrorMsg = "malformedCurrency"}, }); } { @@ -1955,8 +1961,8 @@ class LedgerEntry_test : public beast::unit_test::Suite env, jss::ticket, { - {jss::account, "malformedAddress"}, - {jss::ticket_seq, "malformedRequest"}, + {.fieldName = jss::account, .malformedErrorMsg = "malformedAddress"}, + {.fieldName = jss::ticket_seq, .malformedErrorMsg = "malformedRequest"}, }); } } @@ -2034,8 +2040,9 @@ class LedgerEntry_test : public beast::unit_test::Suite env, jss::oracle, { - {jss::account, "malformedAccount"}, - {jss::oracle_document_id, "malformedDocumentID"}, + {.fieldName = jss::account, .malformedErrorMsg = "malformedAccount"}, + {.fieldName = jss::oracle_document_id, + .malformedErrorMsg = "malformedDocumentID"}, }); } } @@ -2172,7 +2179,7 @@ class LedgerEntry_test : public beast::unit_test::Suite env.close(); auto const seq = env.seq(alice); - env(pdomain::setTx(alice, {{alice, "first credential"}})); + env(pdomain::setTx(alice, {{.issuer = alice, .credType = "first credential"}})); env.close(); auto const objects = pdomain::getObjects(alice, env); if (!BEAST_EXPECT(objects.size() == 1)) @@ -2221,8 +2228,8 @@ class LedgerEntry_test : public beast::unit_test::Suite env, jss::permissioned_domain, { - {jss::account, "malformedAddress"}, - {jss::seq, "malformedRequest"}, + {.fieldName = jss::account, .malformedErrorMsg = "malformedAddress"}, + {.fieldName = jss::seq, .malformedErrorMsg = "malformedRequest"}, }); } } diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index ee07698519..2dae6fccb9 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -1,51 +1,56 @@ -include(XrplAddTest) +include(GoogleTest) +include(isolate_headers) # Test requirements. find_package(GTest REQUIRED) -# Custom target for all tests defined in this file -add_custom_target(xrpl.tests) - -# Test helpers -add_library(xrpl.helpers.test STATIC) -target_sources( - xrpl.helpers.test - PRIVATE helpers/Account.cpp helpers/TestSink.cpp helpers/TxTest.cpp +# Single combined gtest binary built from the shared test helpers and all test +# modules below. +add_executable( + xrpl_tests + main.cpp + helpers/Account.cpp + helpers/TestSink.cpp + helpers/TxTest.cpp ) -target_include_directories(xrpl.helpers.test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(xrpl.helpers.test PUBLIC xrpl.libxrpl gtest::gtest) - -# Common library dependencies for the rest of the tests. -add_library(xrpl.imports.test INTERFACE) -target_link_libraries( - xrpl.imports.test - INTERFACE gtest::gtest xrpl.libxrpl xrpl.helpers.test +set_target_properties( + xrpl_tests + PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) +# Lets test sources include the shared helpers as . +target_include_directories(xrpl_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(xrpl_tests PRIVATE GTest::gtest xrpl.libxrpl) -# One test for each module. -xrpl_add_test(basics) -target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test) -add_dependencies(xrpl.tests xrpl.test.basics) - -xrpl_add_test(crypto) -target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test) -add_dependencies(xrpl.tests xrpl.test.crypto) - -xrpl_add_test(json) -target_link_libraries(xrpl.test.json PRIVATE xrpl.imports.test) -add_dependencies(xrpl.tests xrpl.test.json) - -xrpl_add_test(tx) -target_link_libraries(xrpl.test.tx PRIVATE xrpl.imports.test) -add_dependencies(xrpl.tests xrpl.test.tx) - -xrpl_add_test(protocol_autogen) -target_link_libraries(xrpl.test.protocol_autogen PRIVATE xrpl.imports.test) -add_dependencies(xrpl.tests xrpl.test.protocol_autogen) - -# Network unit tests are currently not supported on Windows +# One source subdirectory per module. Network unit tests are currently not +# supported on Windows. +set(test_modules + basics + crypto + json + tx + protocol_autogen +) if(NOT WIN32) - xrpl_add_test(net) - target_link_libraries(xrpl.test.net PRIVATE xrpl.imports.test) - add_dependencies(xrpl.tests xrpl.test.net) + list(APPEND test_modules net) endif() + +foreach(module IN LISTS test_modules) + # Append the module's sources (${module}/*.cpp and ${module}.cpp, if any). + file( + GLOB_RECURSE sources + CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/${module}/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/${module}.cpp" + ) + target_sources(xrpl_tests PRIVATE ${sources}) + + # Expose the module's private headers under their canonical include path. + isolate_headers( + xrpl_tests + "${CMAKE_SOURCE_DIR}" + "${CMAKE_SOURCE_DIR}/tests/${module}" + PRIVATE + ) +endforeach() + +gtest_discover_tests(xrpl_tests DISCOVERY_TIMEOUT 60) diff --git a/src/tests/libxrpl/crypto/main.cpp b/src/tests/libxrpl/crypto/main.cpp deleted file mode 100644 index 5142bbe08a..0000000000 --- a/src/tests/libxrpl/crypto/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int -main(int argc, char** argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/tests/libxrpl/json/main.cpp b/src/tests/libxrpl/json/main.cpp deleted file mode 100644 index 5142bbe08a..0000000000 --- a/src/tests/libxrpl/json/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int -main(int argc, char** argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/tests/libxrpl/basics/main.cpp b/src/tests/libxrpl/main.cpp similarity index 100% rename from src/tests/libxrpl/basics/main.cpp rename to src/tests/libxrpl/main.cpp diff --git a/src/tests/libxrpl/net/main.cpp b/src/tests/libxrpl/net/main.cpp deleted file mode 100644 index 5142bbe08a..0000000000 --- a/src/tests/libxrpl/net/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int -main(int argc, char** argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/tests/libxrpl/tx/main.cpp b/src/tests/libxrpl/tx/main.cpp deleted file mode 100644 index 5142bbe08a..0000000000 --- a/src/tests/libxrpl/tx/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include - -int -main(int argc, char** argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/xrpld/app/ledger/InboundLedger.h b/src/xrpld/app/ledger/InboundLedger.h index d155c5902c..b82e2f69cd 100644 --- a/src/xrpld/app/ledger/InboundLedger.h +++ b/src/xrpld/app/ledger/InboundLedger.h @@ -128,13 +128,13 @@ private: pmDowncast() override; int - processData(std::shared_ptr peer, protocol::TMLedgerData& data); + processData(std::shared_ptr peer, protocol::TMLedgerData const& data); bool takeHeader(std::string const& data); void - receiveNode(protocol::TMLedgerData& packet, SHAMapAddNode&); + receiveNode(protocol::TMLedgerData const& packet, SHAMapAddNode&); bool takeTxRootNode(Slice const& data, SHAMapAddNode&); @@ -143,10 +143,10 @@ private: takeAsRootNode(Slice const& data, SHAMapAddNode&); std::vector - neededTxHashes(int max, SHAMapSyncFilter* filter) const; + neededTxHashes(int max, SHAMapSyncFilter const* filter) const; std::vector - neededStateHashes(int max, SHAMapSyncFilter* filter) const; + neededStateHashes(int max, SHAMapSyncFilter const* filter) const; clock_type& clock_; clock_type::time_point lastAction_; diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index 9ba7bdf22e..5a9f24cc2e 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -188,7 +188,7 @@ InboundLedger::~InboundLedger() } static std::vector -neededHashes(uint256 const& root, SHAMap& map, int max, SHAMapSyncFilter* filter) +neededHashes(uint256 const& root, SHAMap& map, int max, SHAMapSyncFilter const* filter) { std::vector ret; @@ -211,13 +211,13 @@ neededHashes(uint256 const& root, SHAMap& map, int max, SHAMapSyncFilter* filter } std::vector -InboundLedger::neededTxHashes(int max, SHAMapSyncFilter* filter) const +InboundLedger::neededTxHashes(int max, SHAMapSyncFilter const* filter) const { return neededHashes(ledger_->header().txHash, ledger_->txMap(), max, filter); } std::vector -InboundLedger::neededStateHashes(int max, SHAMapSyncFilter* filter) const +InboundLedger::neededStateHashes(int max, SHAMapSyncFilter const* filter) const { return neededHashes(ledger_->header().accountHash, ledger_->stateMap(), max, filter); } @@ -820,7 +820,7 @@ InboundLedger::takeHeader(std::string const& data) Call with a lock */ void -InboundLedger::receiveNode(protocol::TMLedgerData& packet, SHAMapAddNode& san) +InboundLedger::receiveNode(protocol::TMLedgerData const& packet, SHAMapAddNode& san) { if (!haveHeader_) { @@ -1026,7 +1026,7 @@ InboundLedger::gotData( // TODO Change peer to Consumer // int -InboundLedger::processData(std::shared_ptr peer, protocol::TMLedgerData& packet) +InboundLedger::processData(std::shared_ptr peer, protocol::TMLedgerData const& packet) { if (packet.type() == protocol::liBASE) { diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index 508dfc8590..af5d51289d 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -492,7 +492,7 @@ public: void run() override; void - signalStop(std::string msg) override; + signalStop(std::string const& msg) override; bool checkSigs() const override; void @@ -1602,7 +1602,7 @@ ApplicationImp::run() } void -ApplicationImp::signalStop(std::string msg) +ApplicationImp::signalStop(std::string const& msg) { if (!isTimeToStop.test_and_set(std::memory_order_acquire)) { diff --git a/src/xrpld/app/main/Application.h b/src/xrpld/app/main/Application.h index 200fed7cf9..08e41e2c4c 100644 --- a/src/xrpld/app/main/Application.h +++ b/src/xrpld/app/main/Application.h @@ -111,7 +111,7 @@ public: virtual void run() = 0; virtual void - signalStop(std::string msg) = 0; + signalStop(std::string const& msg) = 0; [[nodiscard]] virtual bool checkSigs() const = 0; virtual void diff --git a/src/xrpld/app/misc/detail/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp index 57b65814e1..0981c32050 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -455,7 +455,7 @@ ValidatorList::parseBlobs(std::uint32_t version, json::Value const& body) std::vector ValidatorList::parseBlobs(protocol::TMValidatorList const& body) { - return {{body.blob(), body.signature(), {}}}; + return {{.blob = body.blob(), .signature = body.signature(), .manifest = {}}}; } // static diff --git a/src/xrpld/consensus/Validations.h b/src/xrpld/consensus/Validations.h index 7be578060e..2f5762ce83 100644 --- a/src/xrpld/consensus/Validations.h +++ b/src/xrpld/consensus/Validations.h @@ -693,7 +693,7 @@ public: validationSET_EXPIRES ago and were not asked to keep. */ void - expire(beast::Journal& j) + expire(beast::Journal const& j) { auto const start = std::chrono::steady_clock::now(); { diff --git a/src/xrpld/overlay/Overlay.h b/src/xrpld/overlay/Overlay.h index ef97ea7f24..87c6ff132a 100644 --- a/src/xrpld/overlay/Overlay.h +++ b/src/xrpld/overlay/Overlay.h @@ -117,11 +117,11 @@ public: /** Broadcast a proposal. */ virtual void - broadcast(protocol::TMProposeSet& m) = 0; + broadcast(protocol::TMProposeSet const& m) = 0; /** Broadcast a validation. */ virtual void - broadcast(protocol::TMValidation& m) = 0; + broadcast(protocol::TMValidation const& m) = 0; /** Relay a proposal. * @param m the serialized proposal @@ -130,7 +130,7 @@ public: * @return the set of peers which have already sent us this proposal */ virtual std::set - relay(protocol::TMProposeSet& m, uint256 const& uid, PublicKey const& validator) = 0; + relay(protocol::TMProposeSet const& m, uint256 const& uid, PublicKey const& validator) = 0; /** Relay a validation. * @param m the serialized validation @@ -139,7 +139,7 @@ public: * @return the set of peers which have already sent us this validation */ virtual std::set - relay(protocol::TMValidation& m, uint256 const& uid, PublicKey const& validator) = 0; + relay(protocol::TMValidation const& m, uint256 const& uid, PublicKey const& validator) = 0; /** Relay a transaction. If the tx reduce-relay feature is enabled then * randomly select peers to relay to and queue transaction's hash diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index b31f54058a..b71cef6719 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -407,7 +407,7 @@ OverlayImpl::makeErrorResponse( std::shared_ptr const& slot, http_request_type const& request, address_type remoteAddress, - std::string text) + std::string const& text) { boost::beast::http::response msg; msg.version(request.version()); @@ -1157,14 +1157,14 @@ OverlayImpl::findPeerByPublicKey(PublicKey const& pubKey) } void -OverlayImpl::broadcast(protocol::TMProposeSet& m) +OverlayImpl::broadcast(protocol::TMProposeSet const& m) { auto const sm = std::make_shared(m, protocol::mtPROPOSE_LEDGER); forEach([&](std::shared_ptr const& p) { p->send(sm); }); } std::set -OverlayImpl::relay(protocol::TMProposeSet& m, uint256 const& uid, PublicKey const& validator) +OverlayImpl::relay(protocol::TMProposeSet const& m, uint256 const& uid, PublicKey const& validator) { if (auto const toSkip = app_.getHashRouter().shouldRelay(uid)) { @@ -1179,14 +1179,14 @@ OverlayImpl::relay(protocol::TMProposeSet& m, uint256 const& uid, PublicKey cons } void -OverlayImpl::broadcast(protocol::TMValidation& m) +OverlayImpl::broadcast(protocol::TMValidation const& m) { auto const sm = std::make_shared(m, protocol::mtVALIDATION); forEach([sm](std::shared_ptr const& p) { p->send(sm); }); } std::set -OverlayImpl::relay(protocol::TMValidation& m, uint256 const& uid, PublicKey const& validator) +OverlayImpl::relay(protocol::TMValidation const& m, uint256 const& uid, PublicKey const& validator) { if (auto const toSkip = app_.getHashRouter().shouldRelay(uid)) { diff --git a/src/xrpld/overlay/detail/OverlayImpl.h b/src/xrpld/overlay/detail/OverlayImpl.h index 6fcc2df854..545d9eb75c 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.h +++ b/src/xrpld/overlay/detail/OverlayImpl.h @@ -202,16 +202,16 @@ public: findPeerByPublicKey(PublicKey const& pubKey) override; void - broadcast(protocol::TMProposeSet& m) override; + broadcast(protocol::TMProposeSet const& m) override; void - broadcast(protocol::TMValidation& m) override; + broadcast(protocol::TMValidation const& m) override; std::set - relay(protocol::TMProposeSet& m, uint256 const& uid, PublicKey const& validator) override; + relay(protocol::TMProposeSet const& m, uint256 const& uid, PublicKey const& validator) override; std::set - relay(protocol::TMValidation& m, uint256 const& uid, PublicKey const& validator) override; + relay(protocol::TMValidation const& m, uint256 const& uid, PublicKey const& validator) override; void relay( @@ -433,7 +433,7 @@ private: std::shared_ptr const& slot, http_request_type const& request, address_type remoteAddress, - std::string msg); + std::string const& msg); /** Handles crawl requests. Crawl returns information about the node and its peers so crawlers can map the network. diff --git a/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp b/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp index fcf30fa4f4..5d276dc9c5 100644 --- a/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp +++ b/src/xrpld/peerfinder/detail/PeerfinderConfig.cpp @@ -18,7 +18,8 @@ Config::Config() : outPeers(calcOutPeers()) std::size_t Config::calcOutPeers() const { - return std::max((maxPeers * Tuning::kOutPercent + 50) / 100, std::size_t(Tuning::kMinOutCount)); + return std::max( + ((maxPeers * Tuning::kOutPercent) + 50) / 100, std::size_t(Tuning::kMinOutCount)); } void diff --git a/src/xrpld/rpc/detail/Pathfinder.cpp b/src/xrpld/rpc/detail/Pathfinder.cpp index daa50cfb07..25da86ef8f 100644 --- a/src/xrpld/rpc/detail/Pathfinder.cpp +++ b/src/xrpld/rpc/detail/Pathfinder.cpp @@ -568,7 +568,11 @@ Pathfinder::rankPaths( JLOG(j_.debug()) << "findPaths: quality: " << uQuality << ": " << currentPath.getJson(JsonOptions::Values::None); - rankedPaths.push_back({uQuality, currentPath.size(), liquidity, i}); + rankedPaths.push_back( + {.quality = uQuality, + .length = currentPath.size(), + .liquidity = liquidity, + .index = i}); } } } @@ -1373,7 +1377,7 @@ fillPaths(Pathfinder::PaymentType type, PathCostList const& costs) auto& list = gPathTable[type]; XRPL_ASSERT(list.empty(), "xrpl::fillPaths : empty paths"); for (auto& cost : costs) - list.push_back({cost.cost, makePath(cost.path)}); + list.push_back({.searchLevel = cost.cost, .type = makePath(cost.path)}); } } // namespace @@ -1396,58 +1400,58 @@ Pathfinder::initPathTable() fillPaths( PaymentType::XrpToNonXrp, - {{1, "sfd"}, // source -> book -> gateway - {3, "sfad"}, // source -> book -> account -> destination - {5, "sfaad"}, // source -> book -> account -> account -> destination - {6, "sbfd"}, // source -> book -> book -> destination - {8, "sbafd"}, // source -> book -> account -> book -> destination - {9, "sbfad"}, // source -> book -> book -> account -> destination - {10, "sbafad"}}); + {{.cost = 1, .path = "sfd"}, // source -> book -> gateway + {.cost = 3, .path = "sfad"}, // source -> book -> account -> destination + {.cost = 5, .path = "sfaad"}, // source -> book -> account -> account -> destination + {.cost = 6, .path = "sbfd"}, // source -> book -> book -> destination + {.cost = 8, .path = "sbafd"}, // source -> book -> account -> book -> destination + {.cost = 9, .path = "sbfad"}, // source -> book -> book -> account -> destination + {.cost = 10, .path = "sbafad"}}); fillPaths( PaymentType::NonXrpToXrp, - {{1, "sxd"}, // gateway buys XRP - {2, "saxd"}, // source -> gateway -> book(XRP) -> dest - {6, "saaxd"}, - {7, "sbxd"}, - {8, "sabxd"}, - {9, "sabaxd"}}); + {{.cost = 1, .path = "sxd"}, // gateway buys XRP + {.cost = 2, .path = "saxd"}, // source -> gateway -> book(XRP) -> dest + {.cost = 6, .path = "saaxd"}, + {.cost = 7, .path = "sbxd"}, + {.cost = 8, .path = "sabxd"}, + {.cost = 9, .path = "sabaxd"}}); // non-XRP to non-XRP (same currency) fillPaths( PaymentType::NonXrpToSame, { - {1, "sad"}, // source -> gateway -> destination - {1, "sfd"}, // source -> book -> destination - {4, "safd"}, // source -> gateway -> book -> destination - {4, "sfad"}, - {5, "saad"}, - {5, "sbfd"}, - {6, "sxfad"}, - {6, "safad"}, - {6, "saxfd"}, // source -> gateway -> book to XRP -> book -> - // destination - {6, "saxfad"}, - {6, "sabfd"}, // source -> gateway -> book -> book -> destination - {7, "saaad"}, + {.cost = 1, .path = "sad"}, // source -> gateway -> destination + {.cost = 1, .path = "sfd"}, // source -> book -> destination + {.cost = 4, .path = "safd"}, // source -> gateway -> book -> destination + {.cost = 4, .path = "sfad"}, + {.cost = 5, .path = "saad"}, + {.cost = 5, .path = "sbfd"}, + {.cost = 6, .path = "sxfad"}, + {.cost = 6, .path = "safad"}, + {.cost = 6, .path = "saxfd"}, // source -> gateway -> book to XRP -> book -> + // destination + {.cost = 6, .path = "saxfad"}, + {.cost = 6, .path = "sabfd"}, // source -> gateway -> book -> book -> destination + {.cost = 7, .path = "saaad"}, }); // non-XRP to non-XRP (different currency) fillPaths( PaymentType::NonXrpToNonXrp, { - {1, "sfad"}, - {1, "safd"}, - {3, "safad"}, - {4, "sxfd"}, - {5, "saxfd"}, - {5, "sxfad"}, - {5, "sbfd"}, - {6, "saxfad"}, - {6, "sabfd"}, - {7, "saafd"}, - {8, "saafad"}, - {9, "safaad"}, + {.cost = 1, .path = "sfad"}, + {.cost = 1, .path = "safd"}, + {.cost = 3, .path = "safad"}, + {.cost = 4, .path = "sxfd"}, + {.cost = 5, .path = "saxfd"}, + {.cost = 5, .path = "sxfad"}, + {.cost = 5, .path = "sbfd"}, + {.cost = 6, .path = "saxfad"}, + {.cost = 6, .path = "sabfd"}, + {.cost = 7, .path = "saafd"}, + {.cost = 8, .path = "saafad"}, + {.cost = 9, .path = "safaad"}, }); /* cspell: enable */ } diff --git a/src/xrpld/rpc/detail/ServerHandler.cpp b/src/xrpld/rpc/detail/ServerHandler.cpp index 0bdece3ec3..c73e474e18 100644 --- a/src/xrpld/rpc/detail/ServerHandler.cpp +++ b/src/xrpld/rpc/detail/ServerHandler.cpp @@ -165,10 +165,10 @@ ServerHandler::setup(Setup const& setup, beast::Journal journal) port.port = endpointPort; if ((setup_.client.port == 0u) && - (port.protocol.count("http") > 0 || port.protocol.count("https") > 0)) + (port.protocol.contains("http") || port.protocol.contains("https"))) setup_.client.port = endpointPort; - if ((setup_.overlay.port() == 0u) && (port.protocol.count("peer") > 0)) + if ((setup_.overlay.port() == 0u) && (port.protocol.contains("peer"))) setup_.overlay.port(endpointPort); } } @@ -217,7 +217,7 @@ ServerHandler::onHandoff( using namespace boost::beast; auto const& p{session.port().protocol}; bool const isWs{ - p.count("ws") > 0 || p.count("ws2") > 0 || p.count("wss") > 0 || p.count("wss2") > 0}; + p.contains("ws") || p.contains("ws2") || p.contains("wss") || p.contains("wss2")}; if (websocket::is_upgrade(request)) { @@ -251,7 +251,7 @@ ServerHandler::onHandoff( return handoff; } - if (bundle && p.count("peer") > 0) + if (bundle && p.contains("peer")) return app_.getOverlay().onHandoff(std::move(bundle), std::move(request), remoteAddress); if (isWs && isStatusRequest(request)) @@ -301,7 +301,7 @@ void ServerHandler::onRequest(Session& session) { // Make sure RPC is enabled on the port - if (session.port().protocol.count("http") == 0 && session.port().protocol.count("https") == 0) + if (!session.port().protocol.contains("http") && !session.port().protocol.contains("https")) { httpReply(403, "Forbidden", makeOutput(session), app_.getJournal("RPC")); session.close(true); @@ -1180,7 +1180,7 @@ parsePorts(Config const& config, std::ostream& log) else { auto const count = std::count_if(result.cbegin(), result.cend(), [](Port const& p) { - return p.protocol.count("peer") != 0; + return p.protocol.contains("peer"); }); if (count > 1) @@ -1203,12 +1203,12 @@ setupClient(ServerHandler::Setup& setup) decltype(setup.ports)::const_iterator iter; for (iter = setup.ports.cbegin(); iter != setup.ports.cend(); ++iter) { - if (iter->protocol.count("http") > 0 || iter->protocol.count("https") > 0) + if (iter->protocol.contains("http") || iter->protocol.contains("https")) break; } if (iter == setup.ports.cend()) return; - setup.client.secure = iter->protocol.count("https") > 0; + setup.client.secure = iter->protocol.contains("https"); if (beast::IP::isUnspecified(iter->ip)) { // VFALCO HACK! to make localhost work @@ -1230,7 +1230,7 @@ static void setupOverlay(ServerHandler::Setup& setup) { auto const iter = std::ranges::find_if( - setup.ports, [](Port const& port) { return port.protocol.count("peer") != 0; }); + setup.ports, [](Port const& port) { return port.protocol.contains("peer"); }); if (iter == setup.ports.cend()) { setup.overlay = {};