diff --git a/.github/workflows/instrumentation.yml b/.github/workflows/instrumentation.yml new file mode 100644 index 00000000000..6a1aef64350 --- /dev/null +++ b/.github/workflows/instrumentation.yml @@ -0,0 +1,103 @@ +name: instrumentation +on: + pull_request: + push: + # If the branches list is ever changed, be sure to change it on all + # build/test jobs (nix, macos, windows, instrumentation) + branches: + # Always build the package branches + - develop + - release + - master + # Branches that opt-in to running + - 'ci/**' +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + + # NOTE we are not using dependencies built inside nix because nix is lagging + # with compiler versions. Instrumentation requires clang version 16 or later + + instrumentation-build: + env: + CLANG_RELEASE: 16 + strategy: + fail-fast: false + runs-on: [self-hosted, heavy] + container: debian:bookworm + steps: + - name: install prerequisites + env: + DEBIAN_FRONTEND: noninteractive + run: | + apt-get update + apt-get install --yes --no-install-recommends \ + clang-${CLANG_RELEASE} clang++-${CLANG_RELEASE} \ + python3-pip python-is-python3 make cmake git wget + apt-get clean + update-alternatives --install \ + /usr/bin/clang clang /usr/bin/clang-${CLANG_RELEASE} 100 \ + --slave /usr/bin/clang++ clang++ /usr/bin/clang++-${CLANG_RELEASE} + update-alternatives --auto clang + pip install --no-cache --break-system-packages "conan<2" + + - name: checkout + uses: actions/checkout@v4 + + - name: prepare environment + run: | + mkdir ${GITHUB_WORKSPACE}/.build + echo "SOURCE_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV + echo "BUILD_DIR=$GITHUB_WORKSPACE/.build" >> $GITHUB_ENV + echo "CC=/usr/bin/clang" >> $GITHUB_ENV + echo "CXX=/usr/bin/clang++" >> $GITHUB_ENV + + - name: configure Conan + run: | + conan profile new --detect default + conan profile update settings.compiler=clang default + conan profile update settings.compiler.version=${CLANG_RELEASE} default + conan profile update settings.compiler.libcxx=libstdc++11 default + conan profile update settings.compiler.cppstd=20 default + conan profile update options.rocksdb=False default + conan profile update \ + 'conf.tools.build:compiler_executables={"c": "/usr/bin/clang", "cpp": "/usr/bin/clang++"}' default + conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default + conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default + conan export external/snappy snappy/1.1.10@ + conan export external/soci soci/4.0.3@ + + - name: build dependencies + run: | + cd ${BUILD_DIR} + conan install ${SOURCE_DIR} \ + --output-folder ${BUILD_DIR} \ + --install-folder ${BUILD_DIR} \ + --build missing \ + --settings build_type=Debug + + - name: build with instrumentation + run: | + cd ${BUILD_DIR} + cmake -S ${SOURCE_DIR} -B ${BUILD_DIR} \ + -Dvoidstar=ON \ + -Dtests=ON \ + -Dxrpld=ON \ + -DCMAKE_BUILD_TYPE=Debug \ + -DSECP256K1_BUILD_BENCHMARK=OFF \ + -DSECP256K1_BUILD_TESTS=OFF \ + -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ + -DCMAKE_TOOLCHAIN_FILE=${BUILD_DIR}/build/generators/conan_toolchain.cmake + cmake --build . --parallel $(nproc) + + - name: verify instrumentation enabled + run: | + cd ${BUILD_DIR} + ./rippled --version | grep libvoidstar + + - name: run unit tests + run: | + cd ${BUILD_DIR} + ./rippled -u --unittest-jobs $(( $(nproc)/4 )) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ab4be74fbf4..c66e0e05f7a 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -3,7 +3,7 @@ on: pull_request: push: # If the branches list is ever changed, be sure to change it on all - # build/test jobs (nix, macos, windows) + # build/test jobs (nix, macos, windows, instrumentation) branches: # Always build the package branches - develop diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 6b8261c5d69..9f2cbac951f 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -3,7 +3,7 @@ on: pull_request: push: # If the branches list is ever changed, be sure to change it on all - # build/test jobs (nix, macos, windows) + # build/test jobs (nix, macos, windows, instrumentation) branches: # Always build the package branches - develop diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 13b48a04cdd..ed29b800ee5 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -4,7 +4,7 @@ on: pull_request: push: # If the branches list is ever changed, be sure to change it on all - # build/test jobs (nix, macos, windows) + # build/test jobs (nix, macos, windows, instrumentation) branches: # Always build the package branches - develop diff --git a/API-CHANGELOG.md b/API-CHANGELOG.md index 1c0595b0081..b3691d5ddcc 100644 --- a/API-CHANGELOG.md +++ b/API-CHANGELOG.md @@ -83,11 +83,13 @@ The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conve The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead. -## XRP Ledger server version 2.2.0 +## XRP Ledger server version 2.4.0 -The following is a non-breaking addition to the API. +### Addition in 2.4 -- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) +- `ledger_entry`: `state` is added an alias for `ripple_state`. + +## XRP Ledger server version 2.3.0 ### Breaking change in 2.3 @@ -105,6 +107,12 @@ The following additions are non-breaking (because they are purely additive). - In `Payment` transactions, `DeliverMax` has been added. This is a replacement for the `Amount` field, which should not be used. Typically, the `delivered_amount` (in transaction metadata) should be used. To ease the transition, `DeliverMax` is present regardless of API version, since adding a field is non-breaking. - API version 2 has been moved from beta to supported, meaning that it is generally available (regardless of the `beta_rpc_api` setting). +## XRP Ledger server version 2.2.0 + +The following is a non-breaking addition to the API. + +- The `feature` method now has a non-admin mode for users. (It was previously only available to admin connections.) The method returns an updated list of amendments, including their names and other information. ([#4781](https://github.com/XRPLF/rippled/pull/4781)) + ## XRP Ledger server version 1.12.0 [Version 1.12.0](https://github.com/XRPLF/rippled/releases/tag/1.12.0) was released on Sep 6, 2023. The following additions are non-breaking (because they are purely additive). diff --git a/Builds/levelization/results/loops.txt b/Builds/levelization/results/loops.txt index 669fb6bbe33..7c132f5429e 100644 --- a/Builds/levelization/results/loops.txt +++ b/Builds/levelization/results/loops.txt @@ -4,9 +4,6 @@ Loop: test.jtx test.toplevel Loop: test.jtx test.unit_test test.unit_test == test.jtx -Loop: xrpl.basics xrpl.json - xrpl.json == xrpl.basics - Loop: xrpld.app xrpld.core xrpld.app > xrpld.core diff --git a/Builds/levelization/results/ordering.txt b/Builds/levelization/results/ordering.txt index 396c99cb711..b2745b906c3 100644 --- a/Builds/levelization/results/ordering.txt +++ b/Builds/levelization/results/ordering.txt @@ -1,5 +1,4 @@ libxrpl.basics > xrpl.basics -libxrpl.basics > xrpl.protocol libxrpl.crypto > xrpl.basics libxrpl.json > xrpl.basics libxrpl.json > xrpl.json @@ -130,6 +129,7 @@ test.shamap > xrpl.protocol test.toplevel > test.csf test.toplevel > xrpl.json test.unit_test > xrpl.basics +xrpl.json > xrpl.basics xrpl.protocol > xrpl.basics xrpl.protocol > xrpl.json xrpl.resource > xrpl.basics diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c34f89397d..49ecd192b7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ set(SECP256K1_INSTALL TRUE) add_subdirectory(external/secp256k1) add_library(secp256k1::secp256k1 ALIAS secp256k1) add_subdirectory(external/ed25519-donna) +add_subdirectory(external/antithesis-sdk) find_package(gRPC REQUIRED) find_package(lz4 REQUIRED) # Target names with :: are not allowed in a generator expression. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ceca1eaa6fc..3bfce52c09b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -343,6 +343,68 @@ pip3 install pre-commit pre-commit install ``` +## Contracts and instrumentation + +We are using [Antithesis](https://antithesis.com/) for continuous fuzzing, +and keep a copy of [Antithesis C++ SDK](https://github.com/antithesishq/antithesis-sdk-cpp/) +in `external/antithesis-sdk`. One of the aims of fuzzing is to identify bugs +by finding external conditions which cause contracts violations inside `rippled`. +The contracts are expressed as `XRPL_ASSERT` or `UNREACHABLE` (defined in +`include/xrpl/beast/utility/instrumentation.h`), which are effectively (outside +of Antithesis) wrappers for `assert(...)` with added name. The purpose of name +is to provide contracts with stable identity which does not rely on line numbers. + +When `rippled` is built with the Antithesis instrumentation enabled +(using `voidstar` CMake option) and ran on the Antithesis platform, the +contracts become +[test properties](https://antithesis.com/docs/using_antithesis/properties.html); +otherwise they are just like a regular `assert`. +To learn more about Antithesis, see +[How Antithesis Works](https://antithesis.com/docs/introduction/how_antithesis_works.html) +and [C++ SDK](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html#) + +We continue to use the old style `assert` or `assert(false)` in certain +locations, where the reporting of contract violations on the Antithesis +platform is either not possible or not useful. + +For this reason: +* The locations where `assert` or `assert(false)` contracts should continue to be used: + * `constexpr` functions + * unit tests i.e. files under `src/test` + * unit tests-related modules (files under `beast/test` and `beast/unit_test`) +* Outside of the listed locations, do not use `assert`; use `XRPL_ASSERT` instead, + giving it unique name, with the short description of the contract. +* Outside of the listed locations, do not use `assert(false)`; use + `UNREACHABLE` instead, giving it unique name, with the description of the + condition being violated +* The contract name should start with a full name (including scope) of the + function, optionally a named lambda, followed by a colon ` : ` and a brief + (typically at most five words) description. `UNREACHABLE` contracts + can use slightly longer descriptions. If there are multiple overloads of the + function, use common sense to balance both brevity and unambiguity of the + function name. NOTE: the purpose of name is to provide stable means of + unique identification of every contract; for this reason try to avoid elements + which can change in some obvious refactors or when reinforcing the condition. +* Contract description typically (except for `UNREACHABLE`) should describe the + _expected_ condition, as in "I assert that _expected_ is true". +* Contract description for `UNREACHABLE` should describe the _unexpected_ + situation which caused the line to have been reached. +* Example good name for an + `UNREACHABLE` macro `"Json::operator==(Value, Value) : invalid type"`; example + good name for an `XRPL_ASSERT` macro `"Json::Value::asCString : valid type"`. +* Example **bad** name + `"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"` + (missing namespace, unnecessary full function signature, description too verbose). + Good name: `"ripple::RFC1751::insert : minimum length"`. +* In **few** well-justified cases a non-standard name can be used, in which case a + comment should be placed to explain the rationale (example in `contract.cpp`) +* Do **not** rename a contract without a good reason (e.g. the name no longer + reflects the location or the condition being checked) +* Do not use `std::unreachable` +* Do not put contracts where they can be violated by an external condition + (e.g. timing, data payload before mandatory validation etc.) as this creates + bogus bug reports (and causes crashes of Debug builds) + ## Unit Tests To execute all unit tests: diff --git a/cmake/RippledCompiler.cmake b/cmake/RippledCompiler.cmake index 43afc628bc3..7485605d950 100644 --- a/cmake/RippledCompiler.cmake +++ b/cmake/RippledCompiler.cmake @@ -120,7 +120,7 @@ else () target_link_libraries (common INTERFACE -rdynamic - $<$:-Wl,-z,relro,-z,now> + $<$:-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 @@ -131,6 +131,17 @@ else () >) endif () +# Antithesis instrumentation will only be built and deployed using machines running Linux. +if (voidstar) + if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Antithesis instrumentation requires Debug build type, aborting...") + elseif (NOT is_linux) + message(FATAL_ERROR "Antithesis instrumentation requires Linux, aborting...") + elseif (NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)) + message(FATAL_ERROR "Antithesis instrumentation requires Clang version 16 or later, aborting...") + endif () +endif () + if (use_mold) # use mold linker if available execute_process ( diff --git a/cmake/RippledCore.cmake b/cmake/RippledCore.cmake index 3b850354ed4..c37971befdb 100644 --- a/cmake/RippledCore.cmake +++ b/cmake/RippledCore.cmake @@ -47,6 +47,57 @@ target_link_libraries(xrpl.libpb gRPC::grpc++ ) +# TODO: Clean up the number of library targets later. +add_library(xrpl.imports.main INTERFACE) +target_link_libraries(xrpl.imports.main INTERFACE + LibArchive::LibArchive + OpenSSL::Crypto + Ripple::boost + Ripple::opts + Ripple::syslibs + absl::random_random + date::date + ed25519::ed25519 + secp256k1::secp256k1 + xxHash::xxhash +) + +include(add_module) +include(target_link_modules) + +# Level 01 +add_module(xrpl beast) +target_link_libraries(xrpl.libxrpl.beast PUBLIC + xrpl.imports.main + xrpl.libpb +) + +# Level 02 +add_module(xrpl basics) +target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast) + +# Level 03 +add_module(xrpl json) +target_link_libraries(xrpl.libxrpl.json PUBLIC xrpl.libxrpl.basics) + +add_module(xrpl crypto) +target_link_libraries(xrpl.libxrpl.crypto PUBLIC xrpl.libxrpl.basics) + +# Level 04 +add_module(xrpl protocol) +target_link_libraries(xrpl.libxrpl.protocol PUBLIC + xrpl.libxrpl.crypto + xrpl.libxrpl.json +) + +# Level 05 +add_module(xrpl resource) +target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol) + +add_module(xrpl server) +target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol) + + add_library(xrpl.libxrpl) set_target_properties(xrpl.libxrpl PROPERTIES OUTPUT_NAME xrpl) if(unity) @@ -60,10 +111,24 @@ file(GLOB_RECURSE sources CONFIGURE_DEPENDS ) target_sources(xrpl.libxrpl PRIVATE ${sources}) -target_include_directories(xrpl.libxrpl - PUBLIC - $ - $) +target_link_modules(xrpl PUBLIC + basics + beast + crypto + json + protocol + resource + server +) + +# All headers in libxrpl are in modules. +# Uncomment this stanza if you have not yet moved new headers into a module. +# target_include_directories(xrpl.libxrpl +# PRIVATE +# $ +# PUBLIC +# $ +# $) target_compile_definitions(xrpl.libxrpl PUBLIC @@ -74,6 +139,7 @@ target_compile_definitions(xrpl.libxrpl target_compile_options(xrpl.libxrpl PUBLIC $<$:-Wno-maybe-uninitialized> + $<$:-DENABLE_VOIDSTAR> ) target_link_libraries(xrpl.libxrpl @@ -89,6 +155,7 @@ target_link_libraries(xrpl.libxrpl secp256k1::secp256k1 xrpl.libpb xxHash::xxhash + $<$:antithesis-sdk-cpp> ) if(xrpld) @@ -129,6 +196,19 @@ if(xrpld) target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI) endif () + if(voidstar) + target_compile_options(rippled + PRIVATE + -fsanitize-coverage=trace-pc-guard + ) + # rippled requires access to antithesis-sdk-cpp implementation file + # antithesis_instrumentation.h, which is not exported as INTERFACE + target_include_directories(rippled + PRIVATE + ${CMAKE_SOURCE_DIR}/external/antithesis-sdk + ) + endif() + # any files that don't play well with unity should be added here if(tests) set_source_files_properties( diff --git a/cmake/RippledInstall.cmake b/cmake/RippledInstall.cmake index 3199c9a19b8..9ce288d7854 100644 --- a/cmake/RippledInstall.cmake +++ b/cmake/RippledInstall.cmake @@ -2,14 +2,25 @@ install stuff #]===================================================================] +include(create_symbolic_link) + install ( TARGETS common opts ripple_syslibs ripple_boost + xrpl.imports.main xrpl.libpb + xrpl.libxrpl.basics + xrpl.libxrpl.beast + xrpl.libxrpl.crypto + xrpl.libxrpl.json + xrpl.libxrpl.protocol + xrpl.libxrpl.resource + xrpl.libxrpl.server xrpl.libxrpl + antithesis-sdk-cpp EXPORT RippleExports LIBRARY DESTINATION lib ARCHIVE DESTINATION lib @@ -21,12 +32,12 @@ install( DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" ) -if(NOT WIN32) - install( - CODE "file(CREATE_LINK xrpl \ - \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple SYMBOLIC)" - ) -endif() +install(CODE " + set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") + include(create_symbolic_link) + create_symbolic_link(xrpl \ + \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple) +") install (EXPORT RippleExports FILE RippleTargets.cmake @@ -55,12 +66,12 @@ if (is_root_project AND TARGET rippled) copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/rippled-example.cfg\" etc rippled.cfg) copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt) ") - if(NOT WIN32) - install( - CODE "file(CREATE_LINK rippled${suffix} \ - \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix} SYMBOLIC)" - ) - endif() + install(CODE " + set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\") + include(create_symbolic_link) + create_symbolic_link(rippled${suffix} \ + \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix}) + ") endif () install ( diff --git a/cmake/RippledSettings.cmake b/cmake/RippledSettings.cmake index b81843cd5b5..3eeebed428c 100644 --- a/cmake/RippledSettings.cmake +++ b/cmake/RippledSettings.cmake @@ -18,6 +18,9 @@ if(unity) set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") endif() endif() +if(is_clang AND is_linux) + option(voidstar "Enable Antithesis instrumentation." OFF) +endif() if(is_gcc OR is_clang) option(coverage "Generates coverage info." OFF) option(profile "Add profiling flags" OFF) diff --git a/cmake/add_module.cmake b/cmake/add_module.cmake new file mode 100644 index 00000000000..bcfce1bf600 --- /dev/null +++ b/cmake/add_module.cmake @@ -0,0 +1,37 @@ +include(isolate_headers) + +# Create an OBJECT library target named +# +# ${PROJECT_NAME}.lib${parent}.${name} +# +# with sources in src/lib${parent}/${name} +# and headers in include/${parent}/${name} +# that cannot include headers from other directories in include/ +# unless they come through linked libraries. +# +# add_module(parent a) +# add_module(parent b) +# target_link_libraries(project.libparent.b PUBLIC project.libparent.a) +function(add_module parent name) + set(target ${PROJECT_NAME}.lib${parent}.${name}) + add_library(${target} OBJECT) + file(GLOB_RECURSE sources CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}/*.cpp" + ) + target_sources(${target} PRIVATE ${sources}) + target_include_directories(${target} PUBLIC + "$" + ) + isolate_headers( + ${target} + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_SOURCE_DIR}/include/${parent}/${name}" + PUBLIC + ) + isolate_headers( + ${target} + "${CMAKE_CURRENT_SOURCE_DIR}/src" + "${CMAKE_CURRENT_SOURCE_DIR}/src/lib${parent}/${name}" + PRIVATE + ) +endfunction() diff --git a/cmake/create_symbolic_link.cmake b/cmake/create_symbolic_link.cmake new file mode 100644 index 00000000000..60fcf2e0b57 --- /dev/null +++ b/cmake/create_symbolic_link.cmake @@ -0,0 +1,20 @@ +# file(CREATE_SYMLINK) only works on Windows with administrator privileges. +# https://stackoverflow.com/a/61244115/618906 +function(create_symbolic_link target link) + if(WIN32) + if(NOT IS_SYMLINK "${link}") + if(NOT IS_ABSOLUTE "${target}") + # Relative links work do not work on Windows. + set(target "${link}/../${target}") + endif() + file(TO_NATIVE_PATH "${target}" target) + file(TO_NATIVE_PATH "${link}" link) + execute_process(COMMAND cmd.exe /c mklink /J "${link}" "${target}") + endif() + else() + file(CREATE_LINK "${target}" "${link}" SYMBOLIC) + endif() + if(NOT IS_SYMLINK "${link}") + message(ERROR "failed to create symlink: <${link}>") + endif() +endfunction() diff --git a/cmake/isolate_headers.cmake b/cmake/isolate_headers.cmake new file mode 100644 index 00000000000..0a5a43a6a28 --- /dev/null +++ b/cmake/isolate_headers.cmake @@ -0,0 +1,48 @@ +include(create_symbolic_link) + +# Consider include directory B nested under prefix A: +# +# /path/to/A/then/to/B/... +# +# Call C the relative path from A to B. +# C is what we want to write in `#include` directives: +# +# #include +# +# Examples, all from the `jobqueue` module: +# +# - Library public headers: +# B = /include/xrpl/jobqueue +# A = /include/ +# C = xrpl/jobqueue +# +# - Library private headers: +# B = /src/libxrpl/jobqueue +# A = /src/ +# C = libxrpl/jobqueue +# +# - Test private headers: +# B = /tests/jobqueue +# A = / +# C = tests/jobqueue +# +# To isolate headers from each other, +# we want to create a symlink Y that points to B, +# within a subdirectory X of the `CMAKE_BINARY_DIR`, +# that has the same relative path C between X and Y, +# and then add X as an include directory of the target, +# sometimes `PUBLIC` and sometimes `PRIVATE`. +# The Cs are all guaranteed to be unique. +# We can guarantee a unique X per target by using +# `${CMAKE_CURRENT_BINARY_DIR}/include/${target}`. +# +# isolate_headers(target A B scope) +function(isolate_headers target A B scope) + file(RELATIVE_PATH C "${A}" "${B}") + set(X "${CMAKE_CURRENT_BINARY_DIR}/modules/${target}") + set(Y "${X}/${C}") + cmake_path(GET Y PARENT_PATH parent) + file(MAKE_DIRECTORY "${parent}") + create_symbolic_link("${B}" "${Y}") + target_include_directories(${target} ${scope} "$") +endfunction() diff --git a/cmake/target_link_modules.cmake b/cmake/target_link_modules.cmake new file mode 100644 index 00000000000..acbf67903a1 --- /dev/null +++ b/cmake/target_link_modules.cmake @@ -0,0 +1,24 @@ +# Link a library to its modules (see: `add_module`) +# and remove the module sources from the library's sources. +# +# add_module(parent a) +# add_module(parent b) +# target_link_libraries(project.libparent.b PUBLIC project.libparent.a) +# add_library(project.libparent) +# target_link_modules(parent PUBLIC a b) +function(target_link_modules parent scope) + set(library ${PROJECT_NAME}.lib${parent}) + foreach(name ${ARGN}) + set(module ${library}.${name}) + get_target_property(sources ${library} SOURCES) + list(LENGTH sources before) + get_target_property(dupes ${module} SOURCES) + list(LENGTH dupes expected) + list(REMOVE_ITEM sources ${dupes}) + list(LENGTH sources after) + math(EXPR actual "${before} - ${after}") + message(STATUS "${module} with ${expected} sources took ${actual} sources from ${library}") + set_target_properties(${library} PROPERTIES SOURCES "${sources}") + target_link_libraries(${library} ${scope} ${module}) + endforeach() +endfunction() diff --git a/external/README.md b/external/README.md index 25ae577ba58..c810539fd7d 100644 --- a/external/README.md +++ b/external/README.md @@ -6,6 +6,7 @@ The Conan recipes include patches we have not yet pushed upstream. | Folder | Upstream | Description | |:----------------|:---------------------------------------------|:------------| +| `antithesis-sdk`| [Project](https://github.com/antithesishq/antithesis-sdk-cpp/) | [Antithesis](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview.html) SDK for C++ | | `ed25519-donna` | [Project](https://github.com/floodyberry/ed25519-donna) | [Ed25519](http://ed25519.cr.yp.to/) digital signatures | | `rocksdb` | [Recipe](https://github.com/conan-io/conan-center-index/tree/master/recipes/rocksdb) | Fast key/value database. (Supports rotational disks better than NuDB.) | | `secp256k1` | [Project](https://github.com/bitcoin-core/secp256k1) | ECDSA digital signatures using the **secp256k1** curve | diff --git a/external/antithesis-sdk/.clang-format b/external/antithesis-sdk/.clang-format new file mode 100644 index 00000000000..e871ed18b43 --- /dev/null +++ b/external/antithesis-sdk/.clang-format @@ -0,0 +1,3 @@ +--- +DisableFormat: true +SortIncludes: false diff --git a/external/antithesis-sdk/CMakeLists.txt b/external/antithesis-sdk/CMakeLists.txt new file mode 100644 index 00000000000..d2c1f536afd --- /dev/null +++ b/external/antithesis-sdk/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.25) + +# Note, version set explicitly by rippled project +project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX) + +add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h) + +# Note, both sections below created by rippled project +target_include_directories(antithesis-sdk-cpp INTERFACE + $ + $ +) + +install( + FILES antithesis_sdk.h + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" +) diff --git a/external/antithesis-sdk/LICENSE b/external/antithesis-sdk/LICENSE new file mode 100644 index 00000000000..90f1712ed1a --- /dev/null +++ b/external/antithesis-sdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Antithesis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/external/antithesis-sdk/README.md b/external/antithesis-sdk/README.md new file mode 100644 index 00000000000..eb0237868de --- /dev/null +++ b/external/antithesis-sdk/README.md @@ -0,0 +1,8 @@ +# Antithesis C++ SDK + +This library provides methods for C++ programs to configure the [Antithesis](https://antithesis.com) platform. It contains three kinds of functionality: +* Assertion macros that allow you to define test properties about your software or workload. +* Randomness functions for requesting both structured and unstructured randomness from the Antithesis platform. +* Lifecycle functions that inform the Antithesis environment that particular test phases or milestones have been reached. + +For general usage guidance see the [Antithesis C++ SDK Documentation](https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/) diff --git a/external/antithesis-sdk/antithesis_instrumentation.h b/external/antithesis-sdk/antithesis_instrumentation.h new file mode 100644 index 00000000000..a88895d72a0 --- /dev/null +++ b/external/antithesis-sdk/antithesis_instrumentation.h @@ -0,0 +1,113 @@ +#pragma once + +/* +This header file enables code coverage instrumentation. It is distributed with the Antithesis C++ SDK. + +This header file can be used in both C and C++ programs. (The rest of the SDK works only for C++ programs.) + +You should include it in a single .cpp or .c file. + +The instructions (such as required compiler flags) and usage guidance are found at https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/. +*/ + +#include +#include +#include +#include +#include +#ifndef __cplusplus +#include +#include +#endif + +// If the libvoidstar(determ) library is present, +// pass thru trace_pc_guard related callbacks to it +typedef void (*trace_pc_guard_init_fn)(uint32_t *start, uint32_t *stop); +typedef void (*trace_pc_guard_fn)(uint32_t *guard, uint64_t edge); + +static trace_pc_guard_init_fn trace_pc_guard_init = NULL; +static trace_pc_guard_fn trace_pc_guard = NULL; +static bool did_check_libvoidstar = false; +static bool has_libvoidstar = false; + +static __attribute__((no_sanitize("coverage"))) void debug_message_out(const char *msg) { + (void)printf("%s\n", msg); + return; +} + +extern +#ifdef __cplusplus + "C" +#endif +__attribute__((no_sanitize("coverage"))) void antithesis_load_libvoidstar() { +#ifdef __cplusplus + constexpr +#endif + const char* LIB_PATH = "/usr/lib/libvoidstar.so"; + + if (did_check_libvoidstar) { + return; + } + debug_message_out("TRYING TO LOAD libvoidstar"); + did_check_libvoidstar = true; + void* shared_lib = dlopen(LIB_PATH, RTLD_NOW); + if (!shared_lib) { + debug_message_out("Can not load the Antithesis native library"); + return; + } + + void* trace_pc_guard_init_sym = dlsym(shared_lib, "__sanitizer_cov_trace_pc_guard_init"); + if (!trace_pc_guard_init_sym) { + debug_message_out("Can not forward calls to libvoidstar for __sanitizer_cov_trace_pc_guard_init"); + return; + } + + void* trace_pc_guard_sym = dlsym(shared_lib, "__sanitizer_cov_trace_pc_guard_internal"); + if (!trace_pc_guard_sym) { + debug_message_out("Can not forward calls to libvoidstar for __sanitizer_cov_trace_pc_guard"); + return; + } + + trace_pc_guard_init = (trace_pc_guard_init_fn)(trace_pc_guard_init_sym); + trace_pc_guard = (trace_pc_guard_fn)(trace_pc_guard_sym); + has_libvoidstar = true; + debug_message_out("LOADED libvoidstar"); +} + +// The following symbols are indeed reserved identifiers, since we're implementing functions defined +// in the compiler runtime. Not clear how to get Clang on board with that besides narrowly suppressing +// the warning in this case. The sample code on the CoverageSanitizer documentation page fails this +// warning! +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-identifier" +extern +#ifdef __cplusplus + "C" +#endif +void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { + debug_message_out("SDK forwarding to libvoidstar for __sanitizer_cov_trace_pc_guard_init()"); + if (!did_check_libvoidstar) { + antithesis_load_libvoidstar(); + } + if (has_libvoidstar) { + trace_pc_guard_init(start, stop); + } + return; +} + +extern +#ifdef __cplusplus + "C" +#endif +void __sanitizer_cov_trace_pc_guard( uint32_t *guard ) { + if (has_libvoidstar) { + uint64_t edge = (uint64_t)(__builtin_return_address(0)); + trace_pc_guard(guard, edge); + } else { + if (guard) { + *guard = 0; + } + } + return; +} +#pragma clang diagnostic pop diff --git a/external/antithesis-sdk/antithesis_sdk.h b/external/antithesis-sdk/antithesis_sdk.h new file mode 100644 index 00000000000..14eb292c2d5 --- /dev/null +++ b/external/antithesis-sdk/antithesis_sdk.h @@ -0,0 +1,1105 @@ +#pragma once + +// This header file contains the Antithesis C++ SDK, which enables C++ applications to integrate with the [Antithesis platform]. +// +// Documentation for the SDK is found at https://antithesis.com/docs/using_antithesis/sdk/cpp/overview/. + +#ifndef NO_ANTITHESIS_SDK + +#if __cplusplus < 202000L + #error "The Antithesis C++ API requires C++20 or higher" + #define NO_ANTITHESIS_SDK +#endif + +#if !defined(__clang__) + #error "The Antithesis C++ API requires a clang compiler" + #define NO_ANTITHESIS_SDK +#endif + +#if __clang_major__ < 16 + #error "The Antithesis C++ API requires clang version 16 or higher" + #define NO_ANTITHESIS_SDK +#endif + +#else + +#if __cplusplus < 201700L + #error "The Antithesis C++ API (with NO_ANTITHESIS_SDK) requires C++17 or higher" +#endif + +#endif + +/***************************************************************************** + * COMMON + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +namespace antithesis { + inline const char* SDK_VERSION = "0.4.4"; + inline const char* PROTOCOL_VERSION = "1.1.0"; + + struct JSON; struct JSONArray; + typedef std::variant JSONValue; + + struct JSONArray : std::vector { + using std::vector::vector; + + template::value, bool>::type = true> + JSONArray(std::vector vals) : std::vector(vals.begin(), vals.end()) {} + }; + + struct JSON : std::map { + JSON() : std::map() {} + JSON( std::initializer_list> args) : std::map(args) {} + + JSON( std::initializer_list> args, std::vector> more_args ) : std::map(args) { + for (auto& pair : more_args) { + (*this)[pair.first] = pair.second; + } + } + }; +} + + +/***************************************************************************** + * INTERNAL HELPERS: LOCAL RANDOM + * Used in both the NO_ANTITHESIS_SDK version and when running locally + *****************************************************************************/ + +#include + +namespace antithesis::internal::random { + struct LocalRandom { + std::random_device device; + std::mt19937_64 gen; + std::uniform_int_distribution distribution; + + LocalRandom() : device(), gen(device()), distribution() {} + + uint64_t random() { +#ifdef ANTITHESIS_RANDOM_OVERRIDE + return ANTITHESIS_RANDOM_OVERRIDE(); +#else + return distribution(gen); +#endif + } + }; +} + +/***************************************************************************** + * INTERNAL HELPERS: JSON + *****************************************************************************/ + +#ifndef NO_ANTITHESIS_SDK + +#include +#include + +namespace antithesis::internal::json { + template + inline constexpr bool always_false_v = false; + + static std::ostream& operator<<(std::ostream& out, const JSON& details); + + static void escaped(std::ostream& out, const char c) { + const char HEX[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + switch (c) { + case '\t': out << "\\t"; break; + case '\b': out << "\\b"; break; + case '\n': out << "\\n"; break; + case '\f': out << "\\f"; break; + case '\r': out << "\\r"; break; + case '\"': out << "\\\""; break; + case '\\': out << "\\\\"; break; + default: + if ('\u0000' <= c && c <= '\u001F') { + out << "\\u00" << HEX[(c >> 4) & 0x0F] << HEX[c & 0x0F]; + } else { + out << c; + } + } + } + + static std::ostream& operator<<(std::ostream& out, const JSONValue& json) { + std::visit([&](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + out << '"'; + for (auto c : arg) { + escaped(out, c); + } + out << '"'; + } else if constexpr (std::is_same_v) { + out << (arg ? "true" : "false"); + } else if constexpr (std::is_same_v) { + out << '"'; + escaped(out, arg); + out << '"'; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << '"'; + for (auto str = arg; *str != '\0'; str++) { + escaped(out, *str); + } + out << '"'; + } else if constexpr (std::is_same_v) { + out << "null"; + } else if constexpr (std::is_same_v) { + out << arg; + } else if constexpr (std::is_same_v) { + out << '['; + bool first = true; + for (auto &item : arg) { + if (!first) { + out << ','; + } + first = false; + out << item; + } + out << ']'; + } else { + static_assert(always_false_v, "non-exhaustive JSONValue visitor!"); + } + }, json); + + return out; + } + + static std::ostream& operator<<(std::ostream& out, const JSON& details) { + out << '{'; + + bool first = true; + for (auto [key, value] : details) { + if (!first) { + out << ','; + } + out << '"'; + for (auto c : key) { + escaped(out, c); + } + out << '"' << ':' << value; + first = false; + } + + out << '}'; + return out; + } +} + +#endif + +/***************************************************************************** + * INTERNAL HELPERS: HANDLERS + * Implementations for running locally and running in Antithesis + *****************************************************************************/ + +#ifndef NO_ANTITHESIS_SDK + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace antithesis::internal::handlers { + constexpr const char* const ERROR_LOG_LINE_PREFIX = "[* antithesis-sdk-cpp *]"; + constexpr const char* LIB_PATH = "/usr/lib/libvoidstar.so"; + constexpr const char* LOCAL_OUTPUT_ENVIRONMENT_VARIABLE = "ANTITHESIS_SDK_LOCAL_OUTPUT"; + + using namespace antithesis::internal::json; + + struct LibHandler { + virtual ~LibHandler() = default; + virtual void output(const char* message) const = 0; + virtual uint64_t random() = 0; + + void output(const JSON& json) const { + std::ostringstream out; + out << json; + output(out.str().c_str()); + } + }; + + struct AntithesisHandler : LibHandler { + void output(const char* message) const override { + if (message != nullptr) { + fuzz_json_data(message, strlen(message)); + fuzz_flush(); + } + } + + uint64_t random() override { + return fuzz_get_random(); + } + + static std::unique_ptr create() { + void* shared_lib = dlopen(LIB_PATH, RTLD_NOW); + if (!shared_lib) { + error("Can not load the Antithesis native library"); + return nullptr; + } + + void* fuzz_json_data = dlsym(shared_lib, "fuzz_json_data"); + if (!fuzz_json_data) { + error("Can not access symbol fuzz_json_data"); + return nullptr; + } + + void* fuzz_flush = dlsym(shared_lib, "fuzz_flush"); + if (!fuzz_flush) { + error("Can not access symbol fuzz_flush"); + return nullptr; + } + + void* fuzz_get_random = dlsym(shared_lib, "fuzz_get_random"); + if (!fuzz_get_random) { + error("Can not access symbol fuzz_get_random"); + return nullptr; + } + + return std::unique_ptr(new AntithesisHandler( + reinterpret_cast(fuzz_json_data), + reinterpret_cast(fuzz_flush), + reinterpret_cast(fuzz_get_random))); + } + + private: + typedef void (*fuzz_json_data_t)( const char* message, size_t length ); + typedef void (*fuzz_flush_t)(); + typedef uint64_t (*fuzz_get_random_t)(); + + + fuzz_json_data_t fuzz_json_data; + fuzz_flush_t fuzz_flush; + fuzz_get_random_t fuzz_get_random; + + AntithesisHandler(fuzz_json_data_t fuzz_json_data, fuzz_flush_t fuzz_flush, fuzz_get_random_t fuzz_get_random) : + fuzz_json_data(fuzz_json_data), fuzz_flush(fuzz_flush), fuzz_get_random(fuzz_get_random) {} + + static void error(const char* message) { + fprintf(stderr, "%s %s: %s\n", ERROR_LOG_LINE_PREFIX, message, dlerror()); + } + }; + + struct LocalHandler : LibHandler{ + ~LocalHandler() override { + if (file != nullptr) { + fclose(file); + } + } + + void output(const char* message) const override { + if (file != nullptr && message != nullptr) { + fprintf(file, "%s\n", message); + } + } + + uint64_t random() override { + return random_gen.random(); + } + + static std::unique_ptr create() { + return std::unique_ptr(new LocalHandler(create_internal())); + } + private: + FILE* file; + antithesis::internal::random::LocalRandom random_gen; + + LocalHandler(FILE* file): file(file), random_gen() { + } + + // If `localOutputEnvVar` is set to a non-empty path, attempt to open that path and truncate the file + // to serve as the log file of the local handler. + // Otherwise, we don't have a log file, and logging is a no-op in the local handler. + static FILE* create_internal() { + const char* path = std::getenv(LOCAL_OUTPUT_ENVIRONMENT_VARIABLE); + if (!path || !path[0]) { + return nullptr; + } + + // Open the file for writing (create if needed and possible) and truncate it + FILE* file = fopen(path, "w"); + if (file == nullptr) { + fprintf(stderr, "%s Failed to open path %s: %s\n", ERROR_LOG_LINE_PREFIX, path, strerror(errno)); + return nullptr; + } + int ret = fchmod(fileno(file), 0644); + if (ret != 0) { + fprintf(stderr, "%s Failed to set permissions for path %s: %s\n", ERROR_LOG_LINE_PREFIX, path, strerror(errno)); + fclose(file); + return nullptr; + } + + return file; + } + }; + + static std::unique_ptr init() { + struct stat stat_buf; + if (stat(LIB_PATH, &stat_buf) == 0) { + std::unique_ptr tmp = AntithesisHandler::create(); + if (!tmp) { + fprintf(stderr, "%s Failed to create handler for Antithesis library\n", ERROR_LOG_LINE_PREFIX); + exit(-1); + } + return tmp; + } else { + return LocalHandler::create(); + } + } + + inline LibHandler& get_lib_handler() { + static LibHandler* lib_handler = nullptr; + if (lib_handler == nullptr) { + lib_handler = init().release(); // Leak on exit, rather than exit-time-destructor + + JSON language_block{ + {"name", "C++"}, + {"version", __VERSION__} + }; + + JSON version_message{ + {"antithesis_sdk", JSON{ + {"language", language_block}, + {"sdk_version", SDK_VERSION}, + {"protocol_version", PROTOCOL_VERSION} + } + }}; + lib_handler->output(version_message); + } + + return *lib_handler; + } +} + +#endif + +/***************************************************************************** + * INTERNAL HELPERS: Various classes related to assertions + *****************************************************************************/ + +#ifndef NO_ANTITHESIS_SDK + +namespace antithesis::internal::assertions { + using namespace antithesis::internal::handlers; + + struct AssertionState { + uint8_t false_not_seen : 1; + uint8_t true_not_seen : 1; + uint8_t rest : 6; + + AssertionState() : false_not_seen(true), true_not_seen(true), rest(0) {} + }; + + enum AssertionType { + ALWAYS_ASSERTION, + ALWAYS_OR_UNREACHABLE_ASSERTION, + SOMETIMES_ASSERTION, + REACHABLE_ASSERTION, + UNREACHABLE_ASSERTION, + }; + + inline constexpr bool get_must_hit(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: + case SOMETIMES_ASSERTION: + case REACHABLE_ASSERTION: + return true; + case ALWAYS_OR_UNREACHABLE_ASSERTION: + case UNREACHABLE_ASSERTION: + return false; + } + } + + inline constexpr const char* get_assert_type_string(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: + case ALWAYS_OR_UNREACHABLE_ASSERTION: + return "always"; + case SOMETIMES_ASSERTION: + return "sometimes"; + case REACHABLE_ASSERTION: + case UNREACHABLE_ASSERTION: + return "reachability"; + } + } + + inline constexpr const char* get_display_type_string(AssertionType type) { + switch (type) { + case ALWAYS_ASSERTION: return "Always"; + case ALWAYS_OR_UNREACHABLE_ASSERTION: return "AlwaysOrUnreachable"; + case SOMETIMES_ASSERTION: return "Sometimes"; + case REACHABLE_ASSERTION: return "Reachable"; + case UNREACHABLE_ASSERTION: return "Unreachable"; + } + } + + struct LocationInfo { + const char* class_name; + const char* function_name; + const char* file_name; + const int line; + const int column; + + JSON to_json() const { + return JSON{ + {"class", class_name}, + {"function", function_name}, + {"file", file_name}, + {"begin_line", line}, + {"begin_column", column}, + }; + } + }; + + inline std::string make_key([[maybe_unused]] const char* message, const LocationInfo& location_info) { + return message; + } + + inline void assert_impl(bool cond, const char* message, const JSON& details, const LocationInfo& location_info, + bool hit, bool must_hit, const char* assert_type, const char* display_type, const char* id) { + JSON assertion{ + {"antithesis_assert", JSON{ + {"hit", hit}, + {"must_hit", must_hit}, + {"assert_type", assert_type}, + {"display_type", display_type}, + {"message", message}, + {"condition", cond}, + {"id", id}, + {"location", location_info.to_json()}, + {"details", details}, + }} + }; + antithesis::internal::handlers::get_lib_handler().output(assertion); + } + + inline void assert_raw(bool cond, const char* message, const JSON& details, + const char* class_name, const char* function_name, const char* file_name, const int line, const int column, + bool hit, bool must_hit, const char* assert_type, const char* display_type, const char* id) { + LocationInfo location_info{ class_name, function_name, file_name, line, column }; + assert_impl(cond, message, details, location_info, hit, must_hit, assert_type, display_type, id); + } + + typedef std::set CatalogEntryTracker; + + inline CatalogEntryTracker& get_catalog_entry_tracker() { + static CatalogEntryTracker catalog_entry_tracker; + return catalog_entry_tracker; + } + + struct Assertion { + AssertionState state; + AssertionType type; + const char* message; + LocationInfo location; + + Assertion(const char* message, AssertionType type, LocationInfo&& location) : + state(), type(type), message(message), location(std::move(location)) { + this->add_to_catalog(); + } + + void add_to_catalog() const { + std::string id = make_key(message, location); + CatalogEntryTracker& tracker = get_catalog_entry_tracker(); + if (!tracker.contains(id)) { + tracker.insert(id); + const bool condition = (type == REACHABLE_ASSERTION ? true : false); + const bool hit = false; + const char* assert_type = get_assert_type_string(type); + const bool must_hit = get_must_hit(type); + const char* display_type = get_display_type_string(type); + assert_impl(condition, message, {}, location, hit, must_hit, assert_type, display_type, id.c_str()); + } + } + + [[clang::always_inline]] inline void check_assertion(auto&& cond, const JSON& details) + requires requires { static_cast(std::forward(cond)); } { + #if defined(NO_ANTITHESIS_SDK) + #error "Antithesis SDK has been disabled" + #endif + if (__builtin_expect(state.false_not_seen || state.true_not_seen, false)) { + check_assertion_internal(static_cast(std::forward(cond)), details); + } + } + + private: + void check_assertion_internal(bool cond, const JSON& details) { + bool emit = false; + if (!cond && state.false_not_seen) { + emit = true; + state.false_not_seen = false; // TODO: is the race OK? + } + + if (cond && state.true_not_seen) { + emit = true; + state.true_not_seen = false; // TODO: is the race OK? + } + + if (emit) { + const bool hit = true; + const char* assert_type = get_assert_type_string(type); + const bool must_hit = get_must_hit(type); + const char* display_type = get_display_type_string(type); + std::string id = make_key(message, location); + assert_impl(cond, message, details, location, hit, must_hit, assert_type, display_type, id.c_str()); + } + } + }; + + enum GuidepostType { + GUIDEPOST_MAXIMIZE, + GUIDEPOST_MINIMIZE, + GUIDEPOST_EXPLORE, + GUIDEPOST_ALL, + GUIDEPOST_NONE + }; + + inline constexpr const char* get_guidance_type_string(GuidepostType type) { + switch (type) { + case GUIDEPOST_MAXIMIZE: + case GUIDEPOST_MINIMIZE: + return "numeric"; + case GUIDEPOST_ALL: + case GUIDEPOST_NONE: + return "boolean"; + case GUIDEPOST_EXPLORE: + return "json"; + } + } + + inline constexpr bool does_guidance_maximize(GuidepostType type) { + switch (type) { + case GUIDEPOST_MAXIMIZE: + case GUIDEPOST_ALL: + return true; + case GUIDEPOST_EXPLORE: + case GUIDEPOST_MINIMIZE: + case GUIDEPOST_NONE: + return false; + } + } + + template > + struct NumericGuidepost { + const char* message; + LocationInfo location; + GuidepostType type; + // an approximation of (left - right) / 2; contains an absolute value and a sign bit + std::pair extreme_half_gap; + + NumericGuidepost(const char* message, LocationInfo&& location, GuidepostType type) : + message(message), location(std::move(location)), type(type) { + this->add_to_catalog(); + if (type == GUIDEPOST_MAXIMIZE) { + extreme_half_gap = { std::numeric_limits::max(), false }; + } else { + extreme_half_gap = { std::numeric_limits::max(), true }; + } + } + + inline void add_to_catalog() { + std::string id = make_key(message, location); + JSON catalog{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(type)}, + {"message", message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(type)}, + {"hit", false} + }} + }; + get_lib_handler().output(catalog); + } + + std::pair compute_half_gap(NumericValue left, NumericValue right) { + // An extremely baroque way to compute (left - right) / 2, rounded toward 0, without overflowing or underflowing + if (std::is_integral_v) { + // If both numbers are odd then the gap doesn't change if we subtract 1 from both sides + // Also subtracting 1 from both sides won't underflow + if (left % 2 == 1 && right % 2 == 1) + return compute_half_gap( left - 1, right - 1); + // If one number is odd then we subtract 1 from the larger number + // This rounds the computation toward 0 but again won't underflow + if (left % 2 == 1 || right % 2 == 1) { + if (left > right) { + return compute_half_gap( left - 1, right ); + } else { + return compute_half_gap( left, right - 1 ); + } + } + // At this point both numbers are even, so the midpoint calculation is exact + NumericValue half_left = left / 2; + NumericValue half_right = right / 2; + NumericValue midpoint = half_left + half_right; + // This won't overflow or underflow because we're subtracting the midpoint + // We compute a positive value and a sign so that we don't have to do weird things with unsigned types + if (left > right) { + return { midpoint - right, true }; + } else { + return { right - midpoint, false }; + } + } else { + // If it's floating point we don't need to worry about overflowing, just do the arithmetic + return { left > right ? (left - right) / 2 : (right - left) / 2, left > right }; + } + } + + bool should_send_value(std::pair half_gap) { + if (this->type == GUIDEPOST_MAXIMIZE) { + if (half_gap.second && !extreme_half_gap.second) { + // we're positive and the extreme value isn't; always send back + return true; + } else if (!half_gap.second && extreme_half_gap.second) { + // we're negative and the extreme value is positive; never send back + return false; + } else if (half_gap.second && extreme_half_gap.second) { + // both positive; send back if our absolute value is at least as large + return half_gap.first >= extreme_half_gap.first; + } else { + // both negative; send back if our absolute value is at least as small + return half_gap.first <= extreme_half_gap.first; + } + } else { + if (half_gap.second && !extreme_half_gap.second) { + // we're positive and the extreme value isn't; never send back + return false; + } else if (!half_gap.second && extreme_half_gap.second) { + // we're negative and the extreme value is positive; always send back + return true; + } else if (half_gap.second && extreme_half_gap.second) { + // both positive; send back if our absolute value is at least as small + return half_gap.first <= extreme_half_gap.first; + } else { + // both negative; send back if our absolute value is at least as large + return half_gap.first >= extreme_half_gap.first; + } + } + } + + [[clang::always_inline]] inline void send_guidance(Value value) { + std::pair half_gap = compute_half_gap(value.first, value.second); + if (should_send_value(half_gap)) { + extreme_half_gap = half_gap; + std::string id = make_key(this->message, this->location); + JSON guidance{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(this->type)}, + {"message", this->message}, + {"id", id}, + {"location", this->location.to_json()}, + {"maximize", does_guidance_maximize(this->type)}, + {"guidance_data", JSON{ + { "left", value.first }, + { "right", value.second } }}, + {"hit", true} + }} + }; + get_lib_handler().output(guidance); + } + } + }; + + template + struct BooleanGuidepost { + const char* message; + LocationInfo location; + GuidepostType type; + + BooleanGuidepost(const char* message, LocationInfo&& location, GuidepostType type) : + message(message), location(std::move(location)), type(type) { + this->add_to_catalog(); + } + + inline void add_to_catalog() { + std::string id = make_key(message, location); + JSON catalog{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(type)}, + {"message", message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(type)}, + {"hit", false} + }} + }; + get_lib_handler().output(catalog); + } + + inline virtual void send_guidance(GuidanceType data) { + std::string id = make_key(this->message, this->location); + JSON guidance{ + {"antithesis_guidance", JSON{ + {"guidance_type", get_guidance_type_string(this->type)}, + {"message", this->message}, + {"id", id}, + {"location", location.to_json()}, + {"maximize", does_guidance_maximize(this->type)}, + {"guidance_data", data}, + {"hit", true} + }} + }; + get_lib_handler().output(guidance); + } + }; +} + +namespace antithesis::internal { +namespace { // Anonymous namespace which is translation-unit-specific; certain symbols aren't exposed in the symbol table as a result + template + struct fixed_string { + std::array contents; + constexpr fixed_string() { + for(unsigned int i=0; i from_c_str( const char* s ) { + fixed_string it; + for(unsigned int i=0; i + fixed_string( const char (&arr)[N] ) -> fixed_string; + + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + static constexpr size_t string_length( const char * s ) { + for(int l = 0; ; l++) + if (!s[l]) + return l; + } + #pragma clang diagnostic pop + + template + struct CatalogEntry { + [[clang::always_inline]] static inline antithesis::internal::assertions::Assertion create() { + antithesis::internal::assertions::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + return antithesis::internal::assertions::Assertion(message.c_str(), type, std::move(location)); + } + + static inline antithesis::internal::assertions::Assertion assertion = create(); + }; + + template + struct BooleanGuidanceCatalogEntry { + [[clang::always_inline]] static inline antithesis::internal::assertions::BooleanGuidepost create() { + antithesis::internal::assertions::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + switch (type) { + case antithesis::internal::assertions::GUIDEPOST_ALL: + case antithesis::internal::assertions::GUIDEPOST_NONE: + return antithesis::internal::assertions::BooleanGuidepost(message.c_str(), std::move(location), type); + default: + throw std::runtime_error("Can't create boolean guidepost with non-boolean type"); + } + } + + static inline antithesis::internal::assertions::BooleanGuidepost guidepost = create(); + }; + + template + struct NumericGuidanceCatalogEntry { + [[clang::always_inline]] static inline antithesis::internal::assertions::NumericGuidepost create() { + antithesis::internal::assertions::LocationInfo location{ "", function_name.c_str(), file_name.c_str(), line, column }; + switch (type) { + case antithesis::internal::assertions::GUIDEPOST_MAXIMIZE: + case antithesis::internal::assertions::GUIDEPOST_MINIMIZE: + return antithesis::internal::assertions::NumericGuidepost(message.c_str(), std::move(location), type); + default: + throw std::runtime_error("Can't create numeric guidepost with non-numeric type"); + } + } + + static inline antithesis::internal::assertions::NumericGuidepost guidepost = create(); + }; +} +} + +#endif + +/***************************************************************************** + * PUBLIC SDK: ASSERTIONS + *****************************************************************************/ + +#define _NL_1(foo) { #foo, foo } +#define _NL_2(foo, ...) { #foo, foo }, _NL_1(__VA_ARGS__) +#define _NL_3(foo, ...) { #foo, foo }, _NL_2(__VA_ARGS__) +#define _NL_4(foo, ...) { #foo, foo }, _NL_3(__VA_ARGS__) +#define _NL_5(foo, ...) { #foo, foo }, _NL_4(__VA_ARGS__) +#define _NL_6(foo, ...) { #foo, foo }, _NL_5(__VA_ARGS__) +#define _NL_7(foo, ...) { #foo, foo }, _NL_6(__VA_ARGS__) +#define _NL_8(foo, ...) { #foo, foo }, _NL_7(__VA_ARGS__) +#define _NL_9(foo, ...) { #foo, foo }, _NL_8(__VA_ARGS__) +#define _NL_10(foo, ...) { #foo, foo }, _NL_9(__VA_ARGS__) + +#define _ELEVENTH_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define _GET_NL(...) \ + _ELEVENTH_ARG(__VA_ARGS__, _NL_10, _NL_9, _NL_8, _NL_7, _NL_6, _NL_5, _NL_4, _NL_3, _NL_2, _NL_1) + +#define NAMED_LIST(...) { _GET_NL(__VA_ARGS__)(__VA_ARGS__) } + +#ifdef NO_ANTITHESIS_SDK + +#ifndef ANTITHESIS_SDK_ALWAYS_POLYFILL + #define ANTITHESIS_SDK_ALWAYS_POLYFILL(...) +#endif + +#ifndef ANTITHESIS_SDK_SOMETIMES_POLYFILL + #define ANTITHESIS_SDK_SOMETIMES_POLYFILL(...) +#endif + +#ifndef ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL + #define ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL(...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL(__VA_ARGS__) +#endif + +#define ALWAYS(cond, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL(cond, message, __VA_ARGS__) +#define ALWAYS_OR_UNREACHABLE(cond, message, ...) \ + ANTITHESIS_SDK_ALWAYS_OR_UNREACHABLE_POLYFILL(cond, message, __VA_ARGS__) +#define SOMETIMES(cond, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL(cond, message, __VA_ARGS__) +#define REACHABLE(message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL(true, message, __VA_ARGS__) +#define UNREACHABLE(message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL(false, message, __VA_ARGS__) +#define ALWAYS_GREATER_THAN(val, threshold, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL((val > threshold), message, __VA_ARGS__) +#define ALWAYS_GREATER_THAN_OR_EQUAL_TO(val, threshold, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL((val >= threshold), message, __VA_ARGS__) +#define SOMETIMES_GREATER_THAN(val, threshold, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL((val > threshold), message, __VA_ARGS__) +#define SOMETIMES_GREATER_THAN_OR_EQUAL_TO(val, threshold, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL((val >= threshold), message, __VA_ARGS__) +#define ALWAYS_LESS_THAN(val, threshold, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL((val < threshold), message, __VA_ARGS__) +#define ALWAYS_LESS_THAN_OR_EQUAL_TO(val, threshold, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL((val <= threshold), message, __VA_ARGS__) +#define SOMETIMES_LESS_THAN(val, threshold, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL((val < threshold), message, __VA_ARGS__) +#define SOMETIMES_LESS_THAN_OR_EQUAL_TO(val, threshold, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL((val <= threshold), message, __VA_ARGS__) +#define ALWAYS_SOME(pairs, message, ...) \ + ANTITHESIS_SDK_ALWAYS_POLYFILL(([&](){ \ + std::initializer_list> ps = pairs; \ + for (auto const& pair : ps) \ + if (pair.second) return true; \ + return false; }()), message, __VA_ARGS__) +#define SOMETIMES_ALL(pairs, message, ...) \ + ANTITHESIS_SDK_SOMETIMES_POLYFILL(([&](){ \ + std::initializer_list> ps = pairs; \ + for (auto const& pair : ps) \ + if (!pair.second) return false; \ + return true; }()), message, __VA_ARGS__) + +#else + +#include + +#define FIXED_STRING_FROM_C_STR(s) (antithesis::internal::fixed_string::from_c_str(s)) + +#define ANTITHESIS_ASSERT_RAW(type, cond, message, ...) ( \ + antithesis::internal::CatalogEntry< \ + type, \ + antithesis::internal::fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::assertion.check_assertion(cond, (antithesis::JSON(__VA_ARGS__)) ) ) + +#define ALWAYS(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_ASSERTION, cond, message, __VA_ARGS__) +#define ALWAYS_OR_UNREACHABLE(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_OR_UNREACHABLE_ASSERTION, cond, message, __VA_ARGS__) +#define SOMETIMES(cond, message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::SOMETIMES_ASSERTION, cond, message, __VA_ARGS__) +#define REACHABLE(message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::REACHABLE_ASSERTION, true, message, __VA_ARGS__) +#define UNREACHABLE(message, ...) ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::UNREACHABLE_ASSERTION, false, message, __VA_ARGS__) + +#define ANTITHESIS_NUMERIC_ASSERT_RAW(name, assertion_type, guidepost_type, left, cmp, right, message, ...) \ +do { \ + static_assert(std::is_same_v, "Values compared in " #name " must be of same type"); \ + ANTITHESIS_ASSERT_RAW(assertion_type, left cmp right, message, __VA_ARGS__ __VA_OPT__(,) {{ "left", left }, { "right", right }} ); \ + antithesis::internal::NumericGuidanceCatalogEntry< \ + decltype(left), \ + guidepost_type, \ + antithesis::internal::fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance({ left, right }); \ +} while (0) + +#define ALWAYS_GREATER_THAN(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_GREATER_THAN, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, >, right, message, __VA_ARGS__) +#define ALWAYS_GREATER_THAN_OR_EQUAL_TO(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_GREATER_THAN_OR_EQUAL_TO, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, >=, right, message, __VA_ARGS__) +#define SOMETIMES_GREATER_THAN(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_GREATER_THAN, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, >, right, message, __VA_ARGS__) +#define SOMETIMES_GREATER_THAN_OR_EQUAL_TO(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_GREATER_THAN_OR_EQUAL_TO, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, >=, right, message, __VA_ARGS__) +#define ALWAYS_LESS_THAN(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_LESS_THAN, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, <, right, message, __VA_ARGS__) +#define ALWAYS_LESS_THAN_OR_EQUAL_TO(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(ALWAYS_LESS_THAN_OR_EQUAL_TO, antithesis::internal::assertions::ALWAYS_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MAXIMIZE, left, <=, right, message, __VA_ARGS__) +#define SOMETIMES_LESS_THAN(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_LESS_THAN, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, <, right, message, __VA_ARGS__) +#define SOMETIMES_LESS_THAN_OR_EQUAL_TO(left, right, message, ...) \ +ANTITHESIS_NUMERIC_ASSERT_RAW(SOMETIMES_LESS_THAN_OR_EQUAL_TO, antithesis::internal::assertions::SOMETIMES_ASSERTION, antithesis::internal::assertions::GUIDEPOST_MINIMIZE, left, <=, right, message, __VA_ARGS__) + +#define ALWAYS_SOME(pairs, message, ...) \ +do { \ + bool disjunction = false; \ + std::vector> vec_pairs = pairs; \ + for (std::pair pair : vec_pairs) { \ + if (pair.second) { \ + disjunction = true; \ + break; \ + } \ + } \ + ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::ALWAYS_ASSERTION, disjunction, message, __VA_ARGS__ __VA_OPT__(,) pairs); \ + antithesis::JSON json_pairs = antithesis::JSON(pairs); \ + antithesis::internal::BooleanGuidanceCatalogEntry< \ + decltype(json_pairs), \ + antithesis::internal::assertions::GUIDEPOST_NONE, \ + antithesis::internal::fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance(json_pairs); \ +} while (0) + +#define SOMETIMES_ALL(pairs, message, ...) \ +do { \ + bool conjunction = true; \ + std::vector> vec_pairs = pairs; \ + for (std::pair pair : vec_pairs) { \ + if (!pair.second) { \ + conjunction = false; \ + break; \ + } \ + } \ + ANTITHESIS_ASSERT_RAW(antithesis::internal::assertions::SOMETIMES_ASSERTION, conjunction, message, __VA_ARGS__ __VA_OPT__(,) pairs); \ + antithesis::JSON json_pairs = antithesis::JSON(pairs); \ + antithesis::internal::BooleanGuidanceCatalogEntry< \ + decltype(json_pairs), \ + antithesis::internal::assertions::GUIDEPOST_ALL, \ + antithesis::internal::fixed_string(message), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().file_name()), \ + FIXED_STRING_FROM_C_STR(std::source_location::current().function_name()), \ + std::source_location::current().line(), \ + std::source_location::current().column() \ + >::guidepost.send_guidance(json_pairs); \ +} while (0) + +#endif + +/***************************************************************************** + * PUBLIC SDK: LIFECYCLE + *****************************************************************************/ + +#ifdef NO_ANTITHESIS_SDK + +namespace antithesis { + inline void setup_complete(const JSON& details) { + } + + inline void send_event(const char* name, const JSON& details) { + } +} + +#else + +namespace antithesis { + inline void setup_complete(const JSON& details) { + JSON json{ + { "antithesis_setup", JSON{ + {"status", "complete"}, + {"details", details} + }} + }; + antithesis::internal::handlers::get_lib_handler().output(json); + } + + inline void send_event(const char* name, const JSON& details) { + JSON json = { { name, details } }; + antithesis::internal::handlers::get_lib_handler().output(json); + } +} +#endif + +/***************************************************************************** + * PUBLIC SDK: RANDOM + *****************************************************************************/ + +namespace antithesis { + // Declarations that we expose + uint64_t get_random(); +} + +#ifdef NO_ANTITHESIS_SDK + +namespace antithesis { + inline uint64_t get_random() { + static antithesis::internal::random::LocalRandom random_gen; + return random_gen.random(); + } +} + +#else + +namespace antithesis { + inline uint64_t get_random() { + return antithesis::internal::handlers::get_lib_handler().random(); + } +} + +#endif + +namespace antithesis { + template + Iter random_choice(Iter begin, Iter end) { + ssize_t num_things = end - begin; + if (num_things == 0) { + return end; + } + + uint64_t uval = get_random(); + ssize_t index = uval % num_things; + return begin + index; + } +} diff --git a/include/xrpl/basics/Buffer.h b/include/xrpl/basics/Buffer.h index 25ae8ca315c..eb7a4571981 100644 --- a/include/xrpl/basics/Buffer.h +++ b/include/xrpl/basics/Buffer.h @@ -21,7 +21,7 @@ #define RIPPLE_BASICS_BUFFER_H_INCLUDED #include -#include +#include #include #include #include @@ -112,9 +112,10 @@ class Buffer operator=(Slice s) { // Ensure the slice isn't a subset of the buffer. - assert( + XRPL_ASSERT( s.size() == 0 || size_ == 0 || s.data() < p_.get() || - s.data() >= p_.get() + size_); + s.data() >= p_.get() + size_, + "ripple::Buffer::operator=(Slice) : input not a subset"); if (auto p = alloc(s.size())) std::memcpy(p, s.data(), s.size()); diff --git a/include/xrpl/basics/Expected.h b/include/xrpl/basics/Expected.h index 10f188af11c..ced41b13caa 100644 --- a/include/xrpl/basics/Expected.h +++ b/include/xrpl/basics/Expected.h @@ -137,13 +137,15 @@ class [[nodiscard]] Expected public: template requires std::convertible_to - constexpr Expected(U&& r) : Base(T(std::forward(r))) + constexpr Expected(U&& r) + : Base(boost::outcome_v2::in_place_type_t{}, std::forward(r)) { } template requires std::convertible_to && (!std::is_reference_v) - constexpr Expected(Unexpected e) : Base(E(std::move(e.value()))) + constexpr Expected(Unexpected e) + : Base(boost::outcome_v2::in_place_type_t{}, std::move(e.value())) { } diff --git a/include/xrpl/basics/MathUtilities.h b/include/xrpl/basics/MathUtilities.h index 4e8e3751cd8..516c07f377f 100644 --- a/include/xrpl/basics/MathUtilities.h +++ b/include/xrpl/basics/MathUtilities.h @@ -43,7 +43,7 @@ namespace ripple { constexpr std::size_t calculatePercent(std::size_t count, std::size_t total) { - assert(total != 0); + assert(total != 0); // NOTE No XRPL_ASSERT here, because constexpr return ((std::min(count, total) * 100) + total - 1) / total; } diff --git a/include/xrpl/basics/Number.h b/include/xrpl/basics/Number.h index 70baf5d1e47..9ee05bfb450 100644 --- a/include/xrpl/basics/Number.h +++ b/include/xrpl/basics/Number.h @@ -20,8 +20,6 @@ #ifndef RIPPLE_BASICS_NUMBER_H_INCLUDED #define RIPPLE_BASICS_NUMBER_H_INCLUDED -#include -#include #include #include #include @@ -60,9 +58,6 @@ class Number explicit Number(rep mantissa, int exponent); explicit constexpr Number(rep mantissa, int exponent, unchecked) noexcept; - Number(XRPAmount const& x); - Number(MPTAmount const& x); - constexpr rep mantissa() const noexcept; constexpr int @@ -104,10 +99,6 @@ class Number * "mixed mode" more convenient, e.g. MPTAmount + Number. */ explicit - operator XRPAmount() const; // round to nearest, even on tie - explicit - operator MPTAmount() const; // round to nearest, even on tie - explicit operator rep() const; // round to nearest, even on tie friend constexpr bool @@ -217,14 +208,6 @@ inline Number::Number(rep mantissa) : Number{mantissa, 0} { } -inline Number::Number(XRPAmount const& x) : Number{x.drops()} -{ -} - -inline Number::Number(MPTAmount const& x) : Number{x.value()} -{ -} - inline constexpr Number::rep Number::mantissa() const noexcept { diff --git a/include/xrpl/basics/SHAMapHash.h b/include/xrpl/basics/SHAMapHash.h index 7e93ead78d3..2d2dcdc3efa 100644 --- a/include/xrpl/basics/SHAMapHash.h +++ b/include/xrpl/basics/SHAMapHash.h @@ -21,6 +21,7 @@ #define RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED #include +#include #include @@ -108,6 +109,13 @@ operator!=(SHAMapHash const& x, SHAMapHash const& y) return !(x == y); } +template <> +inline std::size_t +extract(SHAMapHash const& key) +{ + return *reinterpret_cast(key.as_uint256().data()); +} + } // namespace ripple #endif // RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED diff --git a/include/xrpl/basics/SlabAllocator.h b/include/xrpl/basics/SlabAllocator.h index 5c4cba343cf..5e3a2b5138e 100644 --- a/include/xrpl/basics/SlabAllocator.h +++ b/include/xrpl/basics/SlabAllocator.h @@ -20,7 +20,9 @@ #ifndef RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED #define RIPPLE_BASICS_SLABALLOCATOR_H_INCLUDED +#include #include +#include #include #include @@ -28,10 +30,10 @@ #include #include -#include #include #include #include +#include #if BOOST_OS_LINUX #include @@ -141,7 +143,9 @@ class SlabAllocator void deallocate(std::uint8_t* ptr) noexcept { - assert(own(ptr)); + XRPL_ASSERT( + own(ptr), + "ripple::SlabAllocator::SlabBlock::deallocate : own input"); std::lock_guard l(m_); @@ -184,7 +188,9 @@ class SlabAllocator boost::alignment::align_up(sizeof(Type) + extra, itemAlignment_)) , slabSize_(alloc) { - assert((itemAlignment_ & (itemAlignment_ - 1)) == 0); + XRPL_ASSERT( + (itemAlignment_ & (itemAlignment_ - 1)) == 0, + "ripple::SlabAllocator::SlabAllocator : valid alignment"); } SlabAllocator(SlabAllocator const& other) = delete; @@ -294,7 +300,10 @@ class SlabAllocator bool deallocate(std::uint8_t* ptr) noexcept { - assert(ptr); + XRPL_ASSERT( + ptr, + "ripple::SlabAllocator::SlabAllocator::deallocate : non-null " + "input"); for (auto slab = slabs_.load(); slab != nullptr; slab = slab->next_) { diff --git a/include/xrpl/basics/Slice.h b/include/xrpl/basics/Slice.h index 00126f8882d..9e9991f0dd2 100644 --- a/include/xrpl/basics/Slice.h +++ b/include/xrpl/basics/Slice.h @@ -22,9 +22,9 @@ #include #include +#include #include #include -#include #include #include #include @@ -103,7 +103,9 @@ class Slice std::uint8_t operator[](std::size_t i) const noexcept { - assert(i < size_); + XRPL_ASSERT( + i < size_, + "ripple::Slice::operator[](std::size_t) const : valid input"); return data_[i]; } diff --git a/include/xrpl/basics/base_uint.h b/include/xrpl/basics/base_uint.h index ae5aa17a63e..05d83b3bb0a 100644 --- a/include/xrpl/basics/base_uint.h +++ b/include/xrpl/basics/base_uint.h @@ -29,8 +29,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -289,7 +291,9 @@ class base_uint std::is_trivially_copyable::value>> explicit base_uint(Container const& c) { - assert(c.size() * sizeof(typename Container::value_type) == size()); + XRPL_ASSERT( + c.size() * sizeof(typename Container::value_type) == size(), + "ripple::base_uint::base_uint(Container auto) : input size match"); std::memcpy(data_.data(), c.data(), size()); } @@ -300,7 +304,9 @@ class base_uint base_uint&> operator=(Container const& c) { - assert(c.size() * sizeof(typename Container::value_type) == size()); + XRPL_ASSERT( + c.size() * sizeof(typename Container::value_type) == size(), + "ripple::base_uint::operator=(Container auto) : input size match"); std::memcpy(data_.data(), c.data(), size()); return *this; } @@ -632,6 +638,17 @@ operator<<(std::ostream& out, base_uint const& u) return out << to_string(u); } +template <> +inline std::size_t +extract(uint256 const& key) +{ + std::size_t result; + // Use memcpy to avoid unaligned UB + // (will optimize to equivalent code) + std::memcpy(&result, key.data(), sizeof(std::size_t)); + return result; +} + #ifndef __INTELLISENSE__ static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes"); static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes"); diff --git a/include/xrpl/basics/partitioned_unordered_map.h b/include/xrpl/basics/partitioned_unordered_map.h index 08f4cba9d3e..4619ca1f4ce 100644 --- a/include/xrpl/basics/partitioned_unordered_map.h +++ b/include/xrpl/basics/partitioned_unordered_map.h @@ -20,9 +20,11 @@ #ifndef RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H #define RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H -#include +#include +#include #include #include +#include #include #include #include @@ -31,8 +33,18 @@ namespace ripple { template -std::size_t -partitioner(Key const& key, std::size_t const numPartitions); +static std::size_t +extract(Key const& key) +{ + return key; +} + +template <> +inline std::size_t +extract(std::string const& key) +{ + return ::beast::uhash<>{}(key); +} template < typename Key, @@ -211,7 +223,7 @@ class partitioned_unordered_map std::size_t partitioner(Key const& key) const { - return ripple::partitioner(key, partitions_); + return extract(key) % partitions_; } template @@ -246,7 +258,10 @@ class partitioned_unordered_map ? *partitions : std::thread::hardware_concurrency(); map_.resize(partitions_); - assert(partitions_); + XRPL_ASSERT( + partitions_, + "ripple::partitioned_unordered_map::partitioned_unordered_map : " + "nonzero partitions"); } std::size_t diff --git a/include/xrpl/basics/random.h b/include/xrpl/basics/random.h index 87b303bf6d5..ca65b581d2e 100644 --- a/include/xrpl/basics/random.h +++ b/include/xrpl/basics/random.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_BASICS_RANDOM_H_INCLUDED #define RIPPLE_BASICS_RANDOM_H_INCLUDED +#include #include -#include #include #include #include @@ -114,7 +114,7 @@ std::enable_if_t< Integral> rand_int(Engine& engine, Integral min, Integral max) { - assert(max > min); + XRPL_ASSERT(max > min, "ripple::rand_int : max over min inputs"); // This should have no state and constructing it should // be very cheap. If that turns out not to be the case diff --git a/include/xrpl/basics/scope.h b/include/xrpl/basics/scope.h index b1d13eae8ce..954edcc2a16 100644 --- a/include/xrpl/basics/scope.h +++ b/include/xrpl/basics/scope.h @@ -20,6 +20,8 @@ #ifndef RIPPLE_BASICS_SCOPE_H_INCLUDED #define RIPPLE_BASICS_SCOPE_H_INCLUDED +#include + #include #include #include @@ -233,7 +235,9 @@ class scope_unlock explicit scope_unlock(std::unique_lock& lock) noexcept(true) : plock(&lock) { - assert(plock->owns_lock()); + XRPL_ASSERT( + plock->owns_lock(), + "ripple::scope_unlock::scope_unlock : mutex must be locked"); plock->unlock(); } diff --git a/include/xrpl/basics/spinlock.h b/include/xrpl/basics/spinlock.h index 85a2ac41d51..14a063e27a6 100644 --- a/include/xrpl/basics/spinlock.h +++ b/include/xrpl/basics/spinlock.h @@ -18,8 +18,8 @@ #ifndef RIPPLE_BASICS_SPINLOCK_H_INCLUDED #define RIPPLE_BASICS_SPINLOCK_H_INCLUDED +#include #include -#include #include #include @@ -117,7 +117,9 @@ class packed_spinlock packed_spinlock(std::atomic& lock, int index) : bits_(lock), mask_(static_cast(1) << index) { - assert(index >= 0 && (mask_ != 0)); + XRPL_ASSERT( + index >= 0 && (mask_ != 0), + "ripple::packed_spinlock::packed_spinlock : valid index and mask"); } [[nodiscard]] bool diff --git a/include/xrpl/beast/asio/io_latency_probe.h b/include/xrpl/beast/asio/io_latency_probe.h index bbde13af687..ca3efcdb3f1 100644 --- a/include/xrpl/beast/asio/io_latency_probe.h +++ b/include/xrpl/beast/asio/io_latency_probe.h @@ -20,8 +20,10 @@ #ifndef BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED #define BEAST_ASIO_IO_LATENCY_PROBE_H_INCLUDED +#include #include #include + #include #include #include @@ -172,7 +174,10 @@ class io_latency_probe , m_repeat(repeat) , m_probe(probe) { - assert(m_probe); + XRPL_ASSERT( + m_probe, + "beast::io_latency_probe::sample_op::sample_op : non-null " + "probe input"); m_probe->addref(); } @@ -182,7 +187,10 @@ class io_latency_probe , m_repeat(from.m_repeat) , m_probe(from.m_probe) { - assert(m_probe); + XRPL_ASSERT( + m_probe, + "beast::io_latency_probe::sample_op::sample_op(sample_op&&) : " + "non-null probe input"); from.m_probe = nullptr; } diff --git a/include/xrpl/beast/clock/manual_clock.h b/include/xrpl/beast/clock/manual_clock.h index 97be8e79b90..32ff76bb073 100644 --- a/include/xrpl/beast/clock/manual_clock.h +++ b/include/xrpl/beast/clock/manual_clock.h @@ -21,7 +21,7 @@ #define BEAST_CHRONO_MANUAL_CLOCK_H_INCLUDED #include -#include +#include namespace beast { @@ -61,7 +61,9 @@ class manual_clock : public abstract_clock void set(time_point const& when) { - assert(!Clock::is_steady || when >= now_); + XRPL_ASSERT( + !Clock::is_steady || when >= now_, + "beast::manual_clock::set(time_point) : forward input"); now_ = when; } @@ -78,7 +80,9 @@ class manual_clock : public abstract_clock void advance(std::chrono::duration const& elapsed) { - assert(!Clock::is_steady || (now_ + elapsed) >= now_); + XRPL_ASSERT( + !Clock::is_steady || (now_ + elapsed) >= now_, + "beast::manual_clock::advance(duration) : forward input"); now_ += elapsed; } diff --git a/include/xrpl/beast/container/detail/aged_unordered_container.h b/include/xrpl/beast/container/detail/aged_unordered_container.h index 72e3334801b..abafc6b2c4c 100644 --- a/include/xrpl/beast/container/detail/aged_unordered_container.h +++ b/include/xrpl/beast/container/detail/aged_unordered_container.h @@ -1330,7 +1330,10 @@ class aged_unordered_container size_type bucket(Key const& k) const { - assert(bucket_count() != 0); + XRPL_ASSERT( + bucket_count() != 0, + "beast::detail::aged_unordered_container::bucket : nonzero bucket " + "count"); return m_cont.bucket(k, std::cref(m_config.hash_function())); } @@ -1471,7 +1474,10 @@ class aged_unordered_container { if (would_exceed(additional)) m_buck.resize(size() + additional, m_cont); - assert(load_factor() <= max_load_factor()); + XRPL_ASSERT( + load_factor() <= max_load_factor(), + "beast::detail::aged_unordered_container::maybe_rehash : maximum " + "load factor"); } // map, set diff --git a/include/xrpl/beast/core/LexicalCast.h b/include/xrpl/beast/core/LexicalCast.h index e0fa24ca9f5..b01fd8ae140 100644 --- a/include/xrpl/beast/core/LexicalCast.h +++ b/include/xrpl/beast/core/LexicalCast.h @@ -20,9 +20,10 @@ #ifndef BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED #define BEAST_MODULE_CORE_TEXT_LEXICALCAST_H_INCLUDED +#include + #include #include -#include #include #include #include @@ -159,7 +160,8 @@ struct LexicalCast bool operator()(Out& out, char const* in) const { - assert(in); + XRPL_ASSERT( + in, "beast::detail::LexicalCast(char const*) : non-null input"); return LexicalCast()(out, in); } }; @@ -174,7 +176,7 @@ struct LexicalCast bool operator()(Out& out, char* in) const { - assert(in); + XRPL_ASSERT(in, "beast::detail::LexicalCast(char*) : non-null input"); return LexicalCast()(out, in); } }; diff --git a/include/xrpl/beast/net/IPAddress.h b/include/xrpl/beast/net/IPAddress.h index f3a1a7348f2..cdac4abbd9c 100644 --- a/include/xrpl/beast/net/IPAddress.h +++ b/include/xrpl/beast/net/IPAddress.h @@ -24,9 +24,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -96,7 +96,7 @@ hash_append(Hasher& h, beast::IP::Address const& addr) noexcept else if (addr.is_v6()) hash_append(h, addr.to_v6().to_bytes()); else - assert(false); + UNREACHABLE("beast::hash_append : invalid address type"); } } // namespace beast diff --git a/include/xrpl/beast/net/IPAddressV6.h b/include/xrpl/beast/net/IPAddressV6.h index 74eb6b96d8e..83e4d6f8a32 100644 --- a/include/xrpl/beast/net/IPAddressV6.h +++ b/include/xrpl/beast/net/IPAddressV6.h @@ -20,8 +20,8 @@ #ifndef BEAST_NET_IPADDRESSV6_H_INCLUDED #define BEAST_NET_IPADDRESSV6_H_INCLUDED +#include #include -#include #include #include #include diff --git a/include/xrpl/beast/utility/Journal.h b/include/xrpl/beast/utility/Journal.h index 059355ccae7..908738a2be2 100644 --- a/include/xrpl/beast/utility/Journal.h +++ b/include/xrpl/beast/utility/Journal.h @@ -20,7 +20,7 @@ #ifndef BEAST_UTILITY_JOURNAL_H_INCLUDED #define BEAST_UTILITY_JOURNAL_H_INCLUDED -#include +#include #include namespace beast { @@ -205,7 +205,9 @@ class Journal */ Stream(Sink& sink, Severity level) : m_sink(sink), m_level(level) { - assert(m_level < severities::kDisabled); + XRPL_ASSERT( + m_level < severities::kDisabled, + "beast::Journal::Stream::Stream : maximum level"); } /** Construct or copy another Stream. */ diff --git a/include/xrpl/beast/utility/instrumentation.h b/include/xrpl/beast/utility/instrumentation.h new file mode 100644 index 00000000000..72c48959a04 --- /dev/null +++ b/include/xrpl/beast/utility/instrumentation.h @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +/* +This file is part of rippled: https://github.com/ripple/rippled +Copyright (c) 2024 Ripple Labs Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_UTILITY_INSTRUMENTATION_H_INCLUDED +#define BEAST_UTILITY_INSTRUMENTATION_H_INCLUDED + +#include + +#ifdef ENABLE_VOIDSTAR +#ifdef NDEBUG +#error "Antithesis instrumentation requires Debug build" +#endif +#include +#else +// Macros below are copied from antithesis_sdk.h and slightly simplified +// The duplication is because Visual Studio 2019 cannot compile that header +// even with the option -Zc:__cplusplus added. +#define ALWAYS(cond, message, ...) assert((message) && (cond)) +#define ALWAYS_OR_UNREACHABLE(cond, message, ...) assert((message) && (cond)) +#define SOMETIMES(cond, message, ...) +#define REACHABLE(message, ...) +#define UNREACHABLE(message, ...) assert((message) && false) +#endif + +#define XRPL_ASSERT ALWAYS_OR_UNREACHABLE + +// How to use the instrumentation macros: +// +// * XRPL_ASSERT if cond must be true but the line might not be reached during +// fuzzing. Same like `assert` in normal use. +// * ALWAYS if cond must be true _and_ the line must be reached during fuzzing. +// Same like `assert` in normal use. +// * REACHABLE if the line must be reached during fuzzing +// * SOMETIMES a hint for the fuzzer to try to make the cond true +// * UNREACHABLE if the line must not be reached (in fuzzing or in normal use). +// Same like `assert(false)` in normal use. +// +// NOTE: XRPL_ASSERT has similar semantics as C `assert` macro, with only minor +// differences: +// * XRPL_ASSERT must have an unique name (naming convention in CONTRIBUTING.md) +// * during fuzzing, the program will continue execution past failed XRPL_ASSERT +// +// We continue to use regular C `assert` inside unit tests and inside constexpr +// functions. +// +// NOTE: UNREACHABLE does *not* have the same semantics as std::unreachable. +// The program will continue execution past an UNREACHABLE in a Release build +// and during fuzzing (similar to failed XRPL_ASSERT). +// Also, the naming convention in UNREACHABLE is subtly different from other +// instrumentation macros - its name describes the condition which was _not_ +// meant to happen, while name in other macros describes the condition that is +// meant to happen (e.g. as in "assert that this happens"). + +#endif diff --git a/include/xrpl/beast/utility/rngfill.h b/include/xrpl/beast/utility/rngfill.h index 71f434bdaf9..93f11559cf8 100644 --- a/include/xrpl/beast/utility/rngfill.h +++ b/include/xrpl/beast/utility/rngfill.h @@ -20,8 +20,8 @@ #ifndef BEAST_RANDOM_RNGFILL_H_INCLUDED #define BEAST_RANDOM_RNGFILL_H_INCLUDED +#include #include -#include #include #include #include @@ -42,7 +42,8 @@ rngfill(void* buffer, std::size_t bytes, Generator& g) bytes -= sizeof(v); } - assert(bytes < sizeof(result_type)); + XRPL_ASSERT( + bytes < sizeof(result_type), "beast::rngfill(void*) : maximum bytes"); #ifdef __GNUC__ // gcc 11.1 (falsely) warns about an array-bounds overflow in release mode. diff --git a/include/xrpl/json/detail/json_assert.h b/include/xrpl/json/detail/json_assert.h index c401ccf7200..264bcd90f3d 100644 --- a/include/xrpl/json/detail/json_assert.h +++ b/include/xrpl/json/detail/json_assert.h @@ -22,9 +22,6 @@ #include -#define JSON_ASSERT_UNREACHABLE assert(false) -#define JSON_ASSERT(condition) \ - assert(condition); // @todo <= change this into an exception throw #define JSON_ASSERT_MESSAGE(condition, message) \ if (!(condition)) \ ripple::Throw(message); diff --git a/include/xrpl/protocol/AmountConversions.h b/include/xrpl/protocol/AmountConversions.h index 270d009b916..a65f7fcad8b 100644 --- a/include/xrpl/protocol/AmountConversions.h +++ b/include/xrpl/protocol/AmountConversions.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_AMOUNTCONVERSION_H_INCLUDED #define RIPPLE_PROTOCOL_AMOUNTCONVERSION_H_INCLUDED -#include -#include +#include #include +#include #include @@ -53,7 +53,9 @@ toSTAmount(XRPAmount const& xrp) inline STAmount toSTAmount(XRPAmount const& xrp, Issue const& iss) { - assert(isXRP(iss.account) && isXRP(iss.currency)); + XRPL_ASSERT( + isXRP(iss.account) && isXRP(iss.currency), + "ripple::toSTAmount : is XRP"); return toSTAmount(xrp); } @@ -72,12 +74,14 @@ template <> inline IOUAmount toAmount(STAmount const& amt) { - assert(amt.mantissa() < std::numeric_limits::max()); + XRPL_ASSERT( + amt.mantissa() < std::numeric_limits::max(), + "ripple::toAmount : maximum mantissa"); bool const isNeg = amt.negative(); std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); - assert(!isXRP(amt)); + XRPL_ASSERT(!isXRP(amt), "ripple::toAmount : is not XRP"); return IOUAmount(sMant, amt.exponent()); } @@ -85,12 +89,14 @@ template <> inline XRPAmount toAmount(STAmount const& amt) { - assert(amt.mantissa() < std::numeric_limits::max()); + XRPL_ASSERT( + amt.mantissa() < std::numeric_limits::max(), + "ripple::toAmount : maximum mantissa"); bool const isNeg = amt.negative(); std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); - assert(isXRP(amt)); + XRPL_ASSERT(isXRP(amt), "ripple::toAmount : is XRP"); return XRPAmount(sMant); } diff --git a/include/xrpl/protocol/Asset.h b/include/xrpl/protocol/Asset.h index 2cccc28bd41..0d12cd40580 100644 --- a/include/xrpl/protocol/Asset.h +++ b/include/xrpl/protocol/Asset.h @@ -26,10 +26,17 @@ namespace ripple { +class Asset; + template concept ValidIssueType = std::is_same_v || std::is_same_v; +template +concept AssetType = + std::is_convertible_v || std::is_convertible_v || + std::is_convertible_v || std::is_convertible_v; + /* Asset is an abstraction of three different issue types: XRP, IOU, MPT. * For historical reasons, two issue types XRP and IOU are wrapped in Issue * type. Many functions and classes there were first written for Issue @@ -37,8 +44,10 @@ concept ValidIssueType = */ class Asset { -private: +public: using value_type = std::variant; + +private: value_type issue_; public: @@ -92,8 +101,8 @@ class Asset friend constexpr bool operator==(Asset const& lhs, Asset const& rhs); - friend constexpr bool - operator!=(Asset const& lhs, Asset const& rhs); + friend constexpr std::weak_ordering + operator<=>(Asset const& lhs, Asset const& rhs); friend constexpr bool operator==(Currency const& lhs, Asset const& rhs); @@ -151,10 +160,22 @@ operator==(Asset const& lhs, Asset const& rhs) rhs.issue_); } -constexpr bool -operator!=(Asset const& lhs, Asset const& rhs) +constexpr std::weak_ordering +operator<=>(Asset const& lhs, Asset const& rhs) { - return !(lhs == rhs); + return std::visit( + []( + TLhs const& lhs_, TRhs const& rhs_) { + if constexpr (std::is_same_v) + return std::weak_ordering(lhs_ <=> rhs_); + else if constexpr ( + std::is_same_v && std::is_same_v) + return std::weak_ordering::greater; + else + return std::weak_ordering::less; + }, + lhs.issue_, + rhs.issue_); } constexpr bool diff --git a/include/xrpl/protocol/Feature.h b/include/xrpl/protocol/Feature.h index 90a81c55ef4..18a9b9498aa 100644 --- a/include/xrpl/protocol/Feature.h +++ b/include/xrpl/protocol/Feature.h @@ -151,14 +151,19 @@ class FeatureBitset : private std::bitset explicit FeatureBitset(base const& b) : base(b) { - assert(b.count() == count()); + XRPL_ASSERT( + b.count() == count(), + "ripple::FeatureBitset::FeatureBitset(base) : count match"); } template explicit FeatureBitset(uint256 const& f, Fs&&... fs) { initFromFeatures(f, std::forward(fs)...); - assert(count() == (sizeof...(fs) + 1)); + XRPL_ASSERT( + count() == (sizeof...(fs) + 1), + "ripple::FeatureBitset::FeatureBitset(uint256) : count and " + "sizeof... do match"); } template @@ -166,7 +171,10 @@ class FeatureBitset : private std::bitset { for (auto const& f : fs) set(featureToBitsetIndex(f)); - assert(fs.size() == count()); + XRPL_ASSERT( + fs.size() == count(), + "ripple::FeatureBitset::FeatureBitset(Container auto) : count and " + "size do match"); } auto diff --git a/include/xrpl/basics/FeeUnits.h b/include/xrpl/protocol/FeeUnits.h similarity index 96% rename from include/xrpl/basics/FeeUnits.h rename to include/xrpl/protocol/FeeUnits.h index c63a169f00e..640635c3fcb 100644 --- a/include/xrpl/basics/FeeUnits.h +++ b/include/xrpl/protocol/FeeUnits.h @@ -19,22 +19,29 @@ #ifndef BASICS_FEES_H_INCLUDED #define BASICS_FEES_H_INCLUDED -#include +#include +#include +#include +#include #include -#include -#include +#include -#include #include #include #include +#include +#include #include #include +#include namespace ripple { namespace feeunit { +/** "drops" are the smallest divisible amount of XRP. This is what most + of the code uses. */ +struct dropTag; /** "fee units" calculations are a not-really-unitless value that is used to express the cost of a given transaction vs. a reference transaction. They are primarily used by the Transactor classes. */ @@ -419,9 +426,13 @@ mulDivU(Source1 value, Dest mul, Source2 div) { // split the asserts so if one hits, the user can tell which // without a debugger. - assert(value.value() >= 0); - assert(mul.value() >= 0); - assert(div.value() >= 0); + XRPL_ASSERT( + value.value() >= 0, + "ripple::feeunit::mulDivU : minimum value input"); + XRPL_ASSERT( + mul.value() >= 0, "ripple::feeunit::mulDivU : minimum mul input"); + XRPL_ASSERT( + div.value() >= 0, "ripple::feeunit::mulDivU : minimum div input"); return std::nullopt; } diff --git a/include/xrpl/protocol/Fees.h b/include/xrpl/protocol/Fees.h index 7b4671a91d9..4393f1a1d9c 100644 --- a/include/xrpl/protocol/Fees.h +++ b/include/xrpl/protocol/Fees.h @@ -20,7 +20,7 @@ #ifndef RIPPLE_PROTOCOL_FEES_H_INCLUDED #define RIPPLE_PROTOCOL_FEES_H_INCLUDED -#include +#include namespace ripple { diff --git a/include/xrpl/basics/IOUAmount.h b/include/xrpl/protocol/IOUAmount.h similarity index 100% rename from include/xrpl/basics/IOUAmount.h rename to include/xrpl/protocol/IOUAmount.h diff --git a/include/xrpl/protocol/Indexes.h b/include/xrpl/protocol/Indexes.h index 72cf0b527b1..3ce6ef8e836 100644 --- a/include/xrpl/protocol/Indexes.h +++ b/include/xrpl/protocol/Indexes.h @@ -220,7 +220,8 @@ page(uint256 const& root, std::uint64_t index = 0) noexcept; inline Keylet page(Keylet const& root, std::uint64_t index = 0) noexcept { - assert(root.type == ltDIR_NODE); + XRPL_ASSERT( + root.type == ltDIR_NODE, "ripple::keylet::page : valid root type"); return page(root.key, index); } /** @} */ @@ -273,7 +274,7 @@ nft_sells(uint256 const& id) noexcept; /** AMM entry */ Keylet -amm(Issue const& issue1, Issue const& issue2) noexcept; +amm(Asset const& issue1, Asset const& issue2) noexcept; Keylet amm(uint256 const& amm) noexcept; diff --git a/include/xrpl/protocol/Issue.h b/include/xrpl/protocol/Issue.h index 335dd91354a..83ef337c357 100644 --- a/include/xrpl/protocol/Issue.h +++ b/include/xrpl/protocol/Issue.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_ISSUE_H_INCLUDED #define RIPPLE_PROTOCOL_ISSUE_H_INCLUDED +#include #include #include -#include #include #include @@ -58,6 +58,9 @@ class Issue bool native() const; + + friend constexpr std::weak_ordering + operator<=>(Issue const& lhs, Issue const& rhs); }; bool @@ -95,7 +98,7 @@ operator==(Issue const& lhs, Issue const& rhs) /** Strict weak ordering. */ /** @{ */ -[[nodiscard]] inline constexpr std::weak_ordering +[[nodiscard]] constexpr std::weak_ordering operator<=>(Issue const& lhs, Issue const& rhs) { if (auto const c{lhs.currency <=> rhs.currency}; c != 0) diff --git a/include/xrpl/protocol/LedgerHeader.h b/include/xrpl/protocol/LedgerHeader.h index 663eb709be2..0b35979971a 100644 --- a/include/xrpl/protocol/LedgerHeader.h +++ b/include/xrpl/protocol/LedgerHeader.h @@ -21,11 +21,11 @@ #define RIPPLE_PROTOCOL_LEDGERHEADER_H_INCLUDED #include -#include #include #include #include #include +#include namespace ripple { diff --git a/include/xrpl/basics/MPTAmount.h b/include/xrpl/protocol/MPTAmount.h similarity index 92% rename from include/xrpl/basics/MPTAmount.h rename to include/xrpl/protocol/MPTAmount.h index 34f747a21be..244d6839156 100644 --- a/include/xrpl/basics/MPTAmount.h +++ b/include/xrpl/protocol/MPTAmount.h @@ -17,9 +17,10 @@ */ //============================================================================== -#ifndef RIPPLE_BASICS_MPTAMOUNT_H_INCLUDED -#define RIPPLE_BASICS_MPTAMOUNT_H_INCLUDED +#ifndef RIPPLE_PROTOCOL_MPTAMOUNT_H_INCLUDED +#define RIPPLE_PROTOCOL_MPTAMOUNT_H_INCLUDED +#include #include #include #include @@ -52,6 +53,11 @@ class MPTAmount : private boost::totally_ordered, constexpr MPTAmount& operator=(MPTAmount const& other) = default; + // Round to nearest, even on tie. + explicit MPTAmount(Number const& x) : MPTAmount(static_cast(x)) + { + } + constexpr explicit MPTAmount(value_type value); constexpr MPTAmount& operator=(beast::Zero); @@ -78,6 +84,11 @@ class MPTAmount : private boost::totally_ordered, explicit constexpr operator bool() const noexcept; + operator Number() const noexcept + { + return value(); + } + /** Return the sign of the amount */ constexpr int signum() const noexcept; diff --git a/include/xrpl/protocol/MPTIssue.h b/include/xrpl/protocol/MPTIssue.h index 06f55686caf..028051ab1ae 100644 --- a/include/xrpl/protocol/MPTIssue.h +++ b/include/xrpl/protocol/MPTIssue.h @@ -54,8 +54,8 @@ class MPTIssue friend constexpr bool operator==(MPTIssue const& lhs, MPTIssue const& rhs); - friend constexpr bool - operator!=(MPTIssue const& lhs, MPTIssue const& rhs); + friend constexpr std::weak_ordering + operator<=>(MPTIssue const& lhs, MPTIssue const& rhs); bool native() const @@ -70,10 +70,10 @@ operator==(MPTIssue const& lhs, MPTIssue const& rhs) return lhs.mptID_ == rhs.mptID_; } -constexpr bool -operator!=(MPTIssue const& lhs, MPTIssue const& rhs) +constexpr std::weak_ordering +operator<=>(MPTIssue const& lhs, MPTIssue const& rhs) { - return !(lhs == rhs); + return lhs.mptID_ <=> rhs.mptID_; } /** MPT is a non-native token. diff --git a/include/xrpl/protocol/MultiApiJson.h b/include/xrpl/protocol/MultiApiJson.h index 73c274ff7f7..03bab9b32ea 100644 --- a/include/xrpl/protocol/MultiApiJson.h +++ b/include/xrpl/protocol/MultiApiJson.h @@ -23,8 +23,8 @@ #include #include +#include #include -#include #include #include #include @@ -159,8 +159,10 @@ struct MultiApiJson -> std:: invoke_result_t { - assert( - valid(version) && index(version) >= 0 && index(version) < size); + XRPL_ASSERT( + valid(version) && index(version) >= 0 && index(version) < size, + "ripple::detail::MultiApiJson::operator() : valid " + "version"); return std::invoke( fn, json.val[index(version)], @@ -177,8 +179,9 @@ struct MultiApiJson operator()(Json& json, Version version, Fn fn) const -> std::invoke_result_t { - assert( - valid(version) && index(version) >= 0 && index(version) < size); + XRPL_ASSERT( + valid(version) && index(version) >= 0 && index(version) < size, + "ripple::detail::MultiApiJson::operator() : valid version"); return std::invoke(fn, json.val[index(version)]); } } visitor = {}; diff --git a/include/xrpl/protocol/PayChan.h b/include/xrpl/protocol/PayChan.h index 8344120ccd6..b552b591af2 100644 --- a/include/xrpl/protocol/PayChan.h +++ b/include/xrpl/protocol/PayChan.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_PAYCHAN_H_INCLUDED #define RIPPLE_PROTOCOL_PAYCHAN_H_INCLUDED -#include #include #include #include +#include namespace ripple { diff --git a/include/xrpl/protocol/Protocol.h b/include/xrpl/protocol/Protocol.h index a9bd10a6fd1..68134b4a5fe 100644 --- a/include/xrpl/protocol/Protocol.h +++ b/include/xrpl/protocol/Protocol.h @@ -22,6 +22,7 @@ #include #include +#include #include namespace ripple { diff --git a/include/xrpl/protocol/Quality.h b/include/xrpl/protocol/Quality.h index 1ee2cc9f686..6783fbf6dac 100644 --- a/include/xrpl/protocol/Quality.h +++ b/include/xrpl/protocol/Quality.h @@ -20,10 +20,10 @@ #ifndef RIPPLE_PROTOCOL_QUALITY_H_INCLUDED #define RIPPLE_PROTOCOL_QUALITY_H_INCLUDED -#include -#include #include +#include #include +#include #include #include @@ -298,7 +298,9 @@ class Quality friend double relativeDistance(Quality const& q1, Quality const& q2) { - assert(q1.m_value > 0 && q2.m_value > 0); + XRPL_ASSERT( + q1.m_value > 0 && q2.m_value > 0, + "ripple::Quality::relativeDistance : minimum inputs"); if (q1.m_value == q2.m_value) // make expected common case fast return 0; diff --git a/include/xrpl/protocol/Rate.h b/include/xrpl/protocol/Rate.h index 6970d9c16a8..2872a5809de 100644 --- a/include/xrpl/protocol/Rate.h +++ b/include/xrpl/protocol/Rate.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PROTOCOL_RATE_H_INCLUDED #define RIPPLE_PROTOCOL_RATE_H_INCLUDED +#include #include #include -#include #include #include diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h index 95cd35fead2..b86fb63b858 100644 --- a/include/xrpl/protocol/SOTemplate.h +++ b/include/xrpl/protocol/SOTemplate.h @@ -40,7 +40,7 @@ enum SOEStyle { }; /** Amount fields that can support MPT */ -enum SOETxMPTAmount { soeMPTNone, soeMPTSupported, soeMPTNotSupported }; +enum SOETxMPTIssue { soeMPTNone, soeMPTSupported, soeMPTNotSupported }; //------------------------------------------------------------------------------ @@ -50,7 +50,7 @@ class SOElement // Use std::reference_wrapper so SOElement can be stored in a std::vector. std::reference_wrapper sField_; SOEStyle style_; - SOETxMPTAmount supportMpt_ = soeMPTNone; + SOETxMPTIssue supportMpt_ = soeMPTNone; private: void @@ -72,10 +72,13 @@ class SOElement { init(fieldName); } + + template + requires(std::is_same_v || std::is_same_v) SOElement( - TypedField const& fieldName, + TypedField const& fieldName, SOEStyle style, - SOETxMPTAmount supportMpt = soeMPTNotSupported) + SOETxMPTIssue supportMpt = soeMPTNotSupported) : sField_(fieldName), style_(style), supportMpt_(supportMpt) { init(fieldName); @@ -93,7 +96,7 @@ class SOElement return style_; } - SOETxMPTAmount + SOETxMPTIssue supportMPT() const { return supportMpt_; diff --git a/include/xrpl/protocol/STAmount.h b/include/xrpl/protocol/STAmount.h index e0a6c1eca08..23e4c5e5b59 100644 --- a/include/xrpl/protocol/STAmount.h +++ b/include/xrpl/protocol/STAmount.h @@ -21,24 +21,21 @@ #define RIPPLE_PROTOCOL_STAMOUNT_H_INCLUDED #include -#include #include -#include #include -#include +#include #include +#include +#include +#include #include #include #include +#include #include namespace ripple { -template -concept AssetType = - std::is_same_v || std::is_convertible_v || - std::is_convertible_v || std::is_convertible_v; - // Internal form: // 1: If amount is zero, then value is zero and offset is -100 // 2: Otherwise: @@ -353,7 +350,10 @@ STAmount::STAmount( , mIsNegative(negative) { // mValue is uint64, but needs to fit in the range of int64 - assert(mValue <= std::numeric_limits::max()); + XRPL_ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(SField, A, std::uint64_t, int, bool) : " + "maximum mantissa input"); canonicalize(); } diff --git a/include/xrpl/protocol/STBitString.h b/include/xrpl/protocol/STBitString.h index f3a74f2fc54..bf4ce84a3f3 100644 --- a/include/xrpl/protocol/STBitString.h +++ b/include/xrpl/protocol/STBitString.h @@ -170,8 +170,11 @@ template void STBitString::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == getSType()); + XRPL_ASSERT( + getFName().isBinary(), "ripple::STBitString::add : field is binary"); + XRPL_ASSERT( + getFName().fieldType == getSType(), + "ripple::STBitString::add : field type match"); s.addBitString(value_); } diff --git a/include/xrpl/protocol/STBlob.h b/include/xrpl/protocol/STBlob.h index bdedbd92105..cfe4ab5af58 100644 --- a/include/xrpl/protocol/STBlob.h +++ b/include/xrpl/protocol/STBlob.h @@ -23,9 +23,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/include/xrpl/protocol/STInteger.h b/include/xrpl/protocol/STInteger.h index 6bae2cc3152..68e25be1c9f 100644 --- a/include/xrpl/protocol/STInteger.h +++ b/include/xrpl/protocol/STInteger.h @@ -110,8 +110,11 @@ template inline void STInteger::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == getSType()); + XRPL_ASSERT( + getFName().isBinary(), "ripple::STInteger::add : field is binary"); + XRPL_ASSERT( + getFName().fieldType == getSType(), + "ripple::STInteger::add : field type match"); s.addInteger(value_); } diff --git a/include/xrpl/protocol/STIssue.h b/include/xrpl/protocol/STIssue.h index a0dfbd4faec..08812c15aec 100644 --- a/include/xrpl/protocol/STIssue.h +++ b/include/xrpl/protocol/STIssue.h @@ -21,7 +21,7 @@ #define RIPPLE_PROTOCOL_STISSUE_H_INCLUDED #include -#include +#include #include #include #include @@ -31,31 +31,40 @@ namespace ripple { class STIssue final : public STBase, CountedObject { private: - Issue issue_{xrpIssue()}; + Asset asset_{xrpIssue()}; public: - using value_type = Issue; + using value_type = Asset; STIssue() = default; explicit STIssue(SerialIter& sit, SField const& name); - explicit STIssue(SField const& name, Issue const& issue); + template + explicit STIssue(SField const& name, A const& issue); explicit STIssue(SField const& name); - Issue const& - issue() const; + template + TIss const& + get() const; - Issue const& + template + bool + holds() const; + + value_type const& value() const noexcept; void - setIssue(Issue const& issue); + setIssue(Asset const& issue); SerializedTypeID getSType() const override; + std::string + getText() const override; + Json::Value getJson(JsonOptions) const override; void @@ -67,6 +76,18 @@ class STIssue final : public STBase, CountedObject bool isDefault() const override; + friend constexpr bool + operator==(STIssue const& lhs, STIssue const& rhs); + + friend constexpr std::weak_ordering + operator<=>(STIssue const& lhs, STIssue const& rhs); + + friend constexpr bool + operator==(STIssue const& lhs, Asset const& rhs); + + friend constexpr std::weak_ordering + operator<=>(STIssue const& lhs, Asset const& rhs); + private: STBase* copy(std::size_t n, void* buf) const override; @@ -76,59 +97,72 @@ class STIssue final : public STBase, CountedObject friend class detail::STVar; }; +template +STIssue::STIssue(SField const& name, A const& asset) + : STBase{name}, asset_{asset} +{ + if (holds() && !isConsistent(asset_.get())) + Throw( + "Invalid asset: currency and account native mismatch"); +} + STIssue issueFromJson(SField const& name, Json::Value const& v); -inline Issue const& -STIssue::issue() const +template +bool +STIssue::holds() const +{ + return asset_.holds(); +} + +template +TIss const& +STIssue::get() const { - return issue_; + if (!holds(asset_)) + Throw("Asset doesn't hold the requested issue"); + return std::get(asset_); } -inline Issue const& +inline STIssue::value_type const& STIssue::value() const noexcept { - return issue_; + return asset_; } inline void -STIssue::setIssue(Issue const& issue) +STIssue::setIssue(Asset const& asset) { - if (isXRP(issue_.currency) != isXRP(issue_.account)) + if (holds() && !isConsistent(asset_.get())) Throw( - "invalid issue: currency and account native mismatch"); + "Invalid asset: currency and account native mismatch"); - issue_ = issue; + asset_ = asset; } -inline bool +constexpr bool operator==(STIssue const& lhs, STIssue const& rhs) { - return lhs.issue() == rhs.issue(); -} - -inline bool -operator!=(STIssue const& lhs, STIssue const& rhs) -{ - return !operator==(lhs, rhs); + return lhs.asset_ == rhs.asset_; } -inline bool -operator<(STIssue const& lhs, STIssue const& rhs) +constexpr std::weak_ordering +operator<=>(STIssue const& lhs, STIssue const& rhs) { - return lhs.issue() < rhs.issue(); + return lhs.asset_ <=> rhs.asset_; } -inline bool -operator==(STIssue const& lhs, Issue const& rhs) +constexpr bool +operator==(STIssue const& lhs, Asset const& rhs) { - return lhs.issue() == rhs; + return lhs.asset_ == rhs; } -inline bool -operator<(STIssue const& lhs, Issue const& rhs) +constexpr std::weak_ordering +operator<=>(STIssue const& lhs, Asset const& rhs) { - return lhs.issue() < rhs; + return lhs.asset_ <=> rhs; } } // namespace ripple diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index 748a2b5d685..4c8db2e01e4 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -21,10 +21,11 @@ #define RIPPLE_PROTOCOL_STOBJECT_H_INCLUDED #include -#include #include #include #include +#include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -737,7 +737,7 @@ STObject::Proxy::assign(U&& u) t = dynamic_cast(st_->getPField(*f_, true)); else t = dynamic_cast(st_->makeFieldPresent(*f_)); - assert(t); + XRPL_ASSERT(t, "ripple::STObject::Proxy::assign : type cast succeeded"); *t = std::forward(u); } @@ -1033,13 +1033,19 @@ STObject::at(TypedField const& f) const if (auto const u = dynamic_cast(b)) return u->value(); - assert(mType); - assert(b->getSType() == STI_NOTPRESENT); + XRPL_ASSERT( + mType, + "ripple::STObject::at(TypedField auto) : field template non-null"); + XRPL_ASSERT( + b->getSType() == STI_NOTPRESENT, + "ripple::STObject::at(TypedField auto) : type not present"); if (mType->style(f) == soeOPTIONAL) Throw("Missing optional field: " + f.getName()); - assert(mType->style(f) == soeDEFAULT); + XRPL_ASSERT( + mType->style(f) == soeDEFAULT, + "ripple::STObject::at(TypedField auto) : template style is default"); // Used to help handle the case where value_type is a const reference, // otherwise we would return the address of a temporary. @@ -1057,11 +1063,19 @@ STObject::at(OptionaledField const& of) const auto const u = dynamic_cast(b); if (!u) { - assert(mType); - assert(b->getSType() == STI_NOTPRESENT); + XRPL_ASSERT( + mType, + "ripple::STObject::at(OptionaledField auto) : field template " + "non-null"); + XRPL_ASSERT( + b->getSType() == STI_NOTPRESENT, + "ripple::STObject::at(OptionaledField auto) : type not present"); if (mType->style(*of.f) == soeOPTIONAL) return std::nullopt; - assert(mType->style(*of.f) == soeDEFAULT); + XRPL_ASSERT( + mType->style(*of.f) == soeDEFAULT, + "ripple::STObject::at(OptionaledField auto) : template style is " + "default"); return typename T::value_type{}; } return u->value(); diff --git a/include/xrpl/protocol/STPathSet.h b/include/xrpl/protocol/STPathSet.h index 473086368fb..953a209c150 100644 --- a/include/xrpl/protocol/STPathSet.h +++ b/include/xrpl/protocol/STPathSet.h @@ -21,11 +21,11 @@ #define RIPPLE_PROTOCOL_STPATHSET_H_INCLUDED #include +#include #include #include #include #include -#include #include #include @@ -257,7 +257,9 @@ inline STPathElement::STPathElement( is_offer_ = false; mAccountID = *account; mType |= typeAccount; - assert(mAccountID != noAccount()); + XRPL_ASSERT( + mAccountID != noAccount(), + "ripple::STPathElement::STPathElement : account is set"); } if (currency) @@ -270,7 +272,9 @@ inline STPathElement::STPathElement( { mIssuerID = *issuer; mType |= typeIssuer; - assert(mIssuerID != noAccount()); + XRPL_ASSERT( + mIssuerID != noAccount(), + "ripple::STPathElement::STPathElement : issuer is set"); } hash_value_ = get_hash(*this); diff --git a/include/xrpl/protocol/STValidation.h b/include/xrpl/protocol/STValidation.h index 6cae0971f51..32c60026fcd 100644 --- a/include/xrpl/protocol/STValidation.h +++ b/include/xrpl/protocol/STValidation.h @@ -20,12 +20,12 @@ #ifndef RIPPLE_PROTOCOL_STVALIDATION_H_INCLUDED #define RIPPLE_PROTOCOL_STVALIDATION_H_INCLUDED -#include #include +#include +#include #include #include #include -#include #include #include #include @@ -176,7 +176,9 @@ STValidation::STValidation( Throw("Invalid signature in validation"); } - assert(nodeID_.isNonZero()); + XRPL_ASSERT( + nodeID_.isNonZero(), + "ripple::STValidation::STValidation(SerialIter) : nonzero node"); } /** Construct, sign and trust a new STValidation issued by this node. @@ -199,7 +201,10 @@ STValidation::STValidation( , nodeID_(nodeID) , seenTime_(signTime) { - assert(nodeID_.isNonZero()); + XRPL_ASSERT( + nodeID_.isNonZero(), + "ripple::STValidation::STValidation(PublicKey, SecretKey) : nonzero " + "node"); // First, set our own public key: if (publicKeyType(pk) != KeyType::secp256k1) diff --git a/include/xrpl/protocol/STXChainBridge.h b/include/xrpl/protocol/STXChainBridge.h index 38db1912c70..813bcc44437 100644 --- a/include/xrpl/protocol/STXChainBridge.h +++ b/include/xrpl/protocol/STXChainBridge.h @@ -170,7 +170,7 @@ STXChainBridge::lockingChainDoor() const inline Issue const& STXChainBridge::lockingChainIssue() const { - return lockingChainIssue_.value(); + return lockingChainIssue_.value().get(); }; inline AccountID const& @@ -182,7 +182,7 @@ STXChainBridge::issuingChainDoor() const inline Issue const& STXChainBridge::issuingChainIssue() const { - return issuingChainIssue_.value(); + return issuingChainIssue_.value().get(); }; inline STXChainBridge::value_type const& diff --git a/include/xrpl/protocol/Serializer.h b/include/xrpl/protocol/Serializer.h index 0e96078ed14..80829c80003 100644 --- a/include/xrpl/protocol/Serializer.h +++ b/include/xrpl/protocol/Serializer.h @@ -27,9 +27,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -55,7 +55,9 @@ class Serializer if (size) { - assert(data != nullptr); + XRPL_ASSERT( + data, + "ripple::Serializer::Serializer(void const*) : non-null input"); std::memcpy(mData.data(), data, size); } } @@ -331,7 +333,8 @@ Serializer::addVL(Iter begin, Iter end, int len) len -= begin->size(); #endif } - assert(len == 0); + XRPL_ASSERT( + len == 0, "ripple::Serializer::addVL : length matches distance"); return ret; } diff --git a/include/xrpl/protocol/SystemParameters.h b/include/xrpl/protocol/SystemParameters.h index 7531a0d5fb9..af492340545 100644 --- a/include/xrpl/protocol/SystemParameters.h +++ b/include/xrpl/protocol/SystemParameters.h @@ -20,8 +20,8 @@ #ifndef RIPPLE_PROTOCOL_SYSTEMPARAMETERS_H_INCLUDED #define RIPPLE_PROTOCOL_SYSTEMPARAMETERS_H_INCLUDED -#include #include +#include #include #include diff --git a/include/xrpl/protocol/TxMeta.h b/include/xrpl/protocol/TxMeta.h index 7932a4c55a3..44ec8ae93fd 100644 --- a/include/xrpl/protocol/TxMeta.h +++ b/include/xrpl/protocol/TxMeta.h @@ -116,7 +116,9 @@ class TxMeta STAmount getDeliveredAmount() const { - assert(hasDeliveredAmount()); + XRPL_ASSERT( + hasDeliveredAmount(), + "ripple::TxMeta::getDeliveredAmount : non-null delivered amount"); return *mDelivered; } diff --git a/include/xrpl/basics/XRPAmount.h b/include/xrpl/protocol/XRPAmount.h similarity index 95% rename from include/xrpl/basics/XRPAmount.h rename to include/xrpl/protocol/XRPAmount.h index 30b194845c9..1d6cae9ecf2 100644 --- a/include/xrpl/basics/XRPAmount.h +++ b/include/xrpl/protocol/XRPAmount.h @@ -17,13 +17,14 @@ */ //============================================================================== -#ifndef RIPPLE_BASICS_XRPAMOUNT_H_INCLUDED -#define RIPPLE_BASICS_XRPAMOUNT_H_INCLUDED +#ifndef RIPPLE_PROTOCOL_XRPAMOUNT_H_INCLUDED +#define RIPPLE_PROTOCOL_XRPAMOUNT_H_INCLUDED +#include #include -#include #include #include +#include #include #include @@ -35,14 +36,6 @@ namespace ripple { -namespace feeunit { - -/** "drops" are the smallest divisible amount of XRP. This is what most - of the code uses. */ -struct dropTag; - -} // namespace feeunit - class XRPAmount : private boost::totally_ordered, private boost::additive, private boost::equality_comparable, @@ -61,6 +54,11 @@ class XRPAmount : private boost::totally_ordered, constexpr XRPAmount& operator=(XRPAmount const& other) = default; + // Round to nearest, even on tie. + explicit XRPAmount(Number const& x) : XRPAmount(static_cast(x)) + { + } + constexpr XRPAmount(beast::Zero) : drops_(0) { } @@ -162,6 +160,11 @@ class XRPAmount : private boost::totally_ordered, return drops_ != 0; } + operator Number() const noexcept + { + return drops(); + } + /** Return the sign of the amount */ constexpr int signum() const noexcept diff --git a/include/xrpl/protocol/detail/b58_utils.h b/include/xrpl/protocol/detail/b58_utils.h index b060fc7e166..8fc85f390b0 100644 --- a/include/xrpl/protocol/detail/b58_utils.h +++ b/include/xrpl/protocol/detail/b58_utils.h @@ -21,12 +21,12 @@ #define RIPPLE_PROTOCOL_B58_UTILS_H_INCLUDED #include +#include #include #include #include -#include #include #include #include @@ -130,7 +130,9 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) { // should never happen, but if it does then it seems natural to define // the a null set of numbers to be zero, so the remainder is also zero. - assert(0); + UNREACHABLE( + "ripple::b58_fast::detail::inplace_bigint_div_rem : empty " + "numerator"); return 0; } @@ -146,8 +148,14 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) unsigned __int128 const denom128 = denom; unsigned __int128 const d = num / denom128; unsigned __int128 const r = num - (denom128 * d); - assert(d >> 64 == 0); - assert(r >> 64 == 0); + XRPL_ASSERT( + d >> 64 == 0, + "ripple::b58_fast::detail::inplace_bigint_div_rem::div_rem_64 : " + "valid division result"); + XRPL_ASSERT( + r >> 64 == 0, + "ripple::b58_fast::detail::inplace_bigint_div_rem::div_rem_64 : " + "valid remainder"); return {static_cast(d), static_cast(r)}; }; @@ -169,8 +177,11 @@ inplace_bigint_div_rem(std::span numerator, std::uint64_t divisor) [[nodiscard]] inline std::array b58_10_to_b58_be(std::uint64_t input) { - constexpr std::uint64_t B_58_10 = 430804206899405824; // 58^10; - assert(input < B_58_10); + [[maybe_unused]] static constexpr std::uint64_t B_58_10 = + 430804206899405824; // 58^10; + XRPL_ASSERT( + input < B_58_10, + "ripple::b58_fast::detail::b58_10_to_b58_be : valid input"); constexpr std::size_t resultSize = 10; std::array result{}; int i = 0; diff --git a/include/xrpl/resource/detail/Entry.h b/include/xrpl/resource/detail/Entry.h index d4f32080d9d..32ba77c6d35 100644 --- a/include/xrpl/resource/detail/Entry.h +++ b/include/xrpl/resource/detail/Entry.h @@ -23,9 +23,9 @@ #include #include #include +#include #include #include -#include namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/detail/Key.h b/include/xrpl/resource/detail/Key.h index 3df2dce039d..f953d5103eb 100644 --- a/include/xrpl/resource/detail/Key.h +++ b/include/xrpl/resource/detail/Key.h @@ -21,8 +21,8 @@ #define RIPPLE_RESOURCE_KEY_H_INCLUDED #include +#include #include -#include namespace ripple { namespace Resource { diff --git a/include/xrpl/resource/detail/Logic.h b/include/xrpl/resource/detail/Logic.h index a57e529e0a2..b6c776d1aff 100644 --- a/include/xrpl/resource/detail/Logic.h +++ b/include/xrpl/resource/detail/Logic.h @@ -26,12 +26,12 @@ #include #include #include +#include #include #include #include #include #include -#include #include namespace ripple { @@ -401,7 +401,9 @@ class Logic { std::lock_guard _(lock_); Entry& entry(iter->second); - assert(entry.refcount == 0); + XRPL_ASSERT( + entry.refcount == 0, + "ripple::Resource::Logic::erase : entry not used"); inactive_.erase(inactive_.iterator_to(entry)); table_.erase(iter); } @@ -433,7 +435,9 @@ class Logic admin_.erase(admin_.iterator_to(entry)); break; default: - assert(false); + UNREACHABLE( + "ripple::Resource::Logic::release : invalid entry " + "kind"); break; } inactive_.push_back(entry); diff --git a/include/xrpl/server/detail/BaseHTTPPeer.h b/include/xrpl/server/detail/BaseHTTPPeer.h index 32ec4d3009d..bcdddcc711d 100644 --- a/include/xrpl/server/detail/BaseHTTPPeer.h +++ b/include/xrpl/server/detail/BaseHTTPPeer.h @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include #include diff --git a/include/xrpl/server/detail/BasePeer.h b/include/xrpl/server/detail/BasePeer.h index a90eaabf6e4..97ad77f7f22 100644 --- a/include/xrpl/server/detail/BasePeer.h +++ b/include/xrpl/server/detail/BasePeer.h @@ -21,12 +21,12 @@ #define RIPPLE_SERVER_BASEPEER_H_INCLUDED #include +#include #include #include #include #include #include -#include #include #include diff --git a/include/xrpl/server/detail/BaseWSPeer.h b/include/xrpl/server/detail/BaseWSPeer.h index 4c4049a8b9b..027b0cbf7ca 100644 --- a/include/xrpl/server/detail/BaseWSPeer.h +++ b/include/xrpl/server/detail/BaseWSPeer.h @@ -21,17 +21,21 @@ #define RIPPLE_SERVER_BASEWSPEER_H_INCLUDED #include +#include #include #include #include +#include #include #include + #include #include #include +#include -#include #include +#include namespace ripple { @@ -508,7 +512,9 @@ template void BaseWSPeer::fail(error_code ec, String const& what) { - assert(strand_.running_in_this_thread()); + XRPL_ASSERT( + strand_.running_in_this_thread(), + "ripple::BaseWSPeer::fail : strand in this thread"); cancel_timer(); if (!ec_ && ec != boost::asio::error::operation_aborted) diff --git a/src/libxrpl/basics/Log.cpp b/src/libxrpl/basics/Log.cpp index 3d5963cc266..873087bd217 100644 --- a/src/libxrpl/basics/Log.cpp +++ b/src/libxrpl/basics/Log.cpp @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -224,7 +224,7 @@ Logs::fromSeverity(beast::severities::Severity level) return lsERROR; default: - assert(false); + UNREACHABLE("ripple::Logs::fromSeverity : invalid severity"); [[fallthrough]]; case kFatal: break; @@ -250,7 +250,7 @@ Logs::toSeverity(LogSeverity level) case lsERROR: return kError; default: - assert(false); + UNREACHABLE("ripple::Logs::toSeverity : invalid severity"); [[fallthrough]]; case lsFATAL: break; @@ -277,7 +277,7 @@ Logs::toString(LogSeverity s) case lsFATAL: return "Fatal"; default: - assert(false); + UNREACHABLE("ripple::Logs::toString : invalid severity"); return "Unknown"; } } @@ -341,7 +341,7 @@ Logs::format( output += "ERR "; break; default: - assert(false); + UNREACHABLE("ripple::Logs::format : invalid severity"); [[fallthrough]]; case kFatal: output += "FTL "; diff --git a/src/libxrpl/basics/Number.cpp b/src/libxrpl/basics/Number.cpp index ebbfa0023c9..3bc58970ef7 100644 --- a/src/libxrpl/basics/Number.cpp +++ b/src/libxrpl/basics/Number.cpp @@ -18,9 +18,9 @@ //============================================================================== #include +#include #include #include -#include #include #include #include @@ -235,7 +235,9 @@ Number::operator+=(Number const& y) *this = Number{}; return *this; } - assert(isnormal() && y.isnormal()); + XRPL_ASSERT( + isnormal() && y.isnormal(), + "ripple::Number::operator+=(Number) : is normal"); auto xm = mantissa(); auto xe = exponent(); int xn = 1; @@ -374,7 +376,9 @@ Number::operator*=(Number const& y) *this = y; return *this; } - assert(isnormal() && y.isnormal()); + XRPL_ASSERT( + isnormal() && y.isnormal(), + "ripple::Number::operator*=(Number) : is normal"); auto xm = mantissa(); auto xe = exponent(); int xn = 1; @@ -428,7 +432,9 @@ Number::operator*=(Number const& y) std::to_string(xe)); mantissa_ = xm * zn; exponent_ = xe; - assert(isnormal() || *this == Number{}); + XRPL_ASSERT( + isnormal() || *this == Number{}, + "ripple::Number::operator*=(Number) : result is normal"); return *this; } @@ -499,16 +505,6 @@ Number::operator rep() const return drops; } -Number::operator XRPAmount() const -{ - return XRPAmount{static_cast(*this)}; -} - -Number::operator MPTAmount() const -{ - return MPTAmount{static_cast(*this)}; -} - std::string to_string(Number const& amount) { @@ -536,7 +532,8 @@ to_string(Number const& amount) negative = true; } - assert(exponent + 43 > 0); + XRPL_ASSERT( + exponent + 43 > 0, "ripple::to_string(Number) : minimum exponent"); ptrdiff_t const pad_prefix = 27; ptrdiff_t const pad_suffix = 23; @@ -562,7 +559,9 @@ to_string(Number const& amount) if (std::distance(pre_from, pre_to) > pad_prefix) pre_from += pad_prefix; - assert(post_to >= post_from); + XRPL_ASSERT( + post_to >= post_from, + "ripple::to_string(Number) : first distance check"); pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; }); @@ -571,7 +570,9 @@ to_string(Number const& amount) if (std::distance(post_from, post_to) > pad_suffix) post_to -= pad_suffix; - assert(post_to >= post_from); + XRPL_ASSERT( + post_to >= post_from, + "ripple::to_string(Number) : second distance check"); post_to = std::find_if( std::make_reverse_iterator(post_to), diff --git a/src/libxrpl/basics/ResolverAsio.cpp b/src/libxrpl/basics/ResolverAsio.cpp index 7105eb12a74..8951d809dec 100644 --- a/src/libxrpl/basics/ResolverAsio.cpp +++ b/src/libxrpl/basics/ResolverAsio.cpp @@ -21,9 +21,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -48,7 +48,9 @@ class AsyncObject ~AsyncObject() { // Destroying the object with I/O pending? Not a clean exit! - assert(m_pending.load() == 0); + XRPL_ASSERT( + m_pending.load() == 0, + "ripple::AsyncObject::~AsyncObject : nothing pending"); } /** RAII container that maintains the count of pending I/O. @@ -153,8 +155,11 @@ class ResolverAsioImpl : public ResolverAsio, ~ResolverAsioImpl() override { - assert(m_work.empty()); - assert(m_stopped); + XRPL_ASSERT( + m_work.empty(), + "ripple::ResolverAsioImpl::~ResolverAsioImpl : no pending work"); + XRPL_ASSERT( + m_stopped, "ripple::ResolverAsioImpl::~ResolverAsioImpl : stopped"); } //------------------------------------------------------------------------- @@ -176,8 +181,11 @@ class ResolverAsioImpl : public ResolverAsio, void start() override { - assert(m_stopped == true); - assert(m_stop_called == false); + XRPL_ASSERT( + m_stopped == true, "ripple::ResolverAsioImpl::start : stopped"); + XRPL_ASSERT( + m_stop_called == false, + "ripple::ResolverAsioImpl::start : not stopping"); if (m_stopped.exchange(false) == true) { @@ -217,8 +225,12 @@ class ResolverAsioImpl : public ResolverAsio, resolve(std::vector const& names, HandlerType const& handler) override { - assert(m_stop_called == false); - assert(!names.empty()); + XRPL_ASSERT( + m_stop_called == false, + "ripple::ResolverAsioImpl::resolve : not stopping"); + XRPL_ASSERT( + !names.empty(), + "ripple::ResolverAsioImpl::resolve : names non-empty"); // TODO NIKB use rvalue references to construct and move // reducing cost. @@ -235,7 +247,9 @@ class ResolverAsioImpl : public ResolverAsio, void do_stop(CompletionCounter) { - assert(m_stop_called == true); + XRPL_ASSERT( + m_stop_called == true, + "ripple::ResolverAsioImpl::do_stop : stopping"); if (m_stopped.exchange(true) == false) { @@ -381,7 +395,9 @@ class ResolverAsioImpl : public ResolverAsio, HandlerType const& handler, CompletionCounter) { - assert(!names.empty()); + XRPL_ASSERT( + !names.empty(), + "ripple::ResolverAsioImpl::do_resolve : names non-empty"); if (m_stop_called == false) { diff --git a/src/libxrpl/basics/contract.cpp b/src/libxrpl/basics/contract.cpp index fbda83c7a63..4f0a74644af 100644 --- a/src/libxrpl/basics/contract.cpp +++ b/src/libxrpl/basics/contract.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -48,6 +49,12 @@ LogicError(std::string const& s) noexcept { JLOG(debugLog().fatal()) << s; std::cerr << "Logic error: " << s << std::endl; + // Use a non-standard contract naming here (without namespace) because + // it's the only location where various unrelated execution paths may + // register an error; this is also why the "message" parameter is passed + // here. + // For the above reasons, we want this contract to stand out. + UNREACHABLE("LogicError", {{"message", s}}); detail::accessViolation(); } diff --git a/src/libxrpl/basics/partitioned_unordered_map.cpp b/src/libxrpl/basics/partitioned_unordered_map.cpp deleted file mode 100644 index a6d02cd2c6f..00000000000 --- a/src/libxrpl/basics/partitioned_unordered_map.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of rippled: https://github.com/ripple/rippled - Copyright (c) 2021 Ripple Labs Inc. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#include - -#include -#include -#include -#include -#include -#include - -namespace ripple { - -static std::size_t -extract(uint256 const& key) -{ - std::size_t result; - // Use memcpy to avoid unaligned UB - // (will optimize to equivalent code) - std::memcpy(&result, key.data(), sizeof(std::size_t)); - return result; -} - -static std::size_t -extract(SHAMapHash const& key) -{ - return *reinterpret_cast(key.as_uint256().data()); -} - -static std::size_t -extract(LedgerIndex key) -{ - return static_cast(key); -} - -static std::size_t -extract(std::string const& key) -{ - return ::beast::uhash<>{}(key); -} - -template -std::size_t -partitioner(Key const& key, std::size_t const numPartitions) -{ - return extract(key) % numPartitions; -} - -template std::size_t -partitioner( - LedgerIndex const& key, - std::size_t const numPartitions); - -template std::size_t -partitioner(uint256 const& key, std::size_t const numPartitions); - -template std::size_t -partitioner(SHAMapHash const& key, std::size_t const numPartitions); - -template std::size_t -partitioner( - std::string const& key, - std::size_t const numPartitions); - -} // namespace ripple diff --git a/src/libxrpl/beast/clock/basic_seconds_clock.cpp b/src/libxrpl/beast/clock/basic_seconds_clock.cpp index f5af8bd16ec..1407b67de9a 100644 --- a/src/libxrpl/beast/clock/basic_seconds_clock.cpp +++ b/src/libxrpl/beast/clock/basic_seconds_clock.cpp @@ -18,9 +18,9 @@ //============================================================================== #include +#include #include -#include #include #include #include @@ -57,7 +57,9 @@ static_assert(std::atomic::is_always_lock_free); seconds_clock_thread::~seconds_clock_thread() { - assert(thread_.joinable()); + XRPL_ASSERT( + thread_.joinable(), + "beast::seconds_clock_thread::~seconds_clock_thread : thread joinable"); { std::lock_guard lock(mut_); stop_ = true; diff --git a/src/libxrpl/beast/core/SemanticVersion.cpp b/src/libxrpl/beast/core/SemanticVersion.cpp index b33ed2f48f4..dfe699848d5 100644 --- a/src/libxrpl/beast/core/SemanticVersion.cpp +++ b/src/libxrpl/beast/core/SemanticVersion.cpp @@ -19,9 +19,9 @@ #include #include +#include #include -#include #include namespace beast { @@ -304,7 +304,8 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) if (isNumeric(left)) { - assert(isNumeric(right)); + XRPL_ASSERT( + isNumeric(right), "beast::compare : both inputs numeric"); int const iLeft(lexicalCastThrow(left)); int const iRight(lexicalCastThrow(right)); @@ -316,7 +317,9 @@ compare(SemanticVersion const& lhs, SemanticVersion const& rhs) } else { - assert(!isNumeric(right)); + XRPL_ASSERT( + !isNumeric(right), + "beast::compare : both inputs non-numeric"); int result = left.compare(right); diff --git a/src/libxrpl/beast/insight/StatsDCollector.cpp b/src/libxrpl/beast/insight/StatsDCollector.cpp index 76ae15b82d5..a9febbb3070 100644 --- a/src/libxrpl/beast/insight/StatsDCollector.cpp +++ b/src/libxrpl/beast/insight/StatsDCollector.cpp @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -400,7 +400,10 @@ class StatsDCollectorImp for (auto const& s : *keepAlive) { std::size_t const length(s.size()); - assert(!s.empty()); + XRPL_ASSERT( + !s.empty(), + "beast::insight::detail::StatsDCollectorImp::send_buffers : " + "non-empty payload"); if (!buffers.empty() && (size + length) > max_packet_size) { log(buffers); diff --git a/src/libxrpl/beast/utility/src/beast_Journal.cpp b/src/libxrpl/beast/utility/src/beast_Journal.cpp index 8ce7ea8d47c..449f474739c 100644 --- a/src/libxrpl/beast/utility/src/beast_Journal.cpp +++ b/src/libxrpl/beast/utility/src/beast_Journal.cpp @@ -18,7 +18,7 @@ //============================================================================== #include -#include +#include namespace beast { diff --git a/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp b/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp index 56e862ca8c0..3d68ea30cff 100644 --- a/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp +++ b/src/libxrpl/beast/utility/src/beast_PropertyStream.cpp @@ -18,8 +18,8 @@ //============================================================================== #include +#include #include -#include #include #include @@ -199,7 +199,9 @@ PropertyStream::Source::add(Source& source) std::lock_guard lk1(lock_, std::adopt_lock); std::lock_guard lk2(source.lock_, std::adopt_lock); - assert(source.parent_ == nullptr); + XRPL_ASSERT( + source.parent_ == nullptr, + "beast::PropertyStream::Source::add : null source parent"); children_.push_back(source.item_); source.parent_ = this; } @@ -211,7 +213,9 @@ PropertyStream::Source::remove(Source& child) std::lock_guard lk1(lock_, std::adopt_lock); std::lock_guard lk2(child.lock_, std::adopt_lock); - assert(child.parent_ == this); + XRPL_ASSERT( + child.parent_ == this, + "beast::PropertyStream::Source::remove : child parent match"); children_.erase(children_.iterator_to(child.item_)); child.parent_ = nullptr; } diff --git a/src/libxrpl/crypto/RFC1751.cpp b/src/libxrpl/crypto/RFC1751.cpp index 1c6f28287b0..952e246f5f8 100644 --- a/src/libxrpl/crypto/RFC1751.cpp +++ b/src/libxrpl/crypto/RFC1751.cpp @@ -17,10 +17,10 @@ */ //============================================================================== +#include #include #include #include -#include #include #include @@ -270,10 +270,12 @@ RFC1751::extract(char const* s, int start, int length) unsigned char cr; unsigned long x; - assert(length <= 11); - assert(start >= 0); - assert(length >= 0); - assert(start + length <= 66); + XRPL_ASSERT(length <= 11, "ripple::RFC1751::extract : maximum length"); + XRPL_ASSERT(start >= 0, "ripple::RFC1751::extract : minimum start"); + XRPL_ASSERT(length >= 0, "ripple::RFC1751::extract : minimum length"); + XRPL_ASSERT( + start + length <= 66, + "ripple::RFC1751::extract : maximum start + length"); int const shiftR = 24 - (length + (start % 8)); cl = s[start / 8]; // get components @@ -320,10 +322,12 @@ RFC1751::insert(char* s, int x, int start, int length) unsigned long y; int shift; - assert(length <= 11); - assert(start >= 0); - assert(length >= 0); - assert(start + length <= 66); + XRPL_ASSERT(length <= 11, "ripple::RFC1751::insert : maximum length"); + XRPL_ASSERT(start >= 0, "ripple::RFC1751::insert : minimum start"); + XRPL_ASSERT(length >= 0, "ripple::RFC1751::insert : minimum length"); + XRPL_ASSERT( + start + length <= 66, + "ripple::RFC1751::insert : maximum start + length"); shift = ((8 - ((start + length) % 8)) % 8); y = (long)x << shift; diff --git a/src/libxrpl/crypto/csprng.cpp b/src/libxrpl/crypto/csprng.cpp index 480d561eacf..948500734c0 100644 --- a/src/libxrpl/crypto/csprng.cpp +++ b/src/libxrpl/crypto/csprng.cpp @@ -18,9 +18,9 @@ //============================================================================== #include +#include #include #include -#include #include #include #include diff --git a/src/libxrpl/json/Object.cpp b/src/libxrpl/json/Object.cpp index 179b0e31ef2..f1f30af9a21 100644 --- a/src/libxrpl/json/Object.cpp +++ b/src/libxrpl/json/Object.cpp @@ -18,8 +18,8 @@ //============================================================================== #include +#include #include -#include namespace Json { @@ -168,7 +168,7 @@ Array::append(Json::Value const& v) return; } } - assert(false); // Can't get here. + UNREACHABLE("Json::Array::append : invalid type"); } void @@ -203,7 +203,7 @@ Object::set(std::string const& k, Json::Value const& v) return; } } - assert(false); // Can't get here. + UNREACHABLE("Json::Object::set : invalid type"); } //------------------------------------------------------------------------------ @@ -214,7 +214,7 @@ template void doCopyFrom(Object& to, Json::Value const& from) { - assert(from.isObjectOrNull()); + XRPL_ASSERT(from.isObjectOrNull(), "Json::doCopyFrom : valid input type"); auto members = from.getMemberNames(); for (auto& m : members) to[m] = from[m]; diff --git a/src/libxrpl/json/json_reader.cpp b/src/libxrpl/json/json_reader.cpp index 42488b3ec87..5f027e5189d 100644 --- a/src/libxrpl/json/json_reader.cpp +++ b/src/libxrpl/json/json_reader.cpp @@ -953,7 +953,7 @@ operator>>(std::istream& sin, Value& root) Json::Reader reader; bool ok = reader.parse(sin, root); - // JSON_ASSERT( ok ); + // XRPL_ASSERT(ok, "Json::operator>>() : parse succeeded"); if (!ok) ripple::Throw(reader.getFormatedErrorMessages()); diff --git a/src/libxrpl/json/json_value.cpp b/src/libxrpl/json/json_value.cpp index 155c3e1e044..90926afc6c4 100644 --- a/src/libxrpl/json/json_value.cpp +++ b/src/libxrpl/json/json_value.cpp @@ -207,7 +207,7 @@ Value::Value(ValueType type) : type_(type), allocated_(0) break; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::Value(ValueType) : invalid type"); } } @@ -277,7 +277,7 @@ Value::Value(const Value& other) : type_(other.type_) break; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::Value(Value const&) : invalid type"); } } @@ -305,7 +305,7 @@ Value::~Value() break; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::~Value : invalid type"); } } @@ -406,7 +406,7 @@ operator<(const Value& x, const Value& y) } default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::operator<(Value, Value) : invalid type"); } return 0; // unreachable @@ -452,7 +452,7 @@ operator==(const Value& x, const Value& y) *x.value_.map_ == *y.value_.map_; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::operator==(Value, Value) : invalid type"); } return 0; // unreachable @@ -461,7 +461,7 @@ operator==(const Value& x, const Value& y) const char* Value::asCString() const { - JSON_ASSERT(type_ == stringValue); + XRPL_ASSERT(type_ == stringValue, "Json::Value::asCString : valid type"); return value_.string_; } @@ -493,7 +493,7 @@ Value::asString() const JSON_ASSERT_MESSAGE(false, "Type is not convertible to string"); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asString : invalid type"); } return ""; // unreachable @@ -535,7 +535,7 @@ Value::asInt() const JSON_ASSERT_MESSAGE(false, "Type is not convertible to int"); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asInt : invalid type"); } return 0; // unreachable; @@ -577,7 +577,7 @@ Value::asUInt() const JSON_ASSERT_MESSAGE(false, "Type is not convertible to uint"); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asUInt : invalid type"); } return 0; // unreachable; @@ -609,7 +609,7 @@ Value::asDouble() const JSON_ASSERT_MESSAGE(false, "Type is not convertible to double"); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asDouble : invalid type"); } return 0; // unreachable; @@ -641,7 +641,7 @@ Value::asBool() const return value_.map_->size() != 0; default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::asBool : invalid type"); } return false; // unreachable; @@ -695,7 +695,7 @@ Value::isConvertibleTo(ValueType other) const (other == nullValue && value_.map_->size() == 0); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::isConvertible : invalid type"); } return false; // unreachable; @@ -729,7 +729,7 @@ Value::size() const return Int(value_.map_->size()); default: - JSON_ASSERT_UNREACHABLE; + UNREACHABLE("Json::Value::size : invalid type"); } return 0; // unreachable; @@ -752,8 +752,9 @@ Value::operator bool() const void Value::clear() { - JSON_ASSERT( - type_ == nullValue || type_ == arrayValue || type_ == objectValue); + XRPL_ASSERT( + type_ == nullValue || type_ == arrayValue || type_ == objectValue, + "Json::Value::clear : valid type"); switch (type_) { @@ -770,7 +771,9 @@ Value::clear() Value& Value::operator[](UInt index) { - JSON_ASSERT(type_ == nullValue || type_ == arrayValue); + XRPL_ASSERT( + type_ == nullValue || type_ == arrayValue, + "Json::Value::operator[](UInt) : valid type"); if (type_ == nullValue) *this = Value(arrayValue); @@ -789,7 +792,9 @@ Value::operator[](UInt index) const Value& Value::operator[](UInt index) const { - JSON_ASSERT(type_ == nullValue || type_ == arrayValue); + XRPL_ASSERT( + type_ == nullValue || type_ == arrayValue, + "Json::Value::operator[](UInt) const : valid type"); if (type_ == nullValue) return null; @@ -812,7 +817,9 @@ Value::operator[](const char* key) Value& Value::resolveReference(const char* key, bool isStatic) { - JSON_ASSERT(type_ == nullValue || type_ == objectValue); + XRPL_ASSERT( + type_ == nullValue || type_ == objectValue, + "Json::Value::resolveReference : valid type"); if (type_ == nullValue) *this = Value(objectValue); @@ -846,7 +853,9 @@ Value::isValidIndex(UInt index) const const Value& Value::operator[](const char* key) const { - JSON_ASSERT(type_ == nullValue || type_ == objectValue); + XRPL_ASSERT( + type_ == nullValue || type_ == objectValue, + "Json::Value::operator[](const char*) const : valid type"); if (type_ == nullValue) return null; @@ -906,7 +915,9 @@ Value::get(std::string const& key, const Value& defaultValue) const Value Value::removeMember(const char* key) { - JSON_ASSERT(type_ == nullValue || type_ == objectValue); + XRPL_ASSERT( + type_ == nullValue || type_ == objectValue, + "Json::Value::removeMember : valid type"); if (type_ == nullValue) return null; @@ -947,7 +958,9 @@ Value::isMember(std::string const& key) const Value::Members Value::getMemberNames() const { - JSON_ASSERT(type_ == nullValue || type_ == objectValue); + XRPL_ASSERT( + type_ == nullValue || type_ == objectValue, + "Json::Value::getMemberNames : valid type"); if (type_ == nullValue) return Value::Members(); diff --git a/src/libxrpl/json/json_writer.cpp b/src/libxrpl/json/json_writer.cpp index 5459042cddb..de0ed5848af 100644 --- a/src/libxrpl/json/json_writer.cpp +++ b/src/libxrpl/json/json_writer.cpp @@ -17,8 +17,8 @@ */ //============================================================================== +#include #include -#include #include #include #include @@ -70,7 +70,7 @@ valueToString(Int value) if (isNegative) *--current = '-'; - assert(current >= buffer); + XRPL_ASSERT(current >= buffer, "Json::valueToString(Int) : buffer check"); return current; } @@ -80,7 +80,7 @@ valueToString(UInt value) char buffer[32]; char* current = buffer + sizeof(buffer); uintToString(value, current); - assert(current >= buffer); + XRPL_ASSERT(current >= buffer, "Json::valueToString(UInt) : buffer check"); return current; } @@ -391,7 +391,9 @@ StyledWriter::writeArrayValue(const Value& value) } else // output on a single line { - assert(childValues_.size() == size); + XRPL_ASSERT( + childValues_.size() == size, + "Json::StyledWriter::writeArrayValue : child size match"); document_ += "[ "; for (unsigned index = 0; index < size; ++index) @@ -483,7 +485,9 @@ StyledWriter::indent() void StyledWriter::unindent() { - assert(int(indentString_.size()) >= indentSize_); + XRPL_ASSERT( + int(indentString_.size()) >= indentSize_, + "Json::StyledWriter::unindent : maximum indent size"); indentString_.resize(indentString_.size() - indentSize_); } @@ -613,7 +617,9 @@ StyledStreamWriter::writeArrayValue(const Value& value) } else // output on a single line { - assert(childValues_.size() == size); + XRPL_ASSERT( + childValues_.size() == size, + "Json::StyledStreamWriter::writeArrayValue : child size match"); *document_ << "[ "; for (unsigned index = 0; index < size; ++index) @@ -706,7 +712,9 @@ StyledStreamWriter::indent() void StyledStreamWriter::unindent() { - assert(indentString_.size() >= indentation_.size()); + XRPL_ASSERT( + indentString_.size() >= indentation_.size(), + "Json::StyledStreamWriter::unindent : maximum indent size"); indentString_.resize(indentString_.size() - indentation_.size()); } diff --git a/src/libxrpl/protocol/AMMCore.cpp b/src/libxrpl/protocol/AMMCore.cpp index 7ac27041e76..3bebfc4659a 100644 --- a/src/libxrpl/protocol/AMMCore.cpp +++ b/src/libxrpl/protocol/AMMCore.cpp @@ -109,7 +109,9 @@ ammAuctionTimeSlot(std::uint64_t current, STObject const& auctionSlot) // It should be impossible for expiration to be < TOTAL_TIME_SLOT_SECS, // but check just to be safe auto const expiration = auctionSlot[sfExpiration]; - assert(expiration >= TOTAL_TIME_SLOT_SECS); + XRPL_ASSERT( + expiration >= TOTAL_TIME_SLOT_SECS, + "ripple::ammAuctionTimeSlot : minimum expiration"); if (expiration >= TOTAL_TIME_SLOT_SECS) { if (auto const start = expiration - TOTAL_TIME_SLOT_SECS; diff --git a/src/libxrpl/protocol/AccountID.cpp b/src/libxrpl/protocol/AccountID.cpp index 5f0fa631851..f271882158b 100644 --- a/src/libxrpl/protocol/AccountID.cpp +++ b/src/libxrpl/protocol/AccountID.cpp @@ -77,7 +77,9 @@ class AccountIdCache auto ret = encodeBase58Token(TokenType::AccountID, id.data(), id.size()); - assert(ret.size() <= 38); + XRPL_ASSERT( + ret.size() <= 38, + "ripple::detail::AccountIdCache : maximum result size"); { std::lock_guard lock(sl); diff --git a/src/libxrpl/protocol/BuildInfo.cpp b/src/libxrpl/protocol/BuildInfo.cpp index 995df262885..9b9d56fa663 100644 --- a/src/libxrpl/protocol/BuildInfo.cpp +++ b/src/libxrpl/protocol/BuildInfo.cpp @@ -33,7 +33,7 @@ namespace BuildInfo { // and follow the format described at http://semver.org/ //------------------------------------------------------------------------------ // clang-format off -char const* const versionString = "2.3.0" +char const* const versionString = "2.4.0-b1" // clang-format on #if defined(DEBUG) || defined(SANITIZER) diff --git a/src/libxrpl/protocol/ErrorCodes.cpp b/src/libxrpl/protocol/ErrorCodes.cpp index c157d9b296c..3482a65ee74 100644 --- a/src/libxrpl/protocol/ErrorCodes.cpp +++ b/src/libxrpl/protocol/ErrorCodes.cpp @@ -17,9 +17,9 @@ */ //============================================================================== +#include #include #include -#include #include namespace ripple { @@ -211,7 +211,9 @@ error_code_http_status(error_code_i code) std::string rpcErrorString(Json::Value const& jv) { - assert(RPC::contains_error(jv)); + XRPL_ASSERT( + RPC::contains_error(jv), + "ripple::RPC::rpcErrorString : input contains an error"); return jv[jss::error].asString() + jv[jss::error_message].asString(); } diff --git a/src/libxrpl/protocol/Feature.cpp b/src/libxrpl/protocol/Feature.cpp index 3f6e760577a..05164489ec7 100644 --- a/src/libxrpl/protocol/Feature.cpp +++ b/src/libxrpl/protocol/Feature.cpp @@ -221,7 +221,9 @@ FeatureCollections::FeatureCollections() std::optional FeatureCollections::getRegisteredFeature(std::string const& name) const { - assert(readOnly); + XRPL_ASSERT( + readOnly.load(), + "ripple::FeatureCollections::getRegisteredFeature : startup completed"); Feature const* feature = getByName(name); if (feature) return feature->feature; @@ -303,7 +305,9 @@ FeatureCollections::registrationIsDone() size_t FeatureCollections::featureToBitsetIndex(uint256 const& f) const { - assert(readOnly); + XRPL_ASSERT( + readOnly.load(), + "ripple::FeatureCollections::featureToBitsetIndex : startup completed"); Feature const* feature = getByFeature(f); if (!feature) @@ -315,7 +319,9 @@ FeatureCollections::featureToBitsetIndex(uint256 const& f) const uint256 const& FeatureCollections::bitsetIndexToFeature(size_t i) const { - assert(readOnly); + XRPL_ASSERT( + readOnly.load(), + "ripple::FeatureCollections::bitsetIndexToFeature : startup completed"); Feature const& feature = getByIndex(i); return feature.feature; } @@ -323,7 +329,9 @@ FeatureCollections::bitsetIndexToFeature(size_t i) const std::string FeatureCollections::featureToName(uint256 const& f) const { - assert(readOnly); + XRPL_ASSERT( + readOnly.load(), + "ripple::FeatureCollections::featureToName : startup completed"); Feature const* feature = getByFeature(f); return feature ? feature->name : to_string(f); } diff --git a/src/libxrpl/basics/IOUAmount.cpp b/src/libxrpl/protocol/IOUAmount.cpp similarity index 99% rename from src/libxrpl/basics/IOUAmount.cpp rename to src/libxrpl/protocol/IOUAmount.cpp index a24e1b917f7..7fc879609ed 100644 --- a/src/libxrpl/basics/IOUAmount.cpp +++ b/src/libxrpl/protocol/IOUAmount.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include #include #include #include diff --git a/src/libxrpl/protocol/Indexes.cpp b/src/libxrpl/protocol/Indexes.cpp index 12142879ad5..c7f4441c7bc 100644 --- a/src/libxrpl/protocol/Indexes.cpp +++ b/src/libxrpl/protocol/Indexes.cpp @@ -17,6 +17,8 @@ */ //============================================================================== +#include +#include #include #include #include @@ -26,7 +28,6 @@ #include #include -#include namespace ripple { @@ -95,7 +96,8 @@ indexHash(LedgerNameSpace space, Args const&... args) uint256 getBookBase(Book const& book) { - assert(isConsistent(book)); + XRPL_ASSERT( + isConsistent(book), "ripple::getBookBase : input is consistent"); auto const index = indexHash( LedgerNameSpace::BOOK_DIR, @@ -135,7 +137,7 @@ getTicketIndex(AccountID const& account, std::uint32_t ticketSeq) uint256 getTicketIndex(AccountID const& account, SeqProxy ticketSeq) { - assert(ticketSeq.isTicket()); + XRPL_ASSERT(ticketSeq.isTicket(), "ripple::getTicketIndex : valid input"); return getTicketIndex(account, ticketSeq.value()); } @@ -222,7 +224,8 @@ line( // There is code in SetTrust that calls us with id0 == id1, to allow users // to locate and delete such "weird" trustlines. If we remove that code, we // could enable this assert: - // assert(id0 != id1); + // XRPL_ASSERT(id0 != id1, "ripple::keylet::line : accounts must be + // different"); // A trust line is shared between two accounts; while we typically think // of this as an "issuer" and a "holder" the relationship is actually fully @@ -251,7 +254,8 @@ offer(AccountID const& id, std::uint32_t seq) noexcept Keylet quality(Keylet const& k, std::uint64_t q) noexcept { - assert(k.type == ltDIR_NODE); + XRPL_ASSERT( + k.type == ltDIR_NODE, "ripple::keylet::quality : valid input type"); // Indexes are stored in big endian format: they print as hex as stored. // Most significant bytes are first and the least significant bytes @@ -269,7 +273,9 @@ quality(Keylet const& k, std::uint64_t q) noexcept Keylet next_t::operator()(Keylet const& k) const { - assert(k.type == ltDIR_NODE); + XRPL_ASSERT( + k.type == ltDIR_NODE, + "ripple::keylet::next_t::operator() : valid input type"); return {ltDIR_NODE, getQualityNext(k.key)}; } @@ -387,7 +393,8 @@ nftpage_max(AccountID const& owner) Keylet nftpage(Keylet const& k, uint256 const& token) { - assert(k.type == ltNFTOKEN_PAGE); + XRPL_ASSERT( + k.type == ltNFTOKEN_PAGE, "ripple::keylet::nftpage : valid input type"); return {ltNFTOKEN_PAGE, (k.key & ~nft::pageMask) + (token & nft::pageMask)}; } @@ -411,9 +418,10 @@ nft_sells(uint256 const& id) noexcept } Keylet -amm(Issue const& issue1, Issue const& issue2) noexcept +amm(Asset const& issue1, Asset const& issue2) noexcept { - auto const& [minI, maxI] = std::minmax(issue1, issue2); + auto const& [minI, maxI] = + std::minmax(issue1.get(), issue2.get()); return amm(indexHash( LedgerNameSpace::AMM, minI.account, diff --git a/src/libxrpl/protocol/Keylet.cpp b/src/libxrpl/protocol/Keylet.cpp index 23847811d3b..846c3bc07b3 100644 --- a/src/libxrpl/protocol/Keylet.cpp +++ b/src/libxrpl/protocol/Keylet.cpp @@ -25,7 +25,9 @@ namespace ripple { bool Keylet::check(STLedgerEntry const& sle) const { - assert(sle.getType() != ltANY || sle.getType() != ltCHILD); + XRPL_ASSERT( + sle.getType() != ltANY || sle.getType() != ltCHILD, + "ripple::Keylet::check : valid input type"); if (type == ltANY) return true; diff --git a/src/libxrpl/basics/MPTAmount.cpp b/src/libxrpl/protocol/MPTAmount.cpp similarity index 97% rename from src/libxrpl/basics/MPTAmount.cpp rename to src/libxrpl/protocol/MPTAmount.cpp index 0481da67711..17bbedea451 100644 --- a/src/libxrpl/basics/MPTAmount.cpp +++ b/src/libxrpl/protocol/MPTAmount.cpp @@ -17,7 +17,7 @@ */ //============================================================================== -#include +#include namespace ripple { diff --git a/src/libxrpl/protocol/Quality.cpp b/src/libxrpl/protocol/Quality.cpp index c6464eba9d2..ba669d9bd1f 100644 --- a/src/libxrpl/protocol/Quality.cpp +++ b/src/libxrpl/protocol/Quality.cpp @@ -17,8 +17,8 @@ */ //============================================================================== +#include #include -#include #include namespace ripple { @@ -35,7 +35,7 @@ Quality::Quality(Amounts const& amount) Quality& Quality::operator++() { - assert(m_value > 0); + XRPL_ASSERT(m_value > 0, "ripple::Quality::operator++() : minimum value"); --m_value; return *this; } @@ -51,7 +51,9 @@ Quality::operator++(int) Quality& Quality::operator--() { - assert(m_value < std::numeric_limits::max()); + XRPL_ASSERT( + m_value < std::numeric_limits::max(), + "ripple::Quality::operator--() : maximum value"); ++m_value; return *this; } @@ -81,10 +83,12 @@ ceil_in_impl( // Clamp out if (result.out > amount.out) result.out = amount.out; - assert(result.in == limit); + XRPL_ASSERT( + result.in == limit, "ripple::ceil_in_impl : result matches limit"); return result; } - assert(amount.in <= limit); + XRPL_ASSERT( + amount.in <= limit, "ripple::ceil_in_impl : result inside limit"); return amount; } @@ -120,10 +124,13 @@ ceil_out_impl( // Clamp in if (result.in > amount.in) result.in = amount.in; - assert(result.out == limit); + XRPL_ASSERT( + result.out == limit, + "ripple::ceil_out_impl : result matches limit"); return result; } - assert(amount.out <= limit); + XRPL_ASSERT( + amount.out <= limit, "ripple::ceil_out_impl : result inside limit"); return amount; } @@ -146,17 +153,23 @@ Quality composed_quality(Quality const& lhs, Quality const& rhs) { STAmount const lhs_rate(lhs.rate()); - assert(lhs_rate != beast::zero); + XRPL_ASSERT( + lhs_rate != beast::zero, + "ripple::composed_quality : nonzero left input"); STAmount const rhs_rate(rhs.rate()); - assert(rhs_rate != beast::zero); + XRPL_ASSERT( + rhs_rate != beast::zero, + "ripple::composed_quality : nonzero right input"); STAmount const rate(mulRound(lhs_rate, rhs_rate, lhs_rate.asset(), true)); std::uint64_t const stored_exponent(rate.exponent() + 100); std::uint64_t const stored_mantissa(rate.mantissa()); - assert((stored_exponent > 0) && (stored_exponent <= 255)); + XRPL_ASSERT( + (stored_exponent > 0) && (stored_exponent <= 255), + "ripple::composed_quality : valid exponent"); return Quality((stored_exponent << (64 - 8)) | stored_mantissa); } diff --git a/src/libxrpl/protocol/Rate2.cpp b/src/libxrpl/protocol/Rate2.cpp index 33bd9c5d0be..64ac6c46315 100644 --- a/src/libxrpl/protocol/Rate2.cpp +++ b/src/libxrpl/protocol/Rate2.cpp @@ -46,7 +46,7 @@ transferFeeAsRate(std::uint16_t fee) STAmount multiply(STAmount const& amount, Rate const& rate) { - assert(rate.value != 0); + XRPL_ASSERT(rate.value, "ripple::nft::multiply : nonzero rate input"); if (rate == parityRate) return amount; @@ -57,7 +57,7 @@ multiply(STAmount const& amount, Rate const& rate) STAmount multiplyRound(STAmount const& amount, Rate const& rate, bool roundUp) { - assert(rate.value != 0); + XRPL_ASSERT(rate.value, "ripple::nft::multiplyRound : nonzero rate input"); if (rate == parityRate) return amount; @@ -72,7 +72,8 @@ multiplyRound( Asset const& asset, bool roundUp) { - assert(rate.value != 0); + XRPL_ASSERT( + rate.value, "ripple::nft::multiplyRound(Issue) : nonzero rate input"); if (rate == parityRate) { @@ -85,7 +86,7 @@ multiplyRound( STAmount divide(STAmount const& amount, Rate const& rate) { - assert(rate.value != 0); + XRPL_ASSERT(rate.value, "ripple::nft::divide : nonzero rate input"); if (rate == parityRate) return amount; @@ -96,7 +97,7 @@ divide(STAmount const& amount, Rate const& rate) STAmount divideRound(STAmount const& amount, Rate const& rate, bool roundUp) { - assert(rate.value != 0); + XRPL_ASSERT(rate.value, "ripple::nft::divideRound : nonzero rate input"); if (rate == parityRate) return amount; @@ -111,7 +112,8 @@ divideRound( Asset const& asset, bool roundUp) { - assert(rate.value != 0); + XRPL_ASSERT( + rate.value, "ripple::nft::divideRound(Issue) : nonzero rate input"); if (rate == parityRate) return amount; diff --git a/src/libxrpl/protocol/Rules.cpp b/src/libxrpl/protocol/Rules.cpp index f47e966e138..7043acff96d 100644 --- a/src/libxrpl/protocol/Rules.cpp +++ b/src/libxrpl/protocol/Rules.cpp @@ -91,7 +91,10 @@ class Rules::Impl return true; if (!digest_ || !other.digest_) return false; - assert(presets_ == other.presets_); + XRPL_ASSERT( + presets_ == other.presets_, + "ripple::Rules::Impl::operator==(Impl) const : input presets do " + "match"); return *digest_ == *other.digest_; } }; @@ -118,7 +121,7 @@ Rules::presets() const bool Rules::enabled(uint256 const& feature) const { - assert(impl_); + XRPL_ASSERT(impl_, "ripple::Rules::enabled : initialized"); // The functionality of the "NonFungibleTokensV1_1" amendment is // precisely the functionality of the following three amendments @@ -137,7 +140,9 @@ Rules::enabled(uint256 const& feature) const bool Rules::operator==(Rules const& other) const { - assert(impl_ && other.impl_); + XRPL_ASSERT( + impl_ && other.impl_, + "ripple::Rules::operator==(Rules) const : both initialized"); if (impl_.get() == other.impl_.get()) return true; return *impl_ == *other.impl_; diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index 537fa557fcc..20e1e112655 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -17,8 +17,8 @@ */ //============================================================================== +#include #include -#include #include #include #include diff --git a/src/libxrpl/protocol/STAccount.cpp b/src/libxrpl/protocol/STAccount.cpp index 8ae43f76863..c033e4cb580 100644 --- a/src/libxrpl/protocol/STAccount.cpp +++ b/src/libxrpl/protocol/STAccount.cpp @@ -80,8 +80,11 @@ STAccount::getSType() const void STAccount::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == STI_ACCOUNT); + XRPL_ASSERT( + getFName().isBinary(), "ripple::STAccount::add : field is binary"); + XRPL_ASSERT( + getFName().fieldType == STI_ACCOUNT, + "ripple::STAccount::add : valid field type"); // Preserve the serialization behavior of an STBlob: // o If we are default (all zeros) serialize as an empty blob. diff --git a/src/libxrpl/protocol/STAmount.cpp b/src/libxrpl/protocol/STAmount.cpp index fe13118d88c..37830830ade 100644 --- a/src/libxrpl/protocol/STAmount.cpp +++ b/src/libxrpl/protocol/STAmount.cpp @@ -29,7 +29,7 @@ #include #include #include -#include + #include #include @@ -68,11 +68,14 @@ getInt64Value(STAmount const& amount, bool valid, const char* error) { if (!valid) Throw(error); - assert(amount.exponent() == 0); + XRPL_ASSERT( + amount.exponent() == 0, "ripple::getInt64Value : exponent is zero"); auto ret = static_cast(amount.mantissa()); - assert(static_cast(ret) == amount.mantissa()); + XRPL_ASSERT( + static_cast(ret) == amount.mantissa(), + "ripple::getInt64Value : mantissa must roundtrip"); if (amount.negative()) ret = -ret; @@ -199,7 +202,10 @@ STAmount::STAmount(SField const& name, std::uint64_t mantissa, bool negative) , mOffset(0) , mIsNegative(negative) { - assert(mValue <= std::numeric_limits::max()); + XRPL_ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(SField, std::uint64_t, bool) : maximum " + "mantissa input"); } STAmount::STAmount(SField const& name, STAmount const& from) @@ -209,7 +215,9 @@ STAmount::STAmount(SField const& name, STAmount const& from) , mOffset(from.mOffset) , mIsNegative(from.mIsNegative) { - assert(mValue <= std::numeric_limits::max()); + XRPL_ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(SField, STAmount) : maximum input"); canonicalize(); } @@ -221,7 +229,10 @@ STAmount::STAmount(std::uint64_t mantissa, bool negative) , mOffset(0) , mIsNegative(mantissa != 0 && negative) { - assert(mValue <= std::numeric_limits::max()); + XRPL_ASSERT( + mValue <= std::numeric_limits::max(), + "ripple::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa " + "input"); } STAmount::STAmount(XRPAmount const& amount) @@ -305,7 +316,9 @@ STAmount::mpt() const STAmount& STAmount::operator=(IOUAmount const& iou) { - assert(native() == false); + XRPL_ASSERT( + native() == false, + "ripple::STAmount::operator=(IOUAmount) : is not XRP"); mOffset = iou.exponent(); mIsNegative = iou < beast::zero; if (mIsNegative) @@ -444,7 +457,9 @@ getRate(STAmount const& offerOut, STAmount const& offerIn) STAmount r = divide(offerIn, offerOut, noIssue()); if (r == beast::zero) // offer is too good return 0; - assert((r.exponent() >= -100) && (r.exponent() <= 155)); + XRPL_ASSERT( + (r.exponent() >= -100) && (r.exponent() <= 155), + "ripple::getRate : exponent inside range"); std::uint64_t ret = r.exponent() + 100; return (ret << (64 - 8)) | r.mantissa(); } @@ -525,7 +540,7 @@ STAmount::getText() const return ret; } - assert(mOffset + 43 > 0); + XRPL_ASSERT(mOffset + 43 > 0, "ripple::STAmount::getText : minimum offset"); size_t const pad_prefix = 27; size_t const pad_suffix = 23; @@ -549,7 +564,9 @@ STAmount::getText() const if (std::distance(pre_from, pre_to) > pad_prefix) pre_from += pad_prefix; - assert(post_to >= post_from); + XRPL_ASSERT( + post_to >= post_from, + "ripple::STAmount::getText : first distance check"); pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; }); @@ -558,7 +575,9 @@ STAmount::getText() const if (std::distance(post_from, post_to) > pad_suffix) post_to -= pad_suffix; - assert(post_to >= post_from); + XRPL_ASSERT( + post_to >= post_from, + "ripple::STAmount::getText : second distance check"); post_to = std::find_if( std::make_reverse_iterator(post_to), @@ -594,7 +613,7 @@ STAmount::add(Serializer& s) const { if (native()) { - assert(mOffset == 0); + XRPL_ASSERT(mOffset == 0, "ripple::STAmount::add : zero offset"); if (!mIsNegative) s.add64(mValue | cPositive); @@ -771,10 +790,15 @@ STAmount::canonicalize() if (mOffset > cMaxOffset) Throw("value overflow"); - assert((mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue))); - assert( - (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset))); - assert((mValue != 0) || (mOffset != -100)); + XRPL_ASSERT( + (mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)), + "ripple::STAmount::canonicalize : value inside range"); + XRPL_ASSERT( + (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)), + "ripple::STAmount::canonicalize : offset inside range"); + XRPL_ASSERT( + (mValue != 0) || (mOffset != -100), + "ripple::STAmount::canonicalize : value or offset set"); } void diff --git a/src/libxrpl/protocol/STBase.cpp b/src/libxrpl/protocol/STBase.cpp index 73565cbf765..6986957b61e 100644 --- a/src/libxrpl/protocol/STBase.cpp +++ b/src/libxrpl/protocol/STBase.cpp @@ -17,10 +17,9 @@ */ //============================================================================== +#include #include #include -#include -#include namespace ripple { @@ -30,7 +29,7 @@ STBase::STBase() : fName(&sfGeneric) STBase::STBase(SField const& n) : fName(&n) { - assert(fName); + XRPL_ASSERT(fName, "ripple::STBase::STBase : field is set"); } STBase& @@ -106,13 +105,15 @@ void STBase::add(Serializer& s) const { // Should never be called - assert(false); + UNREACHABLE("ripple::STBase::add : not implemented"); } bool STBase::isEquivalent(const STBase& t) const { - assert(getSType() == STI_NOTPRESENT); + XRPL_ASSERT( + getSType() == STI_NOTPRESENT, + "ripple::STBase::isEquivalent : type not present"); return t.getSType() == STI_NOTPRESENT; } @@ -126,7 +127,7 @@ void STBase::setFName(SField const& n) { fName = &n; - assert(fName); + XRPL_ASSERT(fName, "ripple::STBase::setFName : field is set"); } SField const& @@ -138,7 +139,8 @@ STBase::getFName() const void STBase::addFieldID(Serializer& s) const { - assert(fName->isBinary()); + XRPL_ASSERT( + fName->isBinary(), "ripple::STBase::addFieldID : field is binary"); s.addFieldID(fName->fieldType, fName->fieldValue); } diff --git a/src/libxrpl/protocol/STBlob.cpp b/src/libxrpl/protocol/STBlob.cpp index 63e7b4bf3da..34e759b4c37 100644 --- a/src/libxrpl/protocol/STBlob.cpp +++ b/src/libxrpl/protocol/STBlob.cpp @@ -54,10 +54,11 @@ STBlob::getText() const void STBlob::add(Serializer& s) const { - assert(getFName().isBinary()); - assert( + XRPL_ASSERT(getFName().isBinary(), "ripple::STBlob::add : field is binary"); + XRPL_ASSERT( (getFName().fieldType == STI_VL) || - (getFName().fieldType == STI_ACCOUNT)); + (getFName().fieldType == STI_ACCOUNT), + "ripple::STBlob::add : valid field type"); s.addVL(value_.data(), value_.size()); } diff --git a/src/libxrpl/protocol/STInteger.cpp b/src/libxrpl/protocol/STInteger.cpp index 7dfcc50dea0..9525a47c462 100644 --- a/src/libxrpl/protocol/STInteger.cpp +++ b/src/libxrpl/protocol/STInteger.cpp @@ -199,12 +199,16 @@ Json::Value STUInt64::getJson(JsonOptions) const { auto convertToString = [](uint64_t const value, int const base) { - assert(base == 10 || base == 16); + XRPL_ASSERT( + base == 10 || base == 16, + "ripple::STUInt64::getJson : base 10 or 16"); std::string str( base == 10 ? 20 : 16, 0); // Allocate space depending on base auto ret = std::to_chars(str.data(), str.data() + str.size(), value, base); - assert(ret.ec == std::errc()); + XRPL_ASSERT( + ret.ec == std::errc(), + "ripple::STUInt64::getJson : to_chars succeeded"); str.resize(std::distance(str.data(), ret.ptr)); return str; }; diff --git a/src/libxrpl/protocol/STIssue.cpp b/src/libxrpl/protocol/STIssue.cpp index 00fe86b3287..5a2008cb178 100644 --- a/src/libxrpl/protocol/STIssue.cpp +++ b/src/libxrpl/protocol/STIssue.cpp @@ -40,23 +40,46 @@ STIssue::STIssue(SField const& name) : STBase{name} STIssue::STIssue(SerialIter& sit, SField const& name) : STBase{name} { - issue_.currency = sit.get160(); - if (!isXRP(issue_.currency)) - issue_.account = sit.get160(); - else - issue_.account = xrpAccount(); - - if (isXRP(issue_.currency) != isXRP(issue_.account)) - Throw( - "invalid issue: currency and account native mismatch"); -} + auto const currencyOrAccount = sit.get160(); -STIssue::STIssue(SField const& name, Issue const& issue) - : STBase{name}, issue_{issue} -{ - if (isXRP(issue_.currency) != isXRP(issue_.account)) - Throw( - "invalid issue: currency and account native mismatch"); + if (isXRP(static_cast(currencyOrAccount))) + { + asset_ = xrpIssue(); + } + // Check if MPT + else + { + // MPT is serialized as: + // - 160 bits MPT issuer account + // - 160 bits black hole account + // - 32 bits sequence + AccountID account = static_cast(sit.get160()); + // MPT + if (noAccount() == account) + { + MPTID mptID; + std::uint32_t sequence = sit.get32(); + static_assert( + MPTID::size() == sizeof(sequence) + sizeof(currencyOrAccount)); + memcpy(mptID.data(), &sequence, sizeof(sequence)); + memcpy( + mptID.data() + sizeof(sequence), + currencyOrAccount.data(), + sizeof(currencyOrAccount)); + MPTIssue issue{mptID}; + asset_ = issue; + } + else + { + Issue issue; + issue.currency = currencyOrAccount; + issue.account = account; + if (!isConsistent(issue)) + Throw( + "invalid issue: currency and account native mismatch"); + asset_ = issue; + } + } } SerializedTypeID @@ -65,18 +88,39 @@ STIssue::getSType() const return STI_ISSUE; } +std::string +STIssue::getText() const +{ + return asset_.getText(); +} + Json::Value STIssue::getJson(JsonOptions) const { - return to_json(issue_); + Json::Value jv; + asset_.setJson(jv); + return jv; } void STIssue::add(Serializer& s) const { - s.addBitString(issue_.currency); - if (!isXRP(issue_.currency)) - s.addBitString(issue_.account); + if (holds()) + { + auto const& issue = asset_.get(); + s.addBitString(issue.currency); + if (!isXRP(issue.currency)) + s.addBitString(issue.account); + } + else + { + auto const& issue = asset_.get(); + s.addBitString(issue.getIssuer()); + s.addBitString(noAccount()); + std::uint32_t sequence; + memcpy(&sequence, issue.getMptID().data(), sizeof(sequence)); + s.add32(sequence); + } } bool @@ -89,7 +133,7 @@ STIssue::isEquivalent(const STBase& t) const bool STIssue::isDefault() const { - return issue_ == xrpIssue(); + return holds() && asset_.get() == xrpIssue(); } STBase* @@ -107,7 +151,7 @@ STIssue::move(std::size_t n, void* buf) STIssue issueFromJson(SField const& name, Json::Value const& v) { - return STIssue{name, issueFromJson(v)}; + return STIssue{name, assetFromJson(v)}; } } // namespace ripple diff --git a/src/libxrpl/protocol/STLedgerEntry.cpp b/src/libxrpl/protocol/STLedgerEntry.cpp index 1801149ab2a..0350dd883b8 100644 --- a/src/libxrpl/protocol/STLedgerEntry.cpp +++ b/src/libxrpl/protocol/STLedgerEntry.cpp @@ -161,7 +161,9 @@ STLedgerEntry::thread( if (oldPrevTxID == txID) { // this transaction is already threaded - assert(getFieldU32(sfPreviousTxnLgrSeq) == ledgerSeq); + XRPL_ASSERT( + getFieldU32(sfPreviousTxnLgrSeq) == ledgerSeq, + "ripple::STLedgerEntry::thread : ledger sequence match"); return false; } diff --git a/src/libxrpl/protocol/STNumber.cpp b/src/libxrpl/protocol/STNumber.cpp index 3a92bbb02f9..74961bfbcab 100644 --- a/src/libxrpl/protocol/STNumber.cpp +++ b/src/libxrpl/protocol/STNumber.cpp @@ -19,6 +19,7 @@ #include +#include #include namespace ripple { @@ -52,8 +53,11 @@ STNumber::getText() const void STNumber::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == getSType()); + XRPL_ASSERT( + getFName().isBinary(), "ripple::STNumber::add : field is binary"); + XRPL_ASSERT( + getFName().fieldType == getSType(), + "ripple::STNumber::add : field type match"); s.add64(value_.mantissa()); s.add32(value_.exponent()); } @@ -85,7 +89,9 @@ STNumber::move(std::size_t n, void* buf) bool STNumber::isEquivalent(STBase const& t) const { - assert(t.getSType() == this->getSType()); + XRPL_ASSERT( + t.getSType() == this->getSType(), + "ripple::STNumber::isEquivalent : field type match"); STNumber const& v = dynamic_cast(t); return value_ == v; } diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index c8fc88348e9..821f8f05c96 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -862,9 +862,10 @@ STObject::add(Serializer& s, WhichFields whichFields) const // the type associated by rule with this field name // must be OBJECT, or the object cannot be deserialized SerializedTypeID const sType{field->getSType()}; - assert( + XRPL_ASSERT( (sType != STI_OBJECT) || - (field->getFName().fieldType == STI_OBJECT)); + (field->getFName().fieldType == STI_OBJECT), + "ripple::STObject::add : valid field type"); field->addFieldID(s); field->add(s); if (sType == STI_ARRAY || sType == STI_OBJECT) diff --git a/src/libxrpl/protocol/STParsedJSON.cpp b/src/libxrpl/protocol/STParsedJSON.cpp index 09b6b6679d7..7d08993a8ba 100644 --- a/src/libxrpl/protocol/STParsedJSON.cpp +++ b/src/libxrpl/protocol/STParsedJSON.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include #include -#include #include #include diff --git a/src/libxrpl/protocol/STPathSet.cpp b/src/libxrpl/protocol/STPathSet.cpp index 78c47cadc66..57bcaca6b2c 100644 --- a/src/libxrpl/protocol/STPathSet.cpp +++ b/src/libxrpl/protocol/STPathSet.cpp @@ -209,8 +209,11 @@ STPathSet::getSType() const void STPathSet::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == STI_PATHSET); + XRPL_ASSERT( + getFName().isBinary(), "ripple::STPathSet::add : field is binary"); + XRPL_ASSERT( + getFName().fieldType == STI_PATHSET, + "ripple::STPathSet::add : valid field type"); bool first = true; for (auto const& spPath : value) diff --git a/src/libxrpl/protocol/STTx.cpp b/src/libxrpl/protocol/STTx.cpp index 7bd25246c53..bd1c461c8c7 100644 --- a/src/libxrpl/protocol/STTx.cpp +++ b/src/libxrpl/protocol/STTx.cpp @@ -137,7 +137,9 @@ STTx::getMentionedAccounts() const { if (auto sacc = dynamic_cast(&it)) { - assert(!sacc->isDefault()); + XRPL_ASSERT( + !sacc->isDefault(), + "ripple::STTx::getMentionedAccounts : account is set"); if (!sacc->isDefault()) list.insert(sacc->value()); } @@ -298,7 +300,7 @@ STTx::getMetaSQL( std::string rTxn = sqlBlobLiteral(rawTxn.peekData()); auto format = TxFormats::getInstance().findByType(tx_type_); - assert(format != nullptr); + XRPL_ASSERT(format, "ripple::STTx::getMetaSQL : non-null type format"); return str( boost::format(bfTrans) % to_string(getTransactionID()) % @@ -557,8 +559,10 @@ invalidMPTAmountInTx(STObject const& tx) if (tx.isFieldPresent(e.sField()) && e.supportMPT() != soeMPTNone) { if (auto const& field = tx.peekAtField(e.sField()); - field.getSType() == STI_AMOUNT && - static_cast(field).holds()) + (field.getSType() == STI_AMOUNT && + static_cast(field).holds()) || + (field.getSType() == STI_ISSUE && + static_cast(field).holds())) { if (e.supportMPT() != soeMPTSupported) return true; diff --git a/src/libxrpl/protocol/STValidation.cpp b/src/libxrpl/protocol/STValidation.cpp index ca5ceb0d9ce..16f0c288796 100644 --- a/src/libxrpl/protocol/STValidation.cpp +++ b/src/libxrpl/protocol/STValidation.cpp @@ -107,7 +107,9 @@ STValidation::isValid() const noexcept { if (!valid_) { - assert(publicKeyType(getSignerPublic()) == KeyType::secp256k1); + XRPL_ASSERT( + publicKeyType(getSignerPublic()) == KeyType::secp256k1, + "ripple::STValidation::isValid : valid key type"); valid_ = verifyDigest( getSignerPublic(), diff --git a/src/libxrpl/protocol/STVar.cpp b/src/libxrpl/protocol/STVar.cpp index 55927cb33aa..c5d3102bfa7 100644 --- a/src/libxrpl/protocol/STVar.cpp +++ b/src/libxrpl/protocol/STVar.cpp @@ -121,7 +121,9 @@ STVar::STVar(SerialIter& sit, SField const& name, int depth) STVar::STVar(SerializedTypeID id, SField const& name) { - assert((id == STI_NOTPRESENT) || (id == name.fieldType)); + XRPL_ASSERT( + (id == STI_NOTPRESENT) || (id == name.fieldType), + "ripple::detail::STVar::STVar(SerializedTypeID) : valid type input"); constructST(id, 0, name); } diff --git a/src/libxrpl/protocol/STVector256.cpp b/src/libxrpl/protocol/STVector256.cpp index 385c0ef76db..6f70a3849c1 100644 --- a/src/libxrpl/protocol/STVector256.cpp +++ b/src/libxrpl/protocol/STVector256.cpp @@ -68,8 +68,11 @@ STVector256::isDefault() const void STVector256::add(Serializer& s) const { - assert(getFName().isBinary()); - assert(getFName().fieldType == STI_VECTOR256); + XRPL_ASSERT( + getFName().isBinary(), "ripple::STVector256::add : field is binary"); + XRPL_ASSERT( + getFName().fieldType == STI_VECTOR256, + "ripple::STVector256::add : valid field type"); s.addVL(mValue.begin(), mValue.end(), mValue.size() * (256 / 8)); } diff --git a/src/libxrpl/protocol/Serializer.cpp b/src/libxrpl/protocol/Serializer.cpp index ceaf76faf34..f46104f6382 100644 --- a/src/libxrpl/protocol/Serializer.cpp +++ b/src/libxrpl/protocol/Serializer.cpp @@ -107,7 +107,9 @@ int Serializer::addFieldID(int type, int name) { int ret = mData.size(); - assert((type > 0) && (type < 256) && (name > 0) && (name < 256)); + XRPL_ASSERT( + (type > 0) && (type < 256) && (name > 0) && (name < 256), + "ripple::Serializer::addFieldID : inputs inside range"); if (type < 16) { @@ -176,9 +178,10 @@ Serializer::addVL(Blob const& vector) { int ret = addEncoded(vector.size()); addRaw(vector); - assert( + XRPL_ASSERT( mData.size() == - (ret + vector.size() + encodeLengthLength(vector.size()))); + (ret + vector.size() + encodeLengthLength(vector.size())), + "ripple::Serializer::addVL : size matches expected"); return ret; } @@ -482,7 +485,8 @@ SerialIter::getVLDataLength() } else { - assert(lenLen == 3); + XRPL_ASSERT( + lenLen == 3, "ripple::SerialIter::getVLDataLength : lenLen is 3"); int b2 = get8(); int b3 = get8(); datLen = Serializer::decodeVLLength(b1, b2, b3); diff --git a/src/libxrpl/protocol/TxMeta.cpp b/src/libxrpl/protocol/TxMeta.cpp index 253d00e8414..dad67c13349 100644 --- a/src/libxrpl/protocol/TxMeta.cpp +++ b/src/libxrpl/protocol/TxMeta.cpp @@ -55,7 +55,9 @@ TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj) auto affectedNodes = dynamic_cast(obj.peekAtPField(sfAffectedNodes)); - assert(affectedNodes); + XRPL_ASSERT( + affectedNodes, + "ripple::TxMeta::TxMeta(STObject) : type cast succeeded"); if (affectedNodes) mNodes = *affectedNodes; @@ -106,7 +108,9 @@ TxMeta::setAffectedNode( mNodes.push_back(STObject(type)); STObject& obj = mNodes.back(); - assert(obj.getFName() == type); + XRPL_ASSERT( + obj.getFName() == type, + "ripple::TxMeta::setAffectedNode : field type match"); obj.setFieldH256(sfLedgerIndex, node); obj.setFieldU16(sfLedgerEntryType, nodeType); } @@ -127,14 +131,18 @@ TxMeta::getAffectedAccounts() const if (index != -1) { auto inner = dynamic_cast(&it.peekAtIndex(index)); - assert(inner); + XRPL_ASSERT( + inner, + "ripple::getAffectedAccounts : STObject type cast succeeded"); if (inner) { for (auto const& field : *inner) { if (auto sa = dynamic_cast(&field)) { - assert(!sa->isDefault()); + XRPL_ASSERT( + !sa->isDefault(), + "ripple::getAffectedAccounts : account is set"); if (!sa->isDefault()) list.insert(sa->value()); } @@ -145,7 +153,10 @@ TxMeta::getAffectedAccounts() const (field.getFName() == sfTakerGets)) { auto lim = dynamic_cast(&field); - assert(lim); + XRPL_ASSERT( + lim, + "ripple::getAffectedAccounts : STAmount type cast " + "succeeded"); if (lim != nullptr) { @@ -175,7 +186,9 @@ TxMeta::getAffectedNode(SLE::ref node, SField const& type) mNodes.push_back(STObject(type)); STObject& obj = mNodes.back(); - assert(obj.getFName() == type); + XRPL_ASSERT( + obj.getFName() == type, + "ripple::TxMeta::getAffectedNode(SLE::ref) : field type match"); obj.setFieldH256(sfLedgerIndex, index); obj.setFieldU16(sfLedgerEntryType, node->getFieldU16(sfLedgerEntryType)); @@ -190,7 +203,7 @@ TxMeta::getAffectedNode(uint256 const& node) if (n.getFieldH256(sfLedgerIndex) == node) return n; } - assert(false); + UNREACHABLE("ripple::TxMeta::getAffectedNode(uint256) : node not found"); Throw("Affected node not found"); return *(mNodes.begin()); // Silence compiler warning. } @@ -199,7 +212,7 @@ STObject TxMeta::getAsObject() const { STObject metaData(sfTransactionMetaData); - assert(mResult != 255); + XRPL_ASSERT(mResult != 255, "ripple::TxMeta::getAsObject : result is set"); metaData.setFieldU8(sfTransactionResult, mResult); metaData.setFieldU32(sfTransactionIndex, mIndex); metaData.emplace_back(mNodes); @@ -213,7 +226,9 @@ TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index) { mResult = TERtoInt(result); mIndex = index; - assert((mResult == 0) || ((mResult > 100) && (mResult <= 255))); + XRPL_ASSERT( + (mResult == 0) || ((mResult > 100) && (mResult <= 255)), + "ripple::TxMeta::addRaw : valid TER input"); mNodes.sort([](STObject const& o1, STObject const& o2) { return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex); diff --git a/src/libxrpl/protocol/tokens.cpp b/src/libxrpl/protocol/tokens.cpp index ccae1fb8ed2..49ec926a775 100644 --- a/src/libxrpl/protocol/tokens.cpp +++ b/src/libxrpl/protocol/tokens.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -35,7 +36,6 @@ #include #include -#include #include #include #include @@ -248,7 +248,8 @@ encodeBase58( iter[-1] = carry % 58; carry /= 58; } - assert(carry == 0); + XRPL_ASSERT( + carry == 0, "ripple::b58_ref::detail::encodeBase58 : zero carry"); pbegin++; } @@ -298,7 +299,8 @@ decodeBase58(std::string const& s) *iter = carry % 256; carry /= 256; } - assert(carry == 0); + XRPL_ASSERT( + carry == 0, "ripple::b58_ref::detail::decodeBase58 : zero carry"); ++psz; --remain; } @@ -535,7 +537,9 @@ b58_to_b256_be(std::string_view input, std::span out) ripple::b58_fast::detail::div_rem(input.size(), 10); auto const num_partial_coeffs = partial_coeff_len ? 1 : 0; auto const num_b_58_10_coeffs = num_full_coeffs + num_partial_coeffs; - assert(num_b_58_10_coeffs <= b_58_10_coeff.size()); + XRPL_ASSERT( + num_b_58_10_coeffs <= b_58_10_coeff.size(), + "ripple::b58_fast::detail::b58_to_b256_be : maximum coeff"); for (auto c : input.substr(0, partial_coeff_len)) { auto cur_val = ::ripple::alphabetReverse[c]; diff --git a/src/libxrpl/resource/Consumer.cpp b/src/libxrpl/resource/Consumer.cpp index b8652546841..618b4f5e614 100644 --- a/src/libxrpl/resource/Consumer.cpp +++ b/src/libxrpl/resource/Consumer.cpp @@ -17,10 +17,10 @@ */ //============================================================================== +#include #include #include #include -#include namespace ripple { namespace Resource { @@ -109,14 +109,15 @@ Consumer::charge(Charge const& what) bool Consumer::warn() { - assert(m_entry != nullptr); + XRPL_ASSERT(m_entry, "ripple::Resource::Consumer::warn : non-null entry"); return m_logic->warn(*m_entry); } bool Consumer::disconnect(beast::Journal const& j) { - assert(m_entry != nullptr); + XRPL_ASSERT( + m_entry, "ripple::Resource::Consumer::disconnect : non-null entry"); bool const d = m_logic->disconnect(*m_entry); if (d) { @@ -128,14 +129,15 @@ Consumer::disconnect(beast::Journal const& j) int Consumer::balance() { - assert(m_entry != nullptr); + XRPL_ASSERT( + m_entry, "ripple::Resource::Consumer::balance : non-null entry"); return m_logic->balance(*m_entry); } Entry& Consumer::entry() { - assert(m_entry != nullptr); + XRPL_ASSERT(m_entry, "ripple::Resource::Consumer::entry : non-null entry"); return *m_entry; } diff --git a/src/test/app/MPToken_test.cpp b/src/test/app/MPToken_test.cpp index 796a3f14c88..9fd4927d5eb 100644 --- a/src/test/app/MPToken_test.cpp +++ b/src/test/app/MPToken_test.cpp @@ -1470,19 +1470,19 @@ class MPToken_test : public beast::unit_test::suite void testMPTInvalidInTx(FeatureBitset features) { - testcase("MPT Amount Invalid in Transaction"); + testcase("MPT Issue Invalid in Transaction"); using namespace test::jtx; - // Validate that every transaction with an amount field, + // Validate that every transaction with an amount/issue field, // which doesn't support MPT, fails. - // keyed by transaction + amount field + // keyed by transaction + amount/issue field std::set txWithAmounts; for (auto const& format : TxFormats::getInstance()) { for (auto const& e : format.getSOTemplate()) { - // Transaction has amount fields. + // Transaction has amount/issue fields. // Exclude pseudo-transaction SetFee. Don't consider // the Fee field since it's included in every transaction. if (e.supportMPT() == soeMPTNotSupported && @@ -1508,9 +1508,9 @@ class MPToken_test : public beast::unit_test::suite env.fund(XRP(1'000), alice); env.fund(XRP(1'000), carol); auto test = [&](Json::Value const& jv, - std::string const& amtField) { + std::string const& mptField) { txWithAmounts.erase( - jv[jss::TransactionType].asString() + amtField); + jv[jss::TransactionType].asString() + mptField); // tx is signed auto jtx = env.jt(jv); @@ -1530,8 +1530,27 @@ class MPToken_test : public beast::unit_test::suite jrr = env.rpc("json", "sign", to_string(jv1)); BEAST_EXPECT(jrr[jss::result][jss::error] == "invalidParams"); }; - // All transactions with sfAmount, which don't support MPT - // and transactions with amount fields, which can't be MPT + auto toSFieldRef = [](SField const& field) { + return std::ref(field); + }; + auto setMPTFields = [&](SField const& field, + Json::Value& jv, + bool withAmount = true) { + jv[jss::Asset] = to_json(xrpIssue()); + jv[jss::Asset2] = to_json(USD.issue()); + if (withAmount) + jv[field.fieldName] = + USD(10).value().getJson(JsonOptions::none); + if (field == sfAsset) + jv[jss::Asset] = to_json(mpt.get()); + else if (field == sfAsset2) + jv[jss::Asset2] = to_json(mpt.get()); + else + jv[field.fieldName] = mpt.getJson(JsonOptions::none); + }; + // All transactions with sfAmount, which don't support MPT. + // Transactions with amount fields, which can't be MPT. + // Transactions with issue fields, which can't be MPT. // AMMCreate auto ammCreate = [&](SField const& field) { @@ -1554,58 +1573,84 @@ class MPToken_test : public beast::unit_test::suite Json::Value jv; jv[jss::TransactionType] = jss::AMMDeposit; jv[jss::Account] = alice.human(); - jv[jss::Asset] = to_json(xrpIssue()); - jv[jss::Asset2] = to_json(USD.issue()); - jv[field.fieldName] = mpt.getJson(JsonOptions::none); jv[jss::Flags] = tfSingleAsset; + setMPTFields(field, jv); test(jv, field.fieldName); }; for (SField const& field : - {std::ref(sfAmount), - std::ref(sfAmount2), - std::ref(sfEPrice), - std::ref(sfLPTokenOut)}) + {toSFieldRef(sfAmount), + toSFieldRef(sfAmount2), + toSFieldRef(sfEPrice), + toSFieldRef(sfLPTokenOut), + toSFieldRef(sfAsset), + toSFieldRef(sfAsset2)}) ammDeposit(field); // AMMWithdraw auto ammWithdraw = [&](SField const& field) { Json::Value jv; jv[jss::TransactionType] = jss::AMMWithdraw; jv[jss::Account] = alice.human(); - jv[jss::Asset] = to_json(xrpIssue()); - jv[jss::Asset2] = to_json(USD.issue()); jv[jss::Flags] = tfSingleAsset; - jv[field.fieldName] = mpt.getJson(JsonOptions::none); + setMPTFields(field, jv); test(jv, field.fieldName); }; ammWithdraw(sfAmount); for (SField const& field : - {std::ref(sfAmount2), - std::ref(sfEPrice), - std::ref(sfLPTokenIn)}) + {toSFieldRef(sfAmount2), + toSFieldRef(sfEPrice), + toSFieldRef(sfLPTokenIn), + toSFieldRef(sfAsset), + toSFieldRef(sfAsset2)}) ammWithdraw(field); // AMMBid auto ammBid = [&](SField const& field) { Json::Value jv; jv[jss::TransactionType] = jss::AMMBid; jv[jss::Account] = alice.human(); - jv[jss::Asset] = to_json(xrpIssue()); - jv[jss::Asset2] = to_json(USD.issue()); - jv[field.fieldName] = mpt.getJson(JsonOptions::none); + setMPTFields(field, jv); test(jv, field.fieldName); }; - ammBid(sfBidMin); - ammBid(sfBidMax); + for (SField const& field : + {toSFieldRef(sfBidMin), + toSFieldRef(sfBidMax), + toSFieldRef(sfAsset), + toSFieldRef(sfAsset2)}) + ammBid(field); // AMMClawback - { + auto ammClawback = [&](SField const& field) { Json::Value jv; jv[jss::TransactionType] = jss::AMMClawback; jv[jss::Account] = alice.human(); jv[jss::Holder] = carol.human(); - jv[jss::Asset] = to_json(xrpIssue()); - jv[jss::Asset2] = to_json(USD.issue()); - jv[jss::Amount] = mpt.getJson(JsonOptions::none); - test(jv, jss::Amount.c_str()); - } + setMPTFields(field, jv); + test(jv, field.fieldName); + }; + for (SField const& field : + {toSFieldRef(sfAmount), + toSFieldRef(sfAsset), + toSFieldRef(sfAsset2)}) + ammClawback(field); + // AMMDelete + auto ammDelete = [&](SField const& field) { + Json::Value jv; + jv[jss::TransactionType] = jss::AMMDelete; + jv[jss::Account] = alice.human(); + setMPTFields(field, jv, false); + test(jv, field.fieldName); + }; + ammDelete(sfAsset); + ammDelete(sfAsset2); + // AMMVote + auto ammVote = [&](SField const& field) { + Json::Value jv; + jv[jss::TransactionType] = jss::AMMVote; + jv[jss::Account] = alice.human(); + jv[jss::TradingFee] = 100; + setMPTFields(field, jv, false); + test(jv, field.fieldName); + }; + ammVote(sfAsset); + ammVote(sfAsset2); // CheckCash auto checkCash = [&](SField const& field) { Json::Value jv; diff --git a/src/test/basics/Expected_test.cpp b/src/test/basics/Expected_test.cpp index d60809aee1f..2f8b92eb916 100644 --- a/src/test/basics/Expected_test.cpp +++ b/src/test/basics/Expected_test.cpp @@ -84,6 +84,29 @@ struct Expected_test : beast::unit_test::suite } BEAST_EXPECT(throwOccurred); } + // Test non-error overlapping type construction. + { + auto expected = []() -> Expected { + return 1; + }(); + BEAST_EXPECT(expected); + BEAST_EXPECT(expected.has_value()); + BEAST_EXPECT(expected.value() == 1); + BEAST_EXPECT(*expected == 1); + + bool throwOccurred = false; + try + { + // There's no error, so should throw. + [[maybe_unused]] std::uint16_t const t = expected.error(); + } + catch (std::runtime_error const& e) + { + BEAST_EXPECT(e.what() == std::string("bad expected access")); + throwOccurred = true; + } + BEAST_EXPECT(throwOccurred); + } // Test error construction from rvalue. { auto const expected = []() -> Expected { diff --git a/src/test/basics/FeeUnits_test.cpp b/src/test/basics/FeeUnits_test.cpp index 6608a072621..c32f98f1929 100644 --- a/src/test/basics/FeeUnits_test.cpp +++ b/src/test/basics/FeeUnits_test.cpp @@ -16,8 +16,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include +#include #include #include diff --git a/src/test/basics/IOUAmount_test.cpp b/src/test/basics/IOUAmount_test.cpp index e588a08dc02..306953d5ab9 100644 --- a/src/test/basics/IOUAmount_test.cpp +++ b/src/test/basics/IOUAmount_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { diff --git a/src/test/basics/Number_test.cpp b/src/test/basics/Number_test.cpp index cf626354e0f..8a0a6702a63 100644 --- a/src/test/basics/Number_test.cpp +++ b/src/test/basics/Number_test.cpp @@ -17,9 +17,9 @@ */ //============================================================================== -#include #include #include +#include #include #include #include diff --git a/src/test/basics/XRPAmount_test.cpp b/src/test/basics/XRPAmount_test.cpp index c57890fcfa5..08745b61e32 100644 --- a/src/test/basics/XRPAmount_test.cpp +++ b/src/test/basics/XRPAmount_test.cpp @@ -17,8 +17,8 @@ */ //============================================================================== -#include #include +#include namespace ripple { diff --git a/src/test/csf/Tx.h b/src/test/csf/Tx.h index b21481dcbf9..f87f382167d 100644 --- a/src/test/csf/Tx.h +++ b/src/test/csf/Tx.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/src/test/jtx/amount.h b/src/test/jtx/amount.h index 9468b791f3d..9990c77c38c 100644 --- a/src/test/jtx/amount.h +++ b/src/test/jtx/amount.h @@ -23,8 +23,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/src/test/jtx/impl/amount.cpp b/src/test/jtx/impl/amount.cpp index 9f374c2cb58..5be53dc0a95 100644 --- a/src/test/jtx/impl/amount.cpp +++ b/src/test/jtx/impl/amount.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/src/test/jtx/impl/flags.cpp b/src/test/jtx/impl/flags.cpp index 992e1a88bb2..6658d3eba9b 100644 --- a/src/test/jtx/impl/flags.cpp +++ b/src/test/jtx/impl/flags.cpp @@ -41,7 +41,9 @@ void flags::operator()(Env& env) const { auto const sle = env.le(account_); - if (sle->isFieldPresent(sfFlags)) + if (!sle) + env.test.fail(); + else if (sle->isFieldPresent(sfFlags)) env.test.expect((sle->getFieldU32(sfFlags) & mask_) == mask_); else env.test.expect(mask_ == 0); @@ -51,7 +53,9 @@ void nflags::operator()(Env& env) const { auto const sle = env.le(account_); - if (sle->isFieldPresent(sfFlags)) + if (!sle) + env.test.fail(); + else if (sle->isFieldPresent(sfFlags)) env.test.expect((sle->getFieldU32(sfFlags) & mask_) == 0); else env.test.pass(); diff --git a/src/test/overlay/short_read_test.cpp b/src/test/overlay/short_read_test.cpp index 6dd4f8c00b8..0efc49b84e3 100644 --- a/src/test/overlay/short_read_test.cpp +++ b/src/test/overlay/short_read_test.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #include #include diff --git a/src/test/protocol/STIssue_test.cpp b/src/test/protocol/STIssue_test.cpp new file mode 100644 index 00000000000..4c9eeb0ba1b --- /dev/null +++ b/src/test/protocol/STIssue_test.cpp @@ -0,0 +1,164 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2024 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include + +namespace ripple { +namespace test { + +class STIssue_test : public beast::unit_test::suite +{ +public: + void + testConstructor() + { + testcase("Constructor"); + using namespace jtx; + Account const alice{"alice"}; + auto const USD = alice["USD"]; + Issue issue; + + try + { + issue = xrpIssue(); + issue.account = alice; + STIssue stissue(sfAsset, Asset{issue}); + fail("Inconsistent XRP Issue doesn't fail"); + } + catch (...) + { + pass(); + } + + try + { + issue = USD; + issue.account = xrpAccount(); + STIssue stissue(sfAsset, Asset{issue}); + fail("Inconsistent IOU Issue doesn't fail"); + } + catch (...) + { + pass(); + } + + try + { + // Currency is USD but account is XRP + auto const data = + "00000000000000000000000055534400000000000000000000000000000000" + "000000000000000000"; + base_uint<320> uint; + (void)uint.parseHex(data); + SerialIter iter(Slice(uint.data(), uint.size())); + STIssue stissue(iter, sfAsset); + fail("Inconsistent IOU Issue doesn't fail on serializer"); + } + catch (...) + { + pass(); + } + + try + { + STIssue stissue(sfAsset, Asset{xrpIssue()}); + } + catch (...) + { + fail("XRP issue failed"); + } + + try + { + STIssue stissue(sfAsset, Asset{USD}); + } + catch (...) + { + fail("USD issue failed"); + } + + try + { + auto const data = + "0000000000000000000000005553440000000000ae123a8556f3cf91154711" + "376afb0f894f832b3d"; + base_uint<320> uint; + (void)uint.parseHex(data); + SerialIter iter(Slice(uint.data(), uint.size())); + STIssue stissue(iter, sfAsset); + BEAST_EXPECT(stissue.value() == USD); + } + catch (...) + { + fail("USD Issue fails on serializer"); + } + + try + { + auto const data = "0000000000000000000000000000000000000000"; + base_uint<160> uint; + (void)uint.parseHex(data); + SerialIter iter(Slice(uint.data(), uint.size())); + STIssue stissue(iter, sfAsset); + BEAST_EXPECT(stissue.value() == xrpCurrency()); + } + catch (...) + { + fail("XRP Issue fails on serializer"); + } + } + + void + testCompare() + { + testcase("Compare"); + using namespace jtx; + Account const alice{"alice"}; + auto const USD = alice["USD"]; + Asset const asset1{xrpIssue()}; + Asset const asset2{USD}; + Asset const asset3{MPTID{2}}; + + BEAST_EXPECT(STIssue(sfAsset, asset1) != asset2); + BEAST_EXPECT(STIssue(sfAsset, asset1) != asset3); + BEAST_EXPECT(STIssue(sfAsset, asset1) == asset1); + BEAST_EXPECT(STIssue(sfAsset, asset1).getText() == "XRP"); + BEAST_EXPECT( + STIssue(sfAsset, asset2).getText() == + "USD/rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn"); + BEAST_EXPECT( + STIssue(sfAsset, asset3).getText() == + "000000000000000000000000000000000000000000000002"); + } + + void + run() override + { + // compliments other unit tests to ensure complete coverage + testConstructor(); + testCompare(); + } +}; + +BEAST_DEFINE_TESTSUITE(STIssue, ripple_data, ripple); + +} // namespace test +} // namespace ripple \ No newline at end of file diff --git a/src/test/protocol/types_test.cpp b/src/test/protocol/types_test.cpp index ac4314df640..8257d9c6495 100644 --- a/src/test/protocol/types_test.cpp +++ b/src/test/protocol/types_test.cpp @@ -28,8 +28,16 @@ struct types_test : public beast::unit_test::suite testAccountID() { auto const s = "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh"; - if (BEAST_EXPECT(parseBase58(s))) - BEAST_EXPECT(toBase58(*parseBase58(s)) == s); + if (auto const parsed = parseBase58(s); BEAST_EXPECT(parsed)) + { + BEAST_EXPECT(toBase58(*parsed) == s); + } + + { + auto const s = + "âabcd1rNxp4h8apvRis6mJf9Sh8C6iRxfrDWNâabcdAVâ\xc2\x80\xc2\x8f"; + BEAST_EXPECT(!parseBase58(s)); + } } void diff --git a/src/test/rpc/AccountSet_test.cpp b/src/test/rpc/AccountSet_test.cpp index e5475e3f530..3c6cad00e28 100644 --- a/src/test/rpc/AccountSet_test.cpp +++ b/src/test/rpc/AccountSet_test.cpp @@ -41,7 +41,7 @@ class AccountSet_test : public beast::unit_test::suite env.fund(XRP(10000), noripple(alice)); // ask for the ledger entry - account root, to check its flags auto const jrr = env.le(alice); - BEAST_EXPECT((*env.le(alice))[sfFlags] == 0u); + BEAST_EXPECT(jrr && jrr->at(sfFlags) == 0u); } void diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 41657468666..41b0239fb50 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -1877,160 +1877,164 @@ class LedgerRPC_test : public beast::unit_test::suite env(pay(gw, alice, USD(97))); env.close(); - std::string const ledgerHash{to_string(env.closed()->info().hash)}; - { - // Request the trust line using the accounts and currency. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - BEAST_EXPECT( - jrr[jss::node][sfBalance.jsonName][jss::value] == "-97"); - BEAST_EXPECT( - jrr[jss::node][sfHighLimit.jsonName][jss::value] == "999"); - } - { - // ripple_state is not an object. - Json::Value jvParams; - jvParams[jss::ripple_state] = "ripple_state"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state.currency is missing. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state accounts is not an array. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = 2; - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state one of the accounts is missing. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state more than 2 accounts. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::accounts][2u] = alice.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } + // check both aliases + for (auto const& fieldName : {jss::ripple_state, jss::state}) { - // ripple_state account[0] is not a string. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = 44; - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state account[1] is not a string. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = 21; - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state account[0] == account[1]. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = alice.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedRequest", ""); - } - { - // ripple_state malformed account[0]. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = - makeBadAddress(alice.human()); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedAddress", ""); - } - { - // ripple_state malformed account[1]. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = - makeBadAddress(gw.human()); - jvParams[jss::ripple_state][jss::currency] = "USD"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedAddress", ""); - } - { - // ripple_state malformed currency. - Json::Value jvParams; - jvParams[jss::ripple_state] = Json::objectValue; - jvParams[jss::ripple_state][jss::accounts] = Json::arrayValue; - jvParams[jss::ripple_state][jss::accounts][0u] = alice.human(); - jvParams[jss::ripple_state][jss::accounts][1u] = gw.human(); - jvParams[jss::ripple_state][jss::currency] = "USDollars"; - jvParams[jss::ledger_hash] = ledgerHash; - Json::Value const jrr = env.rpc( - "json", "ledger_entry", to_string(jvParams))[jss::result]; - checkErrorValue(jrr, "malformedCurrency", ""); + std::string const ledgerHash{to_string(env.closed()->info().hash)}; + { + // Request the trust line using the accounts and currency. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + BEAST_EXPECT( + jrr[jss::node][sfBalance.jsonName][jss::value] == "-97"); + BEAST_EXPECT( + jrr[jss::node][sfHighLimit.jsonName][jss::value] == "999"); + } + { + // ripple_state is not an object. + Json::Value jvParams; + jvParams[fieldName] = "ripple_state"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state.currency is missing. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state accounts is not an array. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = 2; + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state one of the accounts is missing. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state more than 2 accounts. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::accounts][2u] = alice.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state account[0] is not a string. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = 44; + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state account[1] is not a string. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = 21; + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state account[0] == account[1]. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = alice.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedRequest", ""); + } + { + // ripple_state malformed account[0]. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = + makeBadAddress(alice.human()); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedAddress", ""); + } + { + // ripple_state malformed account[1]. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = + makeBadAddress(gw.human()); + jvParams[fieldName][jss::currency] = "USD"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedAddress", ""); + } + { + // ripple_state malformed currency. + Json::Value jvParams; + jvParams[fieldName] = Json::objectValue; + jvParams[fieldName][jss::accounts] = Json::arrayValue; + jvParams[fieldName][jss::accounts][0u] = alice.human(); + jvParams[fieldName][jss::accounts][1u] = gw.human(); + jvParams[fieldName][jss::currency] = "USDollars"; + jvParams[jss::ledger_hash] = ledgerHash; + Json::Value const jrr = env.rpc( + "json", "ledger_entry", to_string(jvParams))[jss::result]; + checkErrorValue(jrr, "malformedCurrency", ""); + } } } @@ -3055,6 +3059,33 @@ class LedgerRPC_test : public beast::unit_test::suite } } + void + testLedgerEntryCLI() + { + testcase("ledger_entry command-line"); + using namespace test::jtx; + + Env env{*this}; + Account const alice{"alice"}; + env.fund(XRP(10000), alice); + env.close(); + + auto const checkId = keylet::check(env.master, env.seq(env.master)); + + env(check::create(env.master, alice, XRP(100))); + env.close(); + + std::string const ledgerHash{to_string(env.closed()->info().hash)}; + { + // Request a check. + Json::Value const jrr = + env.rpc("ledger_entry", to_string(checkId.key))[jss::result]; + BEAST_EXPECT( + jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check); + BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] == "100000000"); + } + } + public: void run() override @@ -3085,6 +3116,7 @@ class LedgerRPC_test : public beast::unit_test::suite testInvalidOracleLedgerEntry(); testOracleLedgerEntry(); testLedgerEntryMPT(); + testLedgerEntryCLI(); forAllApiVersions(std::bind_front( &LedgerRPC_test::testLedgerEntryInvalidParams, this)); diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 263d660d003..a746b30357d 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -92,7 +93,8 @@ RCLConsensus::Adaptor::Adaptor( std::numeric_limits::max() - 1)) , nUnlVote_(validatorKeys_.nodeID, j_) { - assert(valCookie_ != 0); + XRPL_ASSERT( + valCookie_, "ripple::RCLConsensus::Adaptor::Adaptor : nonzero cookie"); JLOG(j_.info()) << "Consensus engine started (cookie: " + std::to_string(valCookie_) + ")"; @@ -146,8 +148,12 @@ RCLConsensus::Adaptor::acquireLedger(LedgerHash const& hash) return std::nullopt; } - assert(!built->open() && built->isImmutable()); - assert(built->info().hash == hash); + XRPL_ASSERT( + !built->open() && built->isImmutable(), + "ripple::RCLConsensus::Adaptor::acquireLedger : valid ledger state"); + XRPL_ASSERT( + built->info().hash == hash, + "ripple::RCLConsensus::Adaptor::acquireLedger : ledger hash match"); // Notify inbound transactions of the new ledger sequence number inboundTransactions_.newRound(built->info().seq); @@ -673,8 +679,12 @@ RCLConsensus::Adaptor::doAccept( ledgerMaster_.switchLCL(built.ledger_); // Do these need to exist? - assert(ledgerMaster_.getClosedLedger()->info().hash == built.id()); - assert(app_.openLedger().current()->info().parentHash == built.id()); + XRPL_ASSERT( + ledgerMaster_.getClosedLedger()->info().hash == built.id(), + "ripple::RCLConsensus::Adaptor::doAccept : ledger hash match"); + XRPL_ASSERT( + app_.openLedger().current()->info().parentHash == built.id(), + "ripple::RCLConsensus::Adaptor::doAccept : parent hash match"); } //------------------------------------------------------------------------- @@ -770,7 +780,9 @@ RCLConsensus::Adaptor::buildLCL( std::shared_ptr built = [&]() { if (auto const replayData = ledgerMaster_.releaseReplay()) { - assert(replayData->parent()->info().hash == previousLedger.id()); + XRPL_ASSERT( + replayData->parent()->info().hash == previousLedger.id(), + "ripple::RCLConsensus::Adaptor::buildLCL : parent hash match"); return buildLedger(*replayData, tapNONE, app_, j_); } return buildLedger( diff --git a/src/xrpld/app/consensus/RCLCxPeerPos.cpp b/src/xrpld/app/consensus/RCLCxPeerPos.cpp index 74747853a2d..37f61a8c2d5 100644 --- a/src/xrpld/app/consensus/RCLCxPeerPos.cpp +++ b/src/xrpld/app/consensus/RCLCxPeerPos.cpp @@ -38,7 +38,9 @@ RCLCxPeerPos::RCLCxPeerPos( { // The maximum allowed size of a signature is 72 bytes; we verify // this elsewhere, but we want to be extra careful here: - assert(signature.size() != 0 && signature.size() <= signature_.capacity()); + XRPL_ASSERT( + signature.size() != 0 && signature.size() <= signature_.capacity(), + "ripple::RCLCxPeerPos::RCLCxPeerPos : valid signature size"); if (signature.size() != 0 && signature.size() <= signature_.capacity()) signature_.assign(signature.begin(), signature.end()); diff --git a/src/xrpld/app/consensus/RCLCxTx.h b/src/xrpld/app/consensus/RCLCxTx.h index 58e58ac3b7d..bbf3797887c 100644 --- a/src/xrpld/app/consensus/RCLCxTx.h +++ b/src/xrpld/app/consensus/RCLCxTx.h @@ -111,7 +111,8 @@ class RCLTxSet */ RCLTxSet(std::shared_ptr m) : map_{std::move(m)} { - assert(map_); + XRPL_ASSERT( + map_, "ripple::RCLTxSet::MutableTxSet::RCLTxSet : non-null input"); } /** Constructor from a previously created MutableTxSet @@ -177,7 +178,9 @@ class RCLTxSet std::map ret; for (auto const& [k, v] : delta) { - assert((v.first && !v.second) || (v.second && !v.first)); + XRPL_ASSERT( + (v.first && !v.second) || (v.second && !v.first), + "ripple::RCLTxSet::compare : either side is set"); ret[k] = static_cast(v.first); } diff --git a/src/xrpld/app/consensus/RCLValidations.cpp b/src/xrpld/app/consensus/RCLValidations.cpp index 096ec56df6f..c4d9389e896 100644 --- a/src/xrpld/app/consensus/RCLValidations.cpp +++ b/src/xrpld/app/consensus/RCLValidations.cpp @@ -50,7 +50,10 @@ RCLValidatedLedger::RCLValidatedLedger( auto const hashIndex = ledger->read(keylet::skip()); if (hashIndex) { - assert(hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1)); + XRPL_ASSERT( + hashIndex->getFieldU32(sfLastLedgerSequence) == (seq() - 1), + "ripple::RCLValidatedLedger::RCLValidatedLedger(Ledger) : valid " + "last ledger sequence"); ancestors_ = hashIndex->getFieldV256(sfHashes).value(); } else @@ -151,8 +154,12 @@ RCLValidationsAdaptor::acquire(LedgerHash const& hash) return std::nullopt; } - assert(!ledger->open() && ledger->isImmutable()); - assert(ledger->info().hash == hash); + XRPL_ASSERT( + !ledger->open() && ledger->isImmutable(), + "ripple::RCLValidationsAdaptor::acquire : valid ledger state"); + XRPL_ASSERT( + ledger->info().hash == hash, + "ripple::RCLValidationsAdaptor::acquire : ledger hash match"); return RCLValidatedLedger(std::move(ledger), j_); } @@ -191,7 +198,8 @@ handleNewValidation( { if (bypassAccept == BypassAccept::yes) { - assert(j.has_value()); + XRPL_ASSERT( + j, "ripple::handleNewValidation : journal is available"); if (j.has_value()) { JLOG(j->trace()) << "Bypassing checkAccept for validation " diff --git a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp index e1ad68dff37..6bdb602fd83 100644 --- a/src/xrpld/app/ledger/AcceptedLedgerTx.cpp +++ b/src/xrpld/app/ledger/AcceptedLedgerTx.cpp @@ -33,7 +33,9 @@ AcceptedLedgerTx::AcceptedLedgerTx( , mMeta(txn->getTransactionID(), ledger->seq(), *met) , mAffected(mMeta.getAffectedAccounts()) { - assert(!ledger->open()); + XRPL_ASSERT( + !ledger->open(), + "ripple::AcceptedLedgerTx::AcceptedLedgerTx : valid ledger state"); Serializer s; met->add(s); @@ -76,7 +78,9 @@ AcceptedLedgerTx::AcceptedLedgerTx( std::string AcceptedLedgerTx::getEscMeta() const { - assert(!mRawMeta.empty()); + XRPL_ASSERT( + !mRawMeta.empty(), + "ripple::AcceptedLedgerTx::getEscMeta : metadata is set"); return sqlBlobLiteral(mRawMeta); } diff --git a/src/xrpld/app/ledger/ConsensusTransSetSF.cpp b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp index 4aed7d94bf3..77a0370f7d9 100644 --- a/src/xrpld/app/ledger/ConsensusTransSetSF.cpp +++ b/src/xrpld/app/ledger/ConsensusTransSetSF.cpp @@ -60,7 +60,10 @@ ConsensusTransSetSF::gotNode( Serializer s(nodeData.data() + 4, nodeData.size() - 4); SerialIter sit(s.slice()); auto stx = std::make_shared(std::ref(sit)); - assert(stx->getTransactionID() == nodeHash.as_uint256()); + XRPL_ASSERT( + stx->getTransactionID() == nodeHash.as_uint256(), + "ripple::ConsensusTransSetSF::gotNode : transaction hash " + "match"); auto const pap = &app_; app_.getJobQueue().addJob(jtTRANSACTION, "TXS->TXN", [pap, stx]() { pap->getOPs().submitTransaction(stx); @@ -92,7 +95,9 @@ ConsensusTransSetSF::getNode(SHAMapHash const& nodeHash) const Serializer s; s.add32(HashPrefix::transactionID); txn->getSTransaction()->add(s); - assert(sha512Half(s.slice()) == nodeHash.as_uint256()); + XRPL_ASSERT( + sha512Half(s.slice()) == nodeHash.as_uint256(), + "ripple::ConsensusTransSetSF::getNode : transaction hash match"); nodeData = s.peekData(); return nodeData; } diff --git a/src/xrpld/app/ledger/Ledger.cpp b/src/xrpld/app/ledger/Ledger.cpp index 4991b551cd1..90e77c1e3d0 100644 --- a/src/xrpld/app/ledger/Ledger.cpp +++ b/src/xrpld/app/ledger/Ledger.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,6 @@ #include #include #include -#include #include #include @@ -369,7 +369,7 @@ Ledger::setAccepted( bool correctCloseTime) { // Used when we witnessed the consensus. - assert(!open()); + XRPL_ASSERT(!open(), "ripple::Ledger::setAccepted : valid ledger state"); info_.closeTime = closeTime; info_.closeTimeResolution = closeResolution; @@ -442,7 +442,7 @@ Ledger::read(Keylet const& k) const { if (k.key == beast::zero) { - assert(false); + UNREACHABLE("ripple::Ledger::read : zero key"); return nullptr; } auto const& item = stateMap_.peekItem(k.key); @@ -562,7 +562,8 @@ Ledger::rawTxInsert( std::shared_ptr const& txn, std::shared_ptr const& metaData) { - assert(metaData); + XRPL_ASSERT( + metaData, "ripple::Ledger::rawTxInsert : non-null metadata input"); // low-level - just add to table Serializer s(txn->getDataLength() + metaData->getDataLength() + 16); @@ -579,7 +580,9 @@ Ledger::rawTxInsertWithHash( std::shared_ptr const& txn, std::shared_ptr const& metaData) { - assert(metaData); + XRPL_ASSERT( + metaData, + "ripple::Ledger::rawTxInsertWithHash : non-null metadata input"); // low-level - just add to table Serializer s(txn->getDataLength() + metaData->getDataLength() + 16); @@ -675,7 +678,9 @@ Ledger::setup() void Ledger::defaultFees(Config const& config) { - assert(fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0); + XRPL_ASSERT( + fees_.base == 0 && fees_.reserve == 0 && fees_.increment == 0, + "ripple::Ledger::defaultFees : zero fees"); if (fees_.base == 0) fees_.base = config.FEES.reference_fee; if (fees_.reserve == 0) @@ -871,7 +876,7 @@ Ledger::assertSensible(beast::Journal ledgerJ) const JLOG(ledgerJ.fatal()) << "ledger is not sensible" << j; - assert(false); + UNREACHABLE("ripple::Ledger::assertSensible : ledger is not sensible"); return false; } @@ -905,7 +910,9 @@ Ledger::updateSkipList() created = false; } - assert(hashes.size() <= 256); + XRPL_ASSERT( + hashes.size() <= 256, + "ripple::Ledger::updateSkipList : first maximum hashes size"); hashes.push_back(info_.parentHash); sle->setFieldV256(sfHashes, STVector256(hashes)); sle->setFieldU32(sfLastLedgerSequence, prevIndex); @@ -930,7 +937,9 @@ Ledger::updateSkipList() hashes = static_cast(sle->getFieldV256(sfHashes)); created = false; } - assert(hashes.size() <= 256); + XRPL_ASSERT( + hashes.size() <= 256, + "ripple::Ledger::updateSkipList : second maximum hashes size"); if (hashes.size() == 256) hashes.erase(hashes.begin()); hashes.push_back(info_.parentHash); @@ -1010,7 +1019,8 @@ pendSaveValidated( } } - assert(ledger->isImmutable()); + XRPL_ASSERT( + ledger->isImmutable(), "ripple::pendSaveValidated : immutable ledger"); if (!app.pendingSaves().shouldWork(ledger->info().seq, isSynchronous)) { @@ -1087,9 +1097,10 @@ finishLoadByIndexOrHash( if (!ledger) return; - assert( + XRPL_ASSERT( ledger->info().seq < XRP_LEDGER_EARLIEST_FEES || - ledger->read(keylet::fees())); + ledger->read(keylet::fees()), + "ripple::finishLoadByIndexOrHash : valid ledger fees"); ledger->setImmutable(); JLOG(j.trace()) << "Loaded ledger: " << to_string(ledger->info().hash); @@ -1128,7 +1139,9 @@ loadByHash(uint256 const& ledgerHash, Application& app, bool acquire) { std::shared_ptr ledger = loadLedgerHelper(*info, app, acquire); finishLoadByIndexOrHash(ledger, app.config(), app.journal("Ledger")); - assert(!ledger || ledger->info().hash == ledgerHash); + XRPL_ASSERT( + !ledger || ledger->info().hash == ledgerHash, + "ripple::loadByHash : ledger hash match if loaded"); return ledger; } return {}; diff --git a/src/xrpld/app/ledger/LedgerHistory.cpp b/src/xrpld/app/ledger/LedgerHistory.cpp index b63cd84772a..ed0b11723b0 100644 --- a/src/xrpld/app/ledger/LedgerHistory.cpp +++ b/src/xrpld/app/ledger/LedgerHistory.cpp @@ -58,7 +58,9 @@ LedgerHistory::insert( if (!ledger->isImmutable()) LogicError("mutable Ledger in insert"); - assert(ledger->stateMap().getHash().isNonZero()); + XRPL_ASSERT( + ledger->stateMap().getHash().isNonZero(), + "ripple::LedgerHistory::insert : nonzero hash"); std::unique_lock sl(m_ledgers_by_hash.peekMutex()); @@ -99,13 +101,17 @@ LedgerHistory::getLedgerBySeq(LedgerIndex index) if (!ret) return ret; - assert(ret->info().seq == index); + XRPL_ASSERT( + ret->info().seq == index, + "ripple::LedgerHistory::getLedgerBySeq : result sequence match"); { // Add this ledger to the local tracking by index std::unique_lock sl(m_ledgers_by_hash.peekMutex()); - assert(ret->isImmutable()); + XRPL_ASSERT( + ret->isImmutable(), + "ripple::LedgerHistory::getLedgerBySeq : immutable result ledger"); m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret); mLedgersByIndex[ret->info().seq] = ret->info().hash; return (ret->info().seq == index) ? ret : nullptr; @@ -119,8 +125,14 @@ LedgerHistory::getLedgerByHash(LedgerHash const& hash) if (ret) { - assert(ret->isImmutable()); - assert(ret->info().hash == hash); + XRPL_ASSERT( + ret->isImmutable(), + "ripple::LedgerHistory::getLedgerByHash : immutable fetched " + "ledger"); + XRPL_ASSERT( + ret->info().hash == hash, + "ripple::LedgerHistory::getLedgerByHash : fetched ledger hash " + "match"); return ret; } @@ -129,10 +141,16 @@ LedgerHistory::getLedgerByHash(LedgerHash const& hash) if (!ret) return ret; - assert(ret->isImmutable()); - assert(ret->info().hash == hash); + XRPL_ASSERT( + ret->isImmutable(), + "ripple::LedgerHistory::getLedgerByHash : immutable loaded ledger"); + XRPL_ASSERT( + ret->info().hash == hash, + "ripple::LedgerHistory::getLedgerByHash : loaded ledger hash match"); m_ledgers_by_hash.canonicalize_replace_client(ret->info().hash, ret); - assert(ret->info().hash == hash); + XRPL_ASSERT( + ret->info().hash == hash, + "ripple::LedgerHistory::getLedgerByHash : result hash match"); return ret; } @@ -176,7 +194,9 @@ log_metadata_difference( auto validMetaData = getMeta(validLedger, tx); auto builtMetaData = getMeta(builtLedger, tx); - assert(validMetaData || builtMetaData); + XRPL_ASSERT( + validMetaData || builtMetaData, + "ripple::log_metadata_difference : some metadata present"); if (validMetaData && builtMetaData) { @@ -320,7 +340,9 @@ LedgerHistory::handleMismatch( std::optional const& validatedConsensusHash, Json::Value const& consensus) { - assert(built != valid); + XRPL_ASSERT( + built != valid, + "ripple::LedgerHistory::handleMismatch : unequal hashes"); ++mismatch_counter_; auto builtLedger = getLedgerByHash(built); @@ -335,7 +357,9 @@ LedgerHistory::handleMismatch( return; } - assert(builtLedger->info().seq == validLedger->info().seq); + XRPL_ASSERT( + builtLedger->info().seq == validLedger->info().seq, + "ripple::LedgerHistory::handleMismatch : sequence match"); if (auto stream = j_.debug()) { @@ -428,7 +452,8 @@ LedgerHistory::builtLedger( { LedgerIndex index = ledger->info().seq; LedgerHash hash = ledger->info().hash; - assert(!hash.isZero()); + XRPL_ASSERT( + !hash.isZero(), "ripple::LedgerHistory::builtLedger : nonzero hash"); std::unique_lock sl(m_consensus_validated.peekMutex()); @@ -468,7 +493,9 @@ LedgerHistory::validatedLedger( { LedgerIndex index = ledger->info().seq; LedgerHash hash = ledger->info().hash; - assert(!hash.isZero()); + XRPL_ASSERT( + !hash.isZero(), + "ripple::LedgerHistory::validatedLedger : nonzero hash"); std::unique_lock sl(m_consensus_validated.peekMutex()); diff --git a/src/xrpld/app/ledger/OpenLedger.h b/src/xrpld/app/ledger/OpenLedger.h index b218b1d6e11..95d4a7cb234 100644 --- a/src/xrpld/app/ledger/OpenLedger.h +++ b/src/xrpld/app/ledger/OpenLedger.h @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include namespace ripple { @@ -263,7 +263,8 @@ OpenLedger::apply( // If there are any transactions left, we must have // tried them in at least one final pass - assert(retries.empty() || !retry); + XRPL_ASSERT( + retries.empty() || !retry, "ripple::OpenLedger::apply : valid retries"); } //------------------------------------------------------------------------------ diff --git a/src/xrpld/app/ledger/OrderBookDB.cpp b/src/xrpld/app/ledger/OrderBookDB.cpp index d0eddadbacb..265e0b62905 100644 --- a/src/xrpld/app/ledger/OrderBookDB.cpp +++ b/src/xrpld/app/ledger/OrderBookDB.cpp @@ -129,8 +129,8 @@ OrderBookDB::update(std::shared_ptr const& ledger) } else if (sle->getType() == ltAMM) { - auto const issue1 = (*sle)[sfAsset]; - auto const issue2 = (*sle)[sfAsset2]; + auto const issue1 = (*sle)[sfAsset].get(); + auto const issue2 = (*sle)[sfAsset2].get(); auto addBook = [&](Issue const& in, Issue const& out) { allBooks[in].insert(out); @@ -225,7 +225,9 @@ OrderBookDB::makeBookListeners(Book const& book) ret = std::make_shared(); mListeners[book] = ret; - assert(getBookListeners(book) == ret); + XRPL_ASSERT( + getBookListeners(book) == ret, + "ripple::OrderBookDB::makeBookListeners : result roundtrip lookup"); } return ret; diff --git a/src/xrpld/app/ledger/TransactionStateSF.cpp b/src/xrpld/app/ledger/TransactionStateSF.cpp index fac28cd2aa8..30a4d2f8173 100644 --- a/src/xrpld/app/ledger/TransactionStateSF.cpp +++ b/src/xrpld/app/ledger/TransactionStateSF.cpp @@ -30,7 +30,9 @@ TransactionStateSF::gotNode( SHAMapNodeType type) const { - assert(type != SHAMapNodeType::tnTRANSACTION_NM); + XRPL_ASSERT( + type != SHAMapNodeType::tnTRANSACTION_NM, + "ripple::TransactionStateSF::gotNode : valid input"); db_.store( hotTRANSACTION_NODE, std::move(nodeData), diff --git a/src/xrpld/app/ledger/detail/BuildLedger.cpp b/src/xrpld/app/ledger/detail/BuildLedger.cpp index 8c4a7a3f41d..6e0fe75efe0 100644 --- a/src/xrpld/app/ledger/detail/BuildLedger.cpp +++ b/src/xrpld/app/ledger/detail/BuildLedger.cpp @@ -57,7 +57,8 @@ buildLedgerImpl( { OpenView accum(&*built); - assert(!accum.open()); + XRPL_ASSERT( + !accum.open(), "ripple::buildLedgerImpl : valid ledger state"); applyTxs(accum, built); accum.apply(*built); } @@ -75,9 +76,10 @@ buildLedgerImpl( built->unshare(); // Accept ledger - assert( + XRPL_ASSERT( built->info().seq < XRP_LEDGER_EARLIEST_FEES || - built->read(keylet::fees())); + built->read(keylet::fees()), + "ripple::buildLedgerImpl : valid ledger fees"); built->setAccepted(closeTime, closeResolution, closeTimeCorrect); return built; @@ -169,7 +171,9 @@ applyTransactions( // If there are any transactions left, we must have // tried them in at least one final pass - assert(txns.empty() || !certainRetry); + XRPL_ASSERT( + txns.empty() || !certainRetry, + "ripple::applyTransactions : retry transactions"); return count; } diff --git a/src/xrpld/app/ledger/detail/InboundLedger.cpp b/src/xrpld/app/ledger/detail/InboundLedger.cpp index 16b15c2fce7..4f25e917c19 100644 --- a/src/xrpld/app/ledger/detail/InboundLedger.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedger.cpp @@ -120,9 +120,10 @@ InboundLedger::init(ScopedLockType& collectionLock) JLOG(journal_.debug()) << "Acquiring ledger we already have in " << " local store. " << hash_; - assert( + XRPL_ASSERT( mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees())); + mLedger->read(keylet::fees()), + "ripple::InboundLedger::init : valid ledger fees"); mLedger->setImmutable(); if (mReason == Reason::HISTORY) @@ -351,9 +352,10 @@ InboundLedger::tryDB(NodeStore::Database& srcDB) { JLOG(journal_.debug()) << "Had everything locally"; complete_ = true; - assert( + XRPL_ASSERT( mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees())); + mLedger->read(keylet::fees()), + "ripple::InboundLedger::tryDB : valid ledger fees"); mLedger->setImmutable(); } } @@ -447,13 +449,16 @@ InboundLedger::done() std::to_string(timeouts_) + " ")) << mStats.get(); - assert(complete_ || failed_); + XRPL_ASSERT( + complete_ || failed_, + "ripple::InboundLedger::done : complete or failed"); if (complete_ && !failed_ && mLedger) { - assert( + XRPL_ASSERT( mLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - mLedger->read(keylet::fees())); + mLedger->read(keylet::fees()), + "ripple::InboundLedger::done : valid ledger fees"); mLedger->setImmutable(); switch (mReason) { @@ -613,7 +618,10 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) // if we wind up abandoning this fetch. if (mHaveHeader && !mHaveState && !failed_) { - assert(mLedger); + XRPL_ASSERT( + mLedger, + "ripple::InboundLedger::trigger : non-null ledger to read state " + "from"); if (!mLedger->stateMap().isValid()) { @@ -685,7 +693,10 @@ InboundLedger::trigger(std::shared_ptr const& peer, TriggerReason reason) if (mHaveHeader && !mHaveTransactions && !failed_) { - assert(mLedger); + XRPL_ASSERT( + mLedger, + "ripple::InboundLedger::trigger : non-null ledger to read " + "transactions from"); if (!mLedger->txMap().isValid()) { @@ -950,7 +961,7 @@ InboundLedger::takeAsRootNode(Slice const& data, SHAMapAddNode& san) if (!mHaveHeader) { - assert(false); + UNREACHABLE("ripple::InboundLedger::takeAsRootNode : no ledger header"); return false; } @@ -975,7 +986,7 @@ InboundLedger::takeTxRootNode(Slice const& data, SHAMapAddNode& san) if (!mHaveHeader) { - assert(false); + UNREACHABLE("ripple::InboundLedger::takeTxRootNode : no ledger header"); return false; } diff --git a/src/xrpld/app/ledger/detail/InboundLedgers.cpp b/src/xrpld/app/ledger/detail/InboundLedgers.cpp index f6d86a4d737..99a26ce8f9f 100644 --- a/src/xrpld/app/ledger/detail/InboundLedgers.cpp +++ b/src/xrpld/app/ledger/detail/InboundLedgers.cpp @@ -73,7 +73,9 @@ class InboundLedgersImp : public InboundLedgers InboundLedger::Reason reason) override { auto doAcquire = [&, seq, reason]() -> std::shared_ptr { - assert(hash.isNonZero()); + XRPL_ASSERT( + hash.isNonZero(), + "ripple::InboundLedgersImp::acquire::doAcquire : nonzero hash"); // probably not the right rule if (app_.getOPs().isNeedNetworkLedger() && @@ -162,7 +164,9 @@ class InboundLedgersImp : public InboundLedgers std::shared_ptr find(uint256 const& hash) override { - assert(hash.isNonZero()); + XRPL_ASSERT( + hash.isNonZero(), + "ripple::InboundLedgersImp::find : nonzero input"); std::shared_ptr ret; @@ -324,7 +328,9 @@ class InboundLedgersImp : public InboundLedgers acqs.reserve(mLedgers.size()); for (auto const& it : mLedgers) { - assert(it.second); + XRPL_ASSERT( + it.second, + "ripple::InboundLedgersImp::getInfo : non-null ledger"); acqs.push_back(it); } for (auto const& it : mRecentFailures) @@ -359,7 +365,10 @@ class InboundLedgersImp : public InboundLedgers acquires.reserve(mLedgers.size()); for (auto const& it : mLedgers) { - assert(it.second); + XRPL_ASSERT( + it.second, + "ripple::InboundLedgersImp::gotFetchPack : non-null " + "ledger"); acquires.push_back(it.second); } } diff --git a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp index 3021c691c53..27322e302cc 100644 --- a/src/xrpld/app/ledger/detail/LedgerCleaner.cpp +++ b/src/xrpld/app/ledger/detail/LedgerCleaner.cpp @@ -231,7 +231,9 @@ class LedgerCleanerImp : public LedgerCleaner }); if (shouldExit_) break; - assert(state_ == State::cleaning); + XRPL_ASSERT( + state_ == State::cleaning, + "ripple::LedgerCleanerImp::run : is cleaning"); } doLedgerCleaner(); } @@ -353,7 +355,9 @@ class LedgerCleanerImp : public LedgerCleaner LedgerHash refHash = getLedgerHash(referenceLedger, refIndex); bool const nonzero(refHash.isNonZero()); - assert(nonzero); + XRPL_ASSERT( + nonzero, + "ripple::LedgerCleanerImp::getHash : nonzero hash"); if (nonzero) { // We found the hash and sequence of a better reference diff --git a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp index e079fb3ee27..d312a09008a 100644 --- a/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp +++ b/src/xrpld/app/ledger/detail/LedgerDeltaAcquire.cpp @@ -199,8 +199,12 @@ LedgerDeltaAcquire::tryBuild(std::shared_ptr const& parent) if (failed_ || !complete_ || !replayTemp_) return {}; - assert(parent->seq() + 1 == replayTemp_->seq()); - assert(parent->info().hash == replayTemp_->info().parentHash); + XRPL_ASSERT( + parent->seq() + 1 == replayTemp_->seq(), + "ripple::LedgerDeltaAcquire::tryBuild : parent sequence match"); + XRPL_ASSERT( + parent->info().hash == replayTemp_->info().parentHash, + "ripple::LedgerDeltaAcquire::tryBuild : parent hash match"); // build ledger LedgerReplay replayData(parent, replayTemp_, std::move(orderedTxns_)); fullLedger_ = buildLedger(replayData, tapNONE, app_, journal_); @@ -262,7 +266,7 @@ LedgerDeltaAcquire::onLedgerBuilt( void LedgerDeltaAcquire::notify(ScopedLockType& sl) { - assert(isDone()); + XRPL_ASSERT(isDone(), "ripple::LedgerDeltaAcquire::notify : is done"); std::vector toCall; std::swap(toCall, dataReadyCallbacks_); auto const good = !failed_; diff --git a/src/xrpld/app/ledger/detail/LedgerMaster.cpp b/src/xrpld/app/ledger/detail/LedgerMaster.cpp index 53edef17d33..a302c4fb276 100644 --- a/src/xrpld/app/ledger/detail/LedgerMaster.cpp +++ b/src/xrpld/app/ledger/detail/LedgerMaster.cpp @@ -47,13 +47,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -276,9 +276,11 @@ LedgerMaster::setValidLedger(std::shared_ptr const& l) mValidLedger.set(l); mValidLedgerSign = signTime.time_since_epoch().count(); - assert( + XRPL_ASSERT( mValidLedgerSeq || !app_.getMaxDisallowedLedger() || - l->info().seq + max_ledger_difference_ > app_.getMaxDisallowedLedger()); + l->info().seq + max_ledger_difference_ > + app_.getMaxDisallowedLedger(), + "ripple::LedgerMaster::setValidLedger : valid ledger sequence"); (void)max_ledger_difference_; mValidLedgerSeq = l->info().seq; @@ -343,7 +345,7 @@ LedgerMaster::addHeldTransaction( bool LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) { - assert(ledger); + XRPL_ASSERT(ledger, "ripple::LedgerMaster::canBeCurrent : non-null input"); // Never jump to a candidate ledger that precedes our // last validated ledger @@ -411,7 +413,7 @@ LedgerMaster::canBeCurrent(std::shared_ptr const& ledger) void LedgerMaster::switchLCL(std::shared_ptr const& lastClosed) { - assert(lastClosed); + XRPL_ASSERT(lastClosed, "ripple::LedgerMaster::switchLCL : non-null input"); if (!lastClosed->isImmutable()) LogicError("mutable ledger in switchLCL"); @@ -528,7 +530,9 @@ LedgerMaster::isValidated(ReadView const& ledger) // This ledger's hash is not the hash of the validated ledger if (hash) { - assert(hash->isNonZero()); + XRPL_ASSERT( + hash->isNonZero(), + "ripple::LedgerMaster::isValidated : nonzero hash"); uint256 valHash = app_.getRelationalDatabase().getHashByIndex(seq); if (valHash == ledger.info().hash) @@ -818,7 +822,9 @@ LedgerMaster::setFullLedger( // A new ledger has been accepted as part of the trusted chain JLOG(m_journal.debug()) << "Ledger " << ledger->info().seq << " accepted :" << ledger->info().hash; - assert(ledger->stateMap().getHash().isNonZero()); + XRPL_ASSERT( + ledger->stateMap().getHash().isNonZero(), + "ripple::LedgerMaster::setFullLedger : nonzero ledger state hash"); ledger->setValidated(); ledger->setFull(); @@ -1282,7 +1288,9 @@ LedgerMaster::findNewLedgersToPublish( { JLOG(m_journal.fatal()) << "Ledger: " << valSeq << " does not have hash for " << seq; - assert(false); + UNREACHABLE( + "ripple::LedgerMaster::findNewLedgersToPublish : ledger " + "not found"); } else { @@ -1369,7 +1377,9 @@ LedgerMaster::tryAdvance() app_.getJobQueue().addJob(jtADVANCE, "advanceLedger", [this]() { std::unique_lock sl(m_mutex); - assert(!mValidLedger.empty() && mAdvanceThread); + XRPL_ASSERT( + !mValidLedger.empty() && mAdvanceThread, + "ripple::LedgerMaster::tryAdvance : has valid ledger"); JLOG(m_journal.trace()) << "advanceThread<"; @@ -1670,7 +1680,7 @@ LedgerMaster::walkHashBySeq( // be located easily and should contain the hash. LedgerIndex refIndex = getCandidateLedger(index); auto const refHash = hashOfSeq(*referenceLedger, refIndex, m_journal); - assert(refHash); + XRPL_ASSERT(refHash, "ripple::LedgerMaster::walkHashBySeq : found ledger"); if (refHash) { // Try the hash and sequence of a better reference ledger just found @@ -1695,7 +1705,10 @@ LedgerMaster::walkHashBySeq( *refHash, refIndex, reason)) { ledgerHash = hashOfSeq(*l, index, m_journal); - assert(ledgerHash); + XRPL_ASSERT( + ledgerHash, + "ripple::LedgerMaster::walkHashBySeq : has complete " + "ledger"); } } } @@ -1807,7 +1820,9 @@ LedgerMaster::fetchForHistory( scope_unlock sul{sl}; if (auto hash = getLedgerHashForHistory(missing, reason)) { - assert(hash->isNonZero()); + XRPL_ASSERT( + hash->isNonZero(), + "ripple::LedgerMaster::fetchForHistory : found ledger"); auto ledger = getLedgerByHash(*hash); if (!ledger) { @@ -1834,7 +1849,9 @@ LedgerMaster::fetchForHistory( if (ledger) { auto seq = ledger->info().seq; - assert(seq == missing); + XRPL_ASSERT( + seq == missing, + "ripple::LedgerMaster::fetchForHistory : sequence match"); JLOG(m_journal.trace()) << "fetchForHistory acquired " << seq; setFullLedger(ledger, false, false); int fillInProgress; @@ -1875,7 +1892,10 @@ LedgerMaster::fetchForHistory( std::uint32_t seq = missing - i; if (auto h = getLedgerHashForHistory(seq, reason)) { - assert(h->isNonZero()); + XRPL_ASSERT( + h->isNonZero(), + "ripple::LedgerMaster::fetchForHistory : " + "prefetched ledger"); app_.getInboundLedgers().acquire(*h, seq, reason); } } @@ -2061,7 +2081,7 @@ populateFetchPack( std::uint32_t seq, bool withLeaves = true) { - assert(cnt != 0); + XRPL_ASSERT(cnt, "ripple::populateFetchPack : nonzero count input"); Serializer s(1024); diff --git a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp index d7f29e33b3b..164fbf8cc5a 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayTask.cpp @@ -32,7 +32,10 @@ LedgerReplayTask::TaskParameter::TaskParameter( std::uint32_t totalNumLedgers) : reason_(r), finishHash_(finishLedgerHash), totalLedgers_(totalNumLedgers) { - assert(finishLedgerHash.isNonZero() && totalNumLedgers > 0); + XRPL_ASSERT( + finishLedgerHash.isNonZero() && totalNumLedgers > 0, + "ripple::LedgerReplayTask::TaskParameter::TaskParameter : valid " + "inputs"); } bool @@ -48,7 +51,9 @@ LedgerReplayTask::TaskParameter::update( skipList_ = sList; skipList_.emplace_back(finishHash_); startHash_ = skipList_[skipList_.size() - totalLedgers_]; - assert(startHash_.isNonZero()); + XRPL_ASSERT( + startHash_.isNonZero(), + "ripple::LedgerReplayTask::TaskParameter::update : nonzero start hash"); startSeq_ = finishSeq_ - totalLedgers_ + 1; full_ = true; return true; @@ -200,7 +205,9 @@ LedgerReplayTask::tryAdvance(ScopedLockType& sl) for (; deltaToBuild_ < deltas_.size(); ++deltaToBuild_) { auto& delta = deltas_[deltaToBuild_]; - assert(parent_->seq() + 1 == delta->ledgerSeq_); + XRPL_ASSERT( + parent_->seq() + 1 == delta->ledgerSeq_, + "ripple::LedgerReplayTask::tryAdvance : consecutive sequence"); if (auto l = delta->tryBuild(parent_); l) { JLOG(journal_.debug()) @@ -289,9 +296,11 @@ LedgerReplayTask::addDelta(std::shared_ptr const& delta) JLOG(journal_.trace()) << "addDelta task " << hash_ << " deltaIndex=" << deltaToBuild_ << " totalDeltas=" << deltas_.size(); - assert( + XRPL_ASSERT( deltas_.empty() || - deltas_.back()->ledgerSeq_ + 1 == delta->ledgerSeq_); + deltas_.back()->ledgerSeq_ + 1 == delta->ledgerSeq_, + "ripple::LedgerReplayTask::addDelta : no deltas or consecutive " + "sequence", ); deltas_.push_back(delta); } } diff --git a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp index 4aa0e4beb79..3ef3201567a 100644 --- a/src/xrpld/app/ledger/detail/LedgerReplayer.cpp +++ b/src/xrpld/app/ledger/detail/LedgerReplayer.cpp @@ -47,9 +47,10 @@ LedgerReplayer::replay( uint256 const& finishLedgerHash, std::uint32_t totalNumLedgers) { - assert( + XRPL_ASSERT( finishLedgerHash.isNonZero() && totalNumLedgers > 0 && - totalNumLedgers <= LedgerReplayParameters::MAX_TASK_SIZE); + totalNumLedgers <= LedgerReplayParameters::MAX_TASK_SIZE, + "ripple::LedgerReplayer::replay : valid inputs"); LedgerReplayTask::TaskParameter parameter( r, finishLedgerHash, totalNumLedgers); diff --git a/src/xrpld/app/ledger/detail/SkipListAcquire.cpp b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp index 1d1de62b61b..912c29a9f67 100644 --- a/src/xrpld/app/ledger/detail/SkipListAcquire.cpp +++ b/src/xrpld/app/ledger/detail/SkipListAcquire.cpp @@ -139,7 +139,9 @@ SkipListAcquire::processData( std::uint32_t ledgerSeq, boost::intrusive_ptr const& item) { - assert(ledgerSeq != 0 && item); + XRPL_ASSERT( + ledgerSeq != 0 && item, + "ripple::SkipListAcquire::processData : valid inputs"); ScopedLockType sl(mtx_); if (isDone()) return; @@ -224,7 +226,7 @@ SkipListAcquire::onSkipListAcquired( void SkipListAcquire::notify(ScopedLockType& sl) { - assert(isDone()); + XRPL_ASSERT(isDone(), "ripple::SkipListAcquire::notify : is done"); std::vector toCall; std::swap(toCall, dataReadyCallbacks_); auto const good = !failed_; diff --git a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp index f70e54f8cd4..35d8f1fffb1 100644 --- a/src/xrpld/app/ledger/detail/TimeoutCounter.cpp +++ b/src/xrpld/app/ledger/detail/TimeoutCounter.cpp @@ -43,7 +43,9 @@ TimeoutCounter::TimeoutCounter( , queueJobParameter_(std::move(jobParameter)) , timer_(app_.getIOService()) { - assert((timerInterval_ > 10ms) && (timerInterval_ < 30s)); + XRPL_ASSERT( + (timerInterval_ > 10ms) && (timerInterval_ < 30s), + "ripple::TimeoutCounter::TimeoutCounter : interval input inside range"); } void diff --git a/src/xrpld/app/main/Application.cpp b/src/xrpld/app/main/Application.cpp index a9d66679010..f950e7b6c97 100644 --- a/src/xrpld/app/main/Application.cpp +++ b/src/xrpld/app/main/Application.cpp @@ -586,7 +586,10 @@ class ApplicationImp : public Application, public BasicApp virtual ServerHandler& getServerHandler() override { - assert(serverHandler_); + XRPL_ASSERT( + serverHandler_, + "ripple::ApplicationImp::getServerHandler : non-null server " + "handle"); return *serverHandler_; } @@ -792,28 +795,36 @@ class ApplicationImp : public Application, public BasicApp Overlay& overlay() override { - assert(overlay_); + XRPL_ASSERT( + overlay_, "ripple::ApplicationImp::overlay : non-null overlay"); return *overlay_; } TxQ& getTxQ() override { - assert(txQ_.get() != nullptr); + XRPL_ASSERT( + txQ_, + "ripple::ApplicationImp::getTxQ : non-null transaction queue"); return *txQ_; } RelationalDatabase& getRelationalDatabase() override { - assert(mRelationalDatabase.get() != nullptr); + XRPL_ASSERT( + mRelationalDatabase, + "ripple::ApplicationImp::getRelationalDatabase : non-null " + "relational database"); return *mRelationalDatabase; } DatabaseCon& getWalletDB() override { - assert(mWalletDB.get() != nullptr); + XRPL_ASSERT( + mWalletDB, + "ripple::ApplicationImp::getWalletDB : non-null wallet database"); return *mWalletDB; } @@ -828,7 +839,10 @@ class ApplicationImp : public Application, public BasicApp bool initRelationalDatabase() { - assert(mWalletDB.get() == nullptr); + XRPL_ASSERT( + mWalletDB.get() == nullptr, + "ripple::ApplicationImp::initRelationalDatabase : null wallet " + "database"); try { @@ -1230,7 +1244,8 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline) for (auto const& [a, vote] : amendments) { auto const f = ripple::getRegisteredFeature(a); - assert(f); + XRPL_ASSERT( + f, "ripple::ApplicationImp::setup : registered feature"); if (f) supported.emplace_back(a, *f, vote); } @@ -1693,9 +1708,10 @@ ApplicationImp::startGenesisLedger() auto const next = std::make_shared(*genesis, timeKeeper().closeTime()); next->updateSkipList(); - assert( + XRPL_ASSERT( next->info().seq < XRP_LEDGER_EARLIEST_FEES || - next->read(keylet::fees())); + next->read(keylet::fees()), + "ripple::ApplicationImp::startGenesisLedger : valid ledger fees"); next->setImmutable(); openLedger_.emplace(next, cachedSLEs_, logs_->journal("OpenLedger")); m_ledgerMaster->storeLedger(next); @@ -1714,9 +1730,10 @@ ApplicationImp::getLastFullLedger() if (!ledger) return ledger; - assert( + XRPL_ASSERT( ledger->info().seq < XRP_LEDGER_EARLIEST_FEES || - ledger->read(keylet::fees())); + ledger->read(keylet::fees()), + "ripple::ApplicationImp::getLastFullLedger : valid ledger fees"); ledger->setImmutable(); if (getLedgerMaster().haveLedger(seq)) @@ -1868,9 +1885,10 @@ ApplicationImp::loadLedgerFromFile(std::string const& name) loadLedger->stateMap().flushDirty(hotACCOUNT_NODE); - assert( + XRPL_ASSERT( loadLedger->info().seq < XRP_LEDGER_EARLIEST_FEES || - loadLedger->read(keylet::fees())); + loadLedger->read(keylet::fees()), + "ripple::ApplicationImp::loadLedgerFromFile : valid ledger fees"); loadLedger->setAccepted( closeTime, closeTimeResolution, !closeTimeEstimated); @@ -1968,7 +1986,9 @@ ApplicationImp::loadOldLedger( if (!loadLedger) { JLOG(m_journal.fatal()) << "Replay ledger missing/damaged"; - assert(false); + UNREACHABLE( + "ripple::ApplicationImp::loadOldLedger : replay ledger " + "missing/damaged"); return false; } } @@ -1997,21 +2017,26 @@ ApplicationImp::loadOldLedger( if (loadLedger->info().accountHash.isZero()) { JLOG(m_journal.fatal()) << "Ledger is empty."; - assert(false); + UNREACHABLE( + "ripple::ApplicationImp::loadOldLedger : ledger is empty"); return false; } if (!loadLedger->walkLedger(journal("Ledger"), true)) { JLOG(m_journal.fatal()) << "Ledger is missing nodes."; - assert(false); + UNREACHABLE( + "ripple::ApplicationImp::loadOldLedger : ledger is missing " + "nodes"); return false; } if (!loadLedger->assertSensible(journal("Ledger"))) { JLOG(m_journal.fatal()) << "Ledger is not sensible."; - assert(false); + UNREACHABLE( + "ripple::ApplicationImp::loadOldLedger : ledger is not " + "sensible"); return false; } diff --git a/src/xrpld/app/main/GRPCServer.cpp b/src/xrpld/app/main/GRPCServer.cpp index 5a231dfc9e6..a7280a7688c 100644 --- a/src/xrpld/app/main/GRPCServer.cpp +++ b/src/xrpld/app/main/GRPCServer.cpp @@ -606,7 +606,7 @@ GRPCServer::stop() GRPCServer::~GRPCServer() { - assert(!running_); + XRPL_ASSERT(!running_, "ripple::GRPCServer::~GRPCServer : is not running"); } } // namespace ripple diff --git a/src/xrpld/app/main/LoadManager.cpp b/src/xrpld/app/main/LoadManager.cpp index f5dd8719470..01b96a3d26c 100644 --- a/src/xrpld/app/main/LoadManager.cpp +++ b/src/xrpld/app/main/LoadManager.cpp @@ -73,7 +73,9 @@ void LoadManager::start() { JLOG(journal_.debug()) << "Starting"; - assert(!thread_.joinable()); + XRPL_ASSERT( + !thread_.joinable(), + "ripple::LoadManager::start : thread not joinable"); thread_ = std::thread{&LoadManager::run, this}; } diff --git a/src/xrpld/app/main/Main.cpp b/src/xrpld/app/main/Main.cpp index 169a6dad912..2b47ac9795b 100644 --- a/src/xrpld/app/main/Main.cpp +++ b/src/xrpld/app/main/Main.cpp @@ -69,6 +69,10 @@ #error Multiple supported platforms appear active at once #endif +#ifdef ENABLE_VOIDSTAR +#include "antithesis_instrumentation.h" +#endif + namespace po = boost::program_options; namespace ripple { diff --git a/src/xrpld/app/main/NodeStoreScheduler.cpp b/src/xrpld/app/main/NodeStoreScheduler.cpp index bf07e559fd3..f2dce5421f0 100644 --- a/src/xrpld/app/main/NodeStoreScheduler.cpp +++ b/src/xrpld/app/main/NodeStoreScheduler.cpp @@ -18,7 +18,7 @@ //============================================================================== #include -#include +#include namespace ripple { diff --git a/src/xrpld/app/misc/AMMHelpers.h b/src/xrpld/app/misc/AMMHelpers.h index 7ad0093a2e4..c6c0c808bfe 100644 --- a/src/xrpld/app/misc/AMMHelpers.h +++ b/src/xrpld/app/misc/AMMHelpers.h @@ -20,13 +20,13 @@ #ifndef RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED #define RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED -#include #include #include #include #include #include #include +#include #include #include #include diff --git a/src/xrpld/app/misc/FeeVoteImpl.cpp b/src/xrpld/app/misc/FeeVoteImpl.cpp index cb4e57b0f73..95160f398a1 100644 --- a/src/xrpld/app/misc/FeeVoteImpl.cpp +++ b/src/xrpld/app/misc/FeeVoteImpl.cpp @@ -200,7 +200,9 @@ FeeVoteImpl::doVoting( std::shared_ptr const& initialPosition) { // LCL must be flag ledger - assert(lastClosedLedger && isFlagLedger(lastClosedLedger->seq())); + XRPL_ASSERT( + lastClosedLedger && isFlagLedger(lastClosedLedger->seq()), + "ripple::FeeVoteImpl::doVoting : has a flag ledger"); detail::VotableValue baseFeeVote( lastClosedLedger->fees().base, target_.reference_fee); diff --git a/src/xrpld/app/misc/HashRouter.cpp b/src/xrpld/app/misc/HashRouter.cpp index c117d20fe2b..58e811d4b8f 100644 --- a/src/xrpld/app/misc/HashRouter.cpp +++ b/src/xrpld/app/misc/HashRouter.cpp @@ -101,7 +101,7 @@ HashRouter::getFlags(uint256 const& key) bool HashRouter::setFlags(uint256 const& key, int flags) { - assert(flags != 0); + XRPL_ASSERT(flags, "ripple::HashRouter::setFlags : valid input"); std::lock_guard lock(mutex_); diff --git a/src/xrpld/app/misc/LoadFeeTrack.h b/src/xrpld/app/misc/LoadFeeTrack.h index 6c37864e2fd..875a7bb7dfa 100644 --- a/src/xrpld/app/misc/LoadFeeTrack.h +++ b/src/xrpld/app/misc/LoadFeeTrack.h @@ -20,10 +20,11 @@ #ifndef RIPPLE_CORE_LOADFEETRACK_H_INCLUDED #define RIPPLE_CORE_LOADFEETRACK_H_INCLUDED -#include #include #include #include +#include +#include #include #include #include diff --git a/src/xrpld/app/misc/NegativeUNLVote.cpp b/src/xrpld/app/misc/NegativeUNLVote.cpp index 45d72bcd2b3..471c9374728 100644 --- a/src/xrpld/app/misc/NegativeUNLVote.cpp +++ b/src/xrpld/app/misc/NegativeUNLVote.cpp @@ -89,7 +89,9 @@ NegativeUNLVote::doVoting( { auto n = choose(prevLedger->info().hash, candidates.toDisableCandidates); - assert(nidToKeyMap.count(n)); + XRPL_ASSERT( + nidToKeyMap.contains(n), + "ripple::NegativeUNLVote::doVoting : found node to disable"); addTx(seq, nidToKeyMap.at(n), ToDisable, initialSet); } @@ -97,7 +99,9 @@ NegativeUNLVote::doVoting( { auto n = choose( prevLedger->info().hash, candidates.toReEnableCandidates); - assert(nidToKeyMap.count(n)); + XRPL_ASSERT( + nidToKeyMap.contains(n), + "ripple::NegativeUNLVote::doVoting : found node to enable"); addTx(seq, nidToKeyMap.at(n), ToReEnable, initialSet); } } @@ -140,7 +144,9 @@ NegativeUNLVote::choose( uint256 const& randomPadData, std::vector const& candidates) { - assert(!candidates.empty()); + XRPL_ASSERT( + !candidates.empty(), + "ripple::NegativeUNLVote::choose : non-empty input"); static_assert(NodeID::bytes <= uint256::bytes); NodeID randomPad = NodeID::fromVoid(randomPadData.data()); NodeID txNodeID = candidates[0]; diff --git a/src/xrpld/app/misc/NetworkOPs.cpp b/src/xrpld/app/misc/NetworkOPs.cpp index d647df91f1e..8e483811145 100644 --- a/src/xrpld/app/misc/NetworkOPs.cpp +++ b/src/xrpld/app/misc/NetworkOPs.cpp @@ -105,7 +105,10 @@ class NetworkOPsImp final : public NetworkOPs FailHard f) : transaction(t), admin(a), local(l), failType(f) { - assert(local || failType == FailHard::no); + XRPL_ASSERT( + local || failType == FailHard::no, + "ripple::NetworkOPsImp::TransactionStatus::TransactionStatus : " + "valid inputs"); } }; @@ -1210,7 +1213,9 @@ NetworkOPsImp::processTransaction( *transaction->getSTransaction(), view->rules(), app_.config()); - assert(validity == Validity::Valid); + XRPL_ASSERT( + validity == Validity::Valid, + "ripple::NetworkOPsImp::processTransaction : valid validity"); // Not concerned with local checks at this point. if (validity == Validity::SigBad) @@ -1316,9 +1321,13 @@ NetworkOPsImp::apply(std::unique_lock& batchLock) std::vector submit_held; std::vector transactions; mTransactions.swap(transactions); - assert(!transactions.empty()); + XRPL_ASSERT( + !transactions.empty(), + "ripple::NetworkOPsImp::apply : non-empty transactions"); + XRPL_ASSERT( + mDispatchState != DispatchState::running, + "ripple::NetworkOPsImp::apply : is not running"); - assert(mDispatchState != DispatchState::running); mDispatchState = DispatchState::running; batchLock.unlock(); @@ -1534,7 +1543,9 @@ NetworkOPsImp::getOwnerInfo( for (auto const& uDirEntry : sleNode->getFieldV256(sfIndexes)) { auto sleCur = lpLedger->read(keylet::child(uDirEntry)); - assert(sleCur); + XRPL_ASSERT( + sleCur, + "ripple::NetworkOPsImp::getOwnerInfo : non-null child SLE"); switch (sleCur->getType()) { @@ -1561,7 +1572,9 @@ NetworkOPsImp::getOwnerInfo( case ltACCOUNT_ROOT: case ltDIR_NODE: default: - assert(false); + UNREACHABLE( + "ripple::NetworkOPsImp::getOwnerInfo : invalid " + "type"); break; } } @@ -1571,7 +1584,9 @@ NetworkOPsImp::getOwnerInfo( if (uNodeDir) { sleNode = lpLedger->read(keylet::page(root, uNodeDir)); - assert(sleNode); + XRPL_ASSERT( + sleNode, + "ripple::NetworkOPsImp::getOwnerInfo : read next page"); } } while (uNodeDir); } @@ -1802,7 +1817,9 @@ NetworkOPsImp::switchLastClosedLedger( bool NetworkOPsImp::beginConsensus(uint256 const& networkClosed) { - assert(networkClosed.isNonZero()); + XRPL_ASSERT( + networkClosed.isNonZero(), + "ripple::NetworkOPsImp::beginConsensus : nonzero input"); auto closingInfo = m_ledgerMaster.getCurrentLedger()->info(); @@ -1823,10 +1840,14 @@ NetworkOPsImp::beginConsensus(uint256 const& networkClosed) return false; } - assert(prevLedger->info().hash == closingInfo.parentHash); - assert( - closingInfo.parentHash == - m_ledgerMaster.getClosedLedger()->info().hash); + XRPL_ASSERT( + prevLedger->info().hash == closingInfo.parentHash, + "ripple::NetworkOPsImp::beginConsensus : prevLedger hash matches " + "parent"); + XRPL_ASSERT( + closingInfo.parentHash == m_ledgerMaster.getClosedLedger()->info().hash, + "ripple::NetworkOPsImp::beginConsensus : closedLedger parent matches " + "hash"); if (prevLedger->rules().enabled(featureNegativeUNL)) app_.validators().setNegativeUNL(prevLedger->negativeUNL()); @@ -2799,7 +2820,9 @@ NetworkOPsImp::pubLedger(std::shared_ptr const& lpAccepted) lpAccepted->info().hash, alpAccepted); } - assert(alpAccepted->getLedger().get() == lpAccepted.get()); + XRPL_ASSERT( + alpAccepted->getLedger().get() == lpAccepted.get(), + "ripple::NetworkOPsImp::pubLedger : accepted input"); { JLOG(m_journal.debug()) @@ -3202,9 +3225,11 @@ NetworkOPsImp::pubAccountTransaction( if (last) jvObj.set(jss::account_history_boundary, true); - assert( + XRPL_ASSERT( jvObj.isMember(jss::account_history_tx_stream) == - MultiApiJson::none); + MultiApiJson::none, + "ripple::NetworkOPsImp::pubAccountTransaction : " + "account_history_tx_stream not set"); for (auto& info : accountHistoryNotify) { auto& index = info.index_; @@ -3277,9 +3302,11 @@ NetworkOPsImp::pubProposedAccountTransaction( isrListener->getApiVersion(), // [&](Json::Value const& jv) { isrListener->send(jv, true); }); - assert( + XRPL_ASSERT( jvObj.isMember(jss::account_history_tx_stream) == - MultiApiJson::none); + MultiApiJson::none, + "ripple::NetworkOPs::pubProposedAccountTransaction : " + "account_history_tx_stream not set"); for (auto& info : accountHistoryNotify) { auto& index = info.index_; @@ -3500,7 +3527,9 @@ NetworkOPsImp::addAccountHistoryJob(SubAccountHistoryInfoWeak subInfo) return db->newestAccountTxPage(options); } default: { - assert(false); + UNREACHABLE( + "ripple::NetworkOPsImp::addAccountHistoryJob::" + "getMoreTxns : invalid database type"); return {}; } } @@ -3696,7 +3725,9 @@ NetworkOPsImp::subAccountHistoryStart( } else { - assert(false); + UNREACHABLE( + "ripple::NetworkOPsImp::subAccountHistoryStart : failed to " + "access genesis account"); return; } } @@ -3804,7 +3835,7 @@ NetworkOPsImp::subBook(InfoSub::ref isrListener, Book const& book) if (auto listeners = app_.getOrderBookDB().makeBookListeners(book)) listeners->addSubscriber(isrListener); else - assert(false); + UNREACHABLE("ripple::NetworkOPsImp::subBook : null book listeners"); return true; } @@ -3823,7 +3854,8 @@ NetworkOPsImp::acceptLedger( { // This code-path is exclusively used when the server is in standalone // mode via `ledger_accept` - assert(m_standalone); + XRPL_ASSERT( + m_standalone, "ripple::NetworkOPsImp::acceptLedger : is standalone"); if (!m_standalone) Throw( diff --git a/src/xrpld/app/misc/SHAMapStoreImp.cpp b/src/xrpld/app/misc/SHAMapStoreImp.cpp index 1ce862b095f..3a530e0e410 100644 --- a/src/xrpld/app/misc/SHAMapStoreImp.cpp +++ b/src/xrpld/app/misc/SHAMapStoreImp.cpp @@ -513,7 +513,9 @@ SHAMapStoreImp::clearSql( std::function()> const& getMinSeq, std::function const& deleteBeforeSeq) { - assert(deleteInterval_); + XRPL_ASSERT( + deleteInterval_, + "ripple::SHAMapStoreImp::clearSql : nonzero delete interval"); LedgerIndex min = std::numeric_limits::max(); { diff --git a/src/xrpld/app/misc/detail/AMMHelpers.cpp b/src/xrpld/app/misc/detail/AMMHelpers.cpp index f10b4c15eb0..8724c413a68 100644 --- a/src/xrpld/app/misc/detail/AMMHelpers.cpp +++ b/src/xrpld/app/misc/detail/AMMHelpers.cpp @@ -209,7 +209,9 @@ adjustAmountsByLPTokens( return std::make_tuple(amountActual, std::nullopt, lpTokensActual); } - assert(lpTokensActual == lpTokens); + XRPL_ASSERT( + lpTokensActual == lpTokens, + "ripple::adjustAmountsByLPTokens : LP tokens match actual"); return {amount, amount2, lpTokensActual}; } diff --git a/src/xrpld/app/misc/detail/AMMUtils.cpp b/src/xrpld/app/misc/detail/AMMUtils.cpp index efc80cf17b6..f5f6ae6612c 100644 --- a/src/xrpld/app/misc/detail/AMMUtils.cpp +++ b/src/xrpld/app/misc/detail/AMMUtils.cpp @@ -51,8 +51,8 @@ ammHolds( beast::Journal const j) { auto const issues = [&]() -> std::optional> { - auto const issue1 = ammSle[sfAsset]; - auto const issue2 = ammSle[sfAsset2]; + auto const issue1 = ammSle[sfAsset].get(); + auto const issue2 = ammSle[sfAsset2].get(); if (optIssue1 && optIssue2) { if (invalidAMMAssetPair( @@ -134,8 +134,8 @@ ammLPHolds( { return ammLPHolds( view, - ammSle[sfAsset].currency, - ammSle[sfAsset2].currency, + ammSle[sfAsset].get().currency, + ammSle[sfAsset2].get().currency, ammSle[sfAccount], lpAccount, j); @@ -145,9 +145,10 @@ std::uint16_t getTradingFee(ReadView const& view, SLE const& ammSle, AccountID const& account) { using namespace std::chrono; - assert( + XRPL_ASSERT( !view.rules().enabled(fixInnerObjTemplate) || - ammSle.isFieldPresent(sfAuctionSlot)); + ammSle.isFieldPresent(sfAuctionSlot), + "ripple::getTradingFee : auction present"); if (ammSle.isFieldPresent(sfAuctionSlot)) { auto const& auctionSlot = diff --git a/src/xrpld/app/misc/detail/AmendmentTable.cpp b/src/xrpld/app/misc/detail/AmendmentTable.cpp index 62b80890821..270b5daced2 100644 --- a/src/xrpld/app/misc/detail/AmendmentTable.cpp +++ b/src/xrpld/app/misc/detail/AmendmentTable.cpp @@ -656,7 +656,9 @@ AmendmentTableImpl::persistVote( std::string const& name, AmendmentVote vote) const { - assert(vote != AmendmentVote::obsolete); + XRPL_ASSERT( + vote != AmendmentVote::obsolete, + "ripple::AmendmentTableImpl::persistVote : valid vote input"); auto db = db_.checkoutDb(); voteAmendment(*db, amendment, name, vote); } diff --git a/src/xrpld/app/misc/detail/LoadFeeTrack.cpp b/src/xrpld/app/misc/detail/LoadFeeTrack.cpp index 1267af594d0..50fb0ac14db 100644 --- a/src/xrpld/app/misc/detail/LoadFeeTrack.cpp +++ b/src/xrpld/app/misc/detail/LoadFeeTrack.cpp @@ -20,10 +20,10 @@ #include #include #include -#include #include #include #include +#include #include #include diff --git a/src/xrpld/app/misc/detail/Manifest.cpp b/src/xrpld/app/misc/detail/Manifest.cpp index a17858ceb39..04c8523aece 100644 --- a/src/xrpld/app/misc/detail/Manifest.cpp +++ b/src/xrpld/app/misc/detail/Manifest.cpp @@ -390,7 +390,9 @@ ManifestCache::applyManifest(Manifest m) auto prewriteCheck = [this, &m](auto const& iter, bool checkSignature, auto const& lock) -> std::optional { - assert(lock.owns_lock()); + XRPL_ASSERT( + lock.owns_lock(), + "ripple::ManifestCache::applyManifest::prewriteCheck : locked"); (void)lock; // not used. parameter is present to ensure the mutex is // locked when the lambda is called. if (iter != map_.end() && m.sequence <= iter->second.sequence) diff --git a/src/xrpld/app/misc/detail/Transaction.cpp b/src/xrpld/app/misc/detail/Transaction.cpp index c8f9df232e0..30af6b773d0 100644 --- a/src/xrpld/app/misc/detail/Transaction.cpp +++ b/src/xrpld/app/misc/detail/Transaction.cpp @@ -82,7 +82,10 @@ Transaction::sqlTransactionStatus(boost::optional const& status) return INCLUDED; } - assert(c == txnSqlUnknown); + XRPL_ASSERT( + c == txnSqlUnknown, + "ripple::Transaction::sqlTransactionStatus : unknown transaction " + "status"); return INVALID; } diff --git a/src/xrpld/app/misc/detail/TxQ.cpp b/src/xrpld/app/misc/detail/TxQ.cpp index a4e62b382a7..4c78bc4bc99 100644 --- a/src/xrpld/app/misc/detail/TxQ.cpp +++ b/src/xrpld/app/misc/detail/TxQ.cpp @@ -52,7 +52,7 @@ getFeeLevelPaid(ReadView const& view, STTx const& tx) return std::pair{baseFee + mod, feePaid + mod}; }(); - assert(baseFee.signum() > 0); + XRPL_ASSERT(baseFee.signum() > 0, "ripple::getFeeLevelPaid : positive fee"); if (effectiveFeePaid.signum() <= 0 || baseFee.signum() <= 0) { return FeeLevel64(0); @@ -95,7 +95,9 @@ TxQ::FeeMetrics::update( feeLevels.push_back(getFeeLevelPaid(view, *tx.first)); }); std::sort(feeLevels.begin(), feeLevels.end()); - assert(size == feeLevels.size()); + XRPL_ASSERT( + size == feeLevels.size(), + "ripple::TxQ::FeeMetrics::update : fee levels size"); JLOG((timeLeap ? j_.warn() : j_.debug())) << "Ledger " << view.info().seq << " has " << size << " transactions. " @@ -247,7 +249,10 @@ TxQ::FeeMetrics::escalatedSeriesFeeLevel( auto const target = snapshot.txnsExpected; auto const multiplier = snapshot.escalationMultiplier; - assert(current > target); + XRPL_ASSERT( + current > target, + "ripple::TxQ::FeeMetrics::escalatedSeriesFeeLevel : current over " + "target"); /* Calculate (apologies for the terrible notation) sum(n = current -> last) : multiplier * n * n / (target * target) @@ -292,7 +297,8 @@ std::pair TxQ::MaybeTx::apply(Application& app, OpenView& view, beast::Journal j) { // If the rules or flags change, preflight again - assert(pfresult); + XRPL_ASSERT( + pfresult, "ripple::TxQ::MaybeTx::apply : preflight result is set"); STAmountSO stAmountSO{view.rules().enabled(fixSTAmountCanonicalize)}; NumberSO stNumberSO{view.rules().enabled(fixUniversalNumber)}; @@ -337,8 +343,11 @@ TxQ::TxQAccount::add(MaybeTx&& txn) auto const seqProx = txn.seqProxy; auto result = transactions.emplace(seqProx, std::move(txn)); - assert(result.second); - assert(&result.first->second != &txn); + XRPL_ASSERT( + result.second, "ripple::TxQ::TxQAccount::add : emplace succeeded"); + XRPL_ASSERT( + &result.first->second != &txn, + "ripple::TxQ::TxQAccount::add : transaction moved"); return result.first->second; } @@ -446,9 +455,8 @@ TxQ::erase(TxQ::FeeMultiSet::const_iterator_type candidateIter) // Now that the candidate has been removed from the // intrusive list remove it from the TxQAccount // so the memory can be freed. - auto const found = txQAccount.remove(seqProx); - (void)found; - assert(found); + [[maybe_unused]] auto const found = txQAccount.remove(seqProx); + XRPL_ASSERT(found, "ripple::TxQ::erase : account removed"); return newCandidateIter; } @@ -460,15 +468,20 @@ TxQ::eraseAndAdvance(TxQ::FeeMultiSet::const_iterator_type candidateIter) auto& txQAccount = byAccount_.at(candidateIter->account); auto const accountIter = txQAccount.transactions.find(candidateIter->seqProxy); - assert(accountIter != txQAccount.transactions.end()); + XRPL_ASSERT( + accountIter != txQAccount.transactions.end(), + "ripple::TxQ::eraseAndAdvance : account found"); // Note that sequence-based transactions must be applied in sequence order // from smallest to largest. But ticket-based transactions can be // applied in any order. - assert( + XRPL_ASSERT( candidateIter->seqProxy.isTicket() || - accountIter == txQAccount.transactions.begin()); - assert(byFee_.iterator_to(accountIter->second) == candidateIter); + accountIter == txQAccount.transactions.begin(), + "ripple::TxQ::eraseAndAdvance : ticket or sequence"); + XRPL_ASSERT( + byFee_.iterator_to(accountIter->second) == candidateIter, + "ripple::TxQ::eraseAndAdvance : found in byFee"); auto const accountNextIter = std::next(accountIter); // Check if the next transaction for this account is earlier in the queue, @@ -515,7 +528,9 @@ TxQ::tryClearAccountQueueUpThruTx( beast::Journal j) { SeqProxy const tSeqProx{tx.getSeqProxy()}; - assert(beginTxIter != accountIter->second.transactions.end()); + XRPL_ASSERT( + beginTxIter != accountIter->second.transactions.end(), + "ripple::TxQ::tryClearAccountQueueUpThruTx : non-empty accounts input"); // This check is only concerned with the range from // [aSeqProxy, tSeqProxy) @@ -998,7 +1013,8 @@ TxQ::apply( // o The current first thing in the queue has a Ticket and // * The tx has a Ticket that precedes it or // * txSeqProx == acctSeqProx. - assert(prevIter != txIter->end); + XRPL_ASSERT( + prevIter != txIter->end, "ripple::TxQ::apply : not end"); if (prevIter == txIter->end || txSeqProx < prevIter->first) { // The first Sequence number in the queue must be the @@ -1119,10 +1135,11 @@ TxQ::apply( // inserted in the middle from fouling up later transactions. auto const potentialTotalSpend = totalFee + std::min(balance - std::min(balance, reserve), potentialSpend); - assert( + XRPL_ASSERT( potentialTotalSpend > XRPAmount{0} || - (potentialTotalSpend == XRPAmount{0} && - multiTxn->applyView.fees().base == 0)); + (potentialTotalSpend == XRPAmount{0} && + multiTxn->applyView.fees().base == 0), + "ripple::TxQ::apply : total spend check"); sleBump->setFieldAmount(sfBalance, balance - potentialTotalSpend); // The transaction's sequence/ticket will be valid when the other // transactions in the queue have been processed. If the tx has a @@ -1152,7 +1169,7 @@ TxQ::apply( return {pcresult.ter, false}; // Too low of a fee should get caught by preclaim - assert(feeLevelPaid >= baseLevel); + XRPL_ASSERT(feeLevelPaid >= baseLevel, "ripple::TxQ::apply : minimum fee"); JLOG(j_.trace()) << "Transaction " << transactionID << " from account " << account << " has fee level of " << feeLevelPaid @@ -1277,7 +1294,9 @@ TxQ::apply( // The queue is full, and this transaction is more // valuable, so kick out the cheapest transaction. auto dropRIter = endAccount.transactions.rbegin(); - assert(dropRIter->second.account == lastRIter->account); + XRPL_ASSERT( + dropRIter->second.account == lastRIter->account, + "ripple::TxQ::apply : cheapest transaction found"); JLOG(j_.info()) << "Removing last item of account " << lastRIter->account << " from queue with average fee of " << endEffectiveFeeLevel @@ -1303,11 +1322,10 @@ TxQ::apply( if (!accountIsInQueue) { // Create a new TxQAccount object and add the byAccount lookup. - bool created; + [[maybe_unused]] bool created = false; std::tie(accountIter, created) = byAccount_.emplace(account, TxQAccount(tx)); - (void)created; - assert(created); + XRPL_ASSERT(created, "ripple::TxQ::apply : account created"); } // Modify the flags for use when coming out of the queue. // These changes _may_ cause an extra `preflight`, but as long as @@ -1520,9 +1538,9 @@ TxQ::accept(Application& app, OpenView& view) // making things worse, drop the _last_ transaction for // this account. auto dropRIter = account.transactions.rbegin(); - assert( - dropRIter->second.account == - candidateIter->account); + XRPL_ASSERT( + dropRIter->second.account == candidateIter->account, + "ripple::TxQ::accept : account check"); JLOG(j_.info()) << "Queue is nearly full, and transaction " @@ -1553,7 +1571,8 @@ TxQ::accept(Application& app, OpenView& view) LedgerHash const& parentHash = view.info().parentHash; #if !NDEBUG auto const startingSize = byFee_.size(); - assert(parentHash != parentHash_); + XRPL_ASSERT( + parentHash != parentHash_, "ripple::TxQ::accept : new parent hash"); parentHash_ = parentHash; #endif // byFee_ doesn't "own" the candidate objects inside it, so it's @@ -1575,7 +1594,9 @@ TxQ::accept(Application& app, OpenView& view) byFee_.insert(candidate); } } - assert(byFee_.size() == startingSize); + XRPL_ASSERT( + byFee_.size() == startingSize, + "ripple::TxQ::accept : byFee size match"); return ledgerChanged; } @@ -1734,10 +1755,18 @@ TxQ::removeFromByFee( // If the transaction we're holding replaces a transaction in the // queue, remove the transaction that is being replaced. auto deleteIter = byFee_.iterator_to((*replacedTxIter)->second); - assert(deleteIter != byFee_.end()); - assert(&(*replacedTxIter)->second == &*deleteIter); - assert(deleteIter->seqProxy == tx->getSeqProxy()); - assert(deleteIter->account == (*tx)[sfAccount]); + XRPL_ASSERT( + deleteIter != byFee_.end(), + "ripple::TxQ::removeFromByFee : found in byFee"); + XRPL_ASSERT( + &(*replacedTxIter)->second == &*deleteIter, + "ripple::TxQ::removeFromByFee : matching transaction"); + XRPL_ASSERT( + deleteIter->seqProxy == tx->getSeqProxy(), + "ripple::TxQ::removeFromByFee : matching sequence"); + XRPL_ASSERT( + deleteIter->account == (*tx)[sfAccount], + "ripple::TxQ::removeFromByFee : matching account"); erase(deleteIter); } diff --git a/src/xrpld/app/misc/detail/ValidatorList.cpp b/src/xrpld/app/misc/detail/ValidatorList.cpp index 9a323e0116b..ba77a3213c7 100644 --- a/src/xrpld/app/misc/detail/ValidatorList.cpp +++ b/src/xrpld/app/misc/detail/ValidatorList.cpp @@ -276,7 +276,9 @@ ValidatorList::buildFileData( { Json::Value value(Json::objectValue); - assert(pubCollection.rawVersion == 2 || pubCollection.remaining.empty()); + XRPL_ASSERT( + pubCollection.rawVersion == 2 || pubCollection.remaining.empty(), + "ripple::ValidatorList::buildFileData : valid publisher list input"); auto const effectiveVersion = forceVersion ? *forceVersion : pubCollection.rawVersion; @@ -376,7 +378,9 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) ValidatorBlobInfo& info = result.emplace_back(); info.blob = body[jss::blob].asString(); info.signature = body[jss::signature].asString(); - assert(result.size() == 1); + XRPL_ASSERT( + result.size() == 1, + "ripple::ValidatorList::parseBlobs : single element result"); return result; } // Treat unknown versions as if they're the latest version. This @@ -411,7 +415,10 @@ ValidatorList::parseBlobs(std::uint32_t version, Json::Value const& body) info.manifest = blobInfo[jss::manifest].asString(); } } - assert(result.size() == blobs.size()); + XRPL_ASSERT( + result.size() == blobs.size(), + "ripple::ValidatorList::parseBlobs(version, Jason::Value) : " + "result size matches"); return result; } } @@ -442,7 +449,10 @@ ValidatorList::parseBlobs(protocol::TMValidatorListCollection const& body) info.manifest = blob.manifest(); } } - assert(result.size() == body.blobs_size()); + XRPL_ASSERT( + result.size() == body.blobs_size(), + "ripple::ValidatorList::parseBlobs(TMValidatorList) : result size " + "match"); return result; } @@ -464,7 +474,7 @@ splitMessage( { if (begin == 0 && end == 0) end = largeMsg.blobs_size(); - assert(begin < end); + XRPL_ASSERT(begin < end, "ripple::splitMessage : valid inputs"); if (end <= begin) return 0; @@ -498,7 +508,9 @@ splitMessageParts( if (blob.has_manifest()) smallMsg.set_manifest(blob.manifest()); - assert(Message::totalSize(smallMsg) <= maximiumMessageSize); + XRPL_ASSERT( + Message::totalSize(smallMsg) <= maximiumMessageSize, + "ripple::splitMessageParts : maximum message size"); messages.emplace_back( std::make_shared(smallMsg, protocol::mtVALIDATORLIST), @@ -546,7 +558,10 @@ buildValidatorListMessage( ValidatorBlobInfo const& currentBlob, std::size_t maxSize) { - assert(messages.empty()); + XRPL_ASSERT( + messages.empty(), + "ripple::buildValidatorListMessage(ValidatorBlobInfo) : empty messages " + "input"); protocol::TMValidatorList msg; auto const manifest = currentBlob.manifest ? *currentBlob.manifest : rawManifest; @@ -557,7 +572,10 @@ buildValidatorListMessage( // Override the version msg.set_version(version); - assert(Message::totalSize(msg) <= maximiumMessageSize); + XRPL_ASSERT( + Message::totalSize(msg) <= maximiumMessageSize, + "ripple::buildValidatorListMessage(ValidatorBlobInfo) : maximum " + "message size"); messages.emplace_back( std::make_shared(msg, protocol::mtVALIDATORLIST), sha512Half(msg), @@ -576,7 +594,10 @@ buildValidatorListMessage( std::map const& blobInfos, std::size_t maxSize) { - assert(messages.empty()); + XRPL_ASSERT( + messages.empty(), + "ripple::buildValidatorListMessage(std::map) : empty messages input"); protocol::TMValidatorListCollection msg; auto const version = rawVersion < 2 ? 2 : rawVersion; msg.set_version(version); @@ -592,7 +613,10 @@ buildValidatorListMessage( if (blobInfo.manifest) blob.set_manifest(*blobInfo.manifest); } - assert(msg.blobs_size() > 0); + XRPL_ASSERT( + msg.blobs_size() > 0, + "ripple::buildValidatorListMessage(std::map) : minimum message blobs"); if (Message::totalSize(msg) > maxSize) { // split into smaller messages @@ -621,7 +645,10 @@ ValidatorList::buildValidatorListMessages( std::vector& messages, std::size_t maxSize /*= maximiumMessageSize*/) { - assert(!blobInfos.empty()); + XRPL_ASSERT( + !blobInfos.empty(), + "ripple::ValidatorList::buildValidatorListMessages : empty messages " + "input"); auto const& [currentSeq, currentBlob] = *blobInfos.begin(); auto numVLs = std::accumulate( messages.begin(), @@ -704,7 +731,10 @@ ValidatorList::sendValidatorList( messages); if (newPeerSequence) { - assert(!messages.empty()); + XRPL_ASSERT( + !messages.empty(), + "ripple::ValidatorList::sendValidatorList : non-empty messages " + "input"); // Don't send it next time. peer.setPublisherListSequence(publisherKey, newPeerSequence); @@ -720,7 +750,9 @@ ValidatorList::sendValidatorList( } // The only way sent wil be false is if the messages was too big, and // thus there will only be one entry without a message - assert(sent || messages.size() == 1); + XRPL_ASSERT( + sent || messages.size() == 1, + "ripple::ValidatorList::sendValidatorList : sent or one message"); if (sent) { if (messageVersion > 1) @@ -734,7 +766,10 @@ ValidatorList::sendValidatorList( << "]"; else { - assert(numVLs == 1); + XRPL_ASSERT( + numVLs == 1, + "ripple::ValidatorList::sendValidatorList : one validator " + "list"); JLOG(j.debug()) << "Sent validator list for " << strHex(publisherKey) << " with sequence " << newPeerSequence << " to " @@ -829,9 +864,10 @@ ValidatorList::broadcastBlobs( // be built to hold info for all of the valid VLs. std::map blobInfos; - assert( + XRPL_ASSERT( lists.current.sequence == maxSequence || - lists.remaining.count(maxSequence) == 1); + lists.remaining.count(maxSequence) == 1, + "ripple::ValidatorList::broadcastBlobs : valid sequence"); // Can't use overlay.foreach here because we need to modify // the peer, and foreach provides a const& for (auto& peer : overlay.getActivePeers()) @@ -975,7 +1011,9 @@ ValidatorList::applyLists( for (auto iter = remaining.begin(); iter != remaining.end();) { auto next = std::next(iter); - assert(next == remaining.end() || next->first > iter->first); + XRPL_ASSERT( + next == remaining.end() || next->first > iter->first, + "ripple::ValidatorList::applyLists : next is valid"); if (iter->first <= current.sequence || (next != remaining.end() && next->second.validFrom <= iter->second.validFrom)) @@ -1147,7 +1185,9 @@ ValidatorList::applyList( // Remove the entry in "remaining" pubCollection.remaining.erase(sequence); // Done - assert(publisher.sequence == sequence); + XRPL_ASSERT( + publisher.sequence == sequence, + "ripple::ValidatorList::applyList : publisher sequence match"); } else { @@ -1441,9 +1481,10 @@ ValidatorList::removePublisherList( PublicKey const& publisherKey, PublisherStatus reason) { - assert( + XRPL_ASSERT( reason != PublisherStatus::available && - reason != PublisherStatus::unavailable); + reason != PublisherStatus::unavailable, + "ripple::ValidatorList::removePublisherList : valid reason input"); auto const iList = publisherLists_.find(publisherKey); if (iList == publisherLists_.end()) return false; @@ -1628,7 +1669,9 @@ ValidatorList::getJson() const Json::Value& r = remaining.append(Json::objectValue); appendList(future, r); // Race conditions can happen, so make this check "fuzzy" - assert(future.validFrom > timeKeeper_.now() + 600s); + XRPL_ASSERT( + future.validFrom > timeKeeper_.now() + 600s, + "ripple::ValidatorList::getJson : minimum valid from"); } if (remaining.size()) curr[jss::remaining] = std::move(remaining); @@ -1693,7 +1736,9 @@ ValidatorList::for_each_available( { if (plCollection.status != PublisherStatus::available) continue; - assert(plCollection.maxSequence); + XRPL_ASSERT( + plCollection.maxSequence != 0, + "ripple::ValidatorList::for_each_available : nonzero maxSequence"); func( plCollection.rawManifest, plCollection.rawVersion, @@ -1827,21 +1872,31 @@ ValidatorList::updateTrusted( next->second.validFrom <= closeTime; ++iter, ++next) { - assert(std::next(iter) == next); + XRPL_ASSERT( + std::next(iter) == next, + "ripple::ValidatorList::updateTrusted : sequential " + "remaining"); } - assert(iter != remaining.end()); + XRPL_ASSERT( + iter != remaining.end(), + "ripple::ValidatorList::updateTrusted : non-end of " + "remaining"); // Rotate the pending list in to current auto sequence = iter->first; auto& candidate = iter->second; auto& current = collection.current; - assert(candidate.validFrom <= closeTime); + XRPL_ASSERT( + candidate.validFrom <= closeTime, + "ripple::ValidatorList::updateTrusted : maximum time"); auto const oldList = current.list; current = std::move(candidate); if (collection.status != PublisherStatus::available) collection.status = PublisherStatus::available; - assert(current.sequence == sequence); + XRPL_ASSERT( + current.sequence == sequence, + "ripple::ValidatorList::updateTrusted : sequence match"); // If the list is expired, remove the validators so they don't // get processed in. The expiration check below will do the rest // of the work @@ -1918,7 +1973,9 @@ ValidatorList::updateTrusted( { std::optional const signingKey = validatorManifests_.getSigningKey(k); - assert(signingKey); + XRPL_ASSERT( + signingKey, + "ripple::ValidatorList::updateTrusted : found signing key"); trustedSigningKeys_.insert(*signingKey); } } diff --git a/src/xrpld/app/misc/detail/ValidatorSite.cpp b/src/xrpld/app/misc/detail/ValidatorSite.cpp index 0c12816c1b8..1994f498614 100644 --- a/src/xrpld/app/misc/detail/ValidatorSite.cpp +++ b/src/xrpld/app/misc/detail/ValidatorSite.cpp @@ -411,7 +411,9 @@ ValidatorSite::parseJsonResponse( } auto const manifest = body[jss::manifest].asString(); - assert(version == body[jss::version].asUInt()); + XRPL_ASSERT( + version == body[jss::version].asUInt(), + "ripple::ValidatorSite::parseJsonResponse : version match"); auto const& uri = sites_[siteIdx].activeResource->uri; auto const hash = sha512Half(manifest, blobs, version); auto const applyResult = app_.validators().applyListsAndBroadcast( @@ -586,7 +588,10 @@ ValidatorSite::onSiteFetch( case status::temporary_redirect: { auto newLocation = processRedirect(res, siteIdx, lock_sites); - assert(newLocation); + XRPL_ASSERT( + newLocation, + "ripple::ValidatorSite::onSiteFetch : non-null " + "validator"); // for perm redirects, also update our starting URI if (res.result() == status::moved_permanently || res.result() == status::permanent_redirect) diff --git a/src/xrpld/app/misc/detail/WorkBase.h b/src/xrpld/app/misc/detail/WorkBase.h index d7795af8bf0..cd909265115 100644 --- a/src/xrpld/app/misc/detail/WorkBase.h +++ b/src/xrpld/app/misc/detail/WorkBase.h @@ -282,7 +282,7 @@ WorkBase::onResponse(error_code const& ec) return fail(ec); close(); - assert(cb_); + XRPL_ASSERT(cb_, "ripple::detail::WorkBase::onResponse : callback is set"); cb_(ec, lastEndpoint_, std::move(res_)); cb_ = nullptr; } diff --git a/src/xrpld/app/misc/detail/WorkFile.h b/src/xrpld/app/misc/detail/WorkFile.h index 266e5098cb6..9b8d86f5e16 100644 --- a/src/xrpld/app/misc/detail/WorkFile.h +++ b/src/xrpld/app/misc/detail/WorkFile.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include namespace ripple { @@ -88,7 +88,7 @@ WorkFile::run() error_code ec; auto const fileContents = getFileContents(ec, path_, megabytes(1)); - assert(cb_); + XRPL_ASSERT(cb_, "ripple::detail::WorkFile::run : callback is set"); cb_(ec, fileContents); cb_ = nullptr; } diff --git a/src/xrpld/app/paths/Credit.cpp b/src/xrpld/app/paths/Credit.cpp index b3870937367..e027949e761 100644 --- a/src/xrpld/app/paths/Credit.cpp +++ b/src/xrpld/app/paths/Credit.cpp @@ -42,8 +42,12 @@ creditLimit( result.setIssuer(account); } - assert(result.getIssuer() == account); - assert(result.getCurrency() == currency); + XRPL_ASSERT( + result.getIssuer() == account, + "ripple::creditLimit : result issuer match"); + XRPL_ASSERT( + result.getCurrency() == currency, + "ripple::creditLimit : result currency match"); return result; } @@ -76,8 +80,12 @@ creditBalance( result.setIssuer(account); } - assert(result.getIssuer() == account); - assert(result.getCurrency() == currency); + XRPL_ASSERT( + result.getIssuer() == account, + "ripple::creditBalance : result issuer match"); + XRPL_ASSERT( + result.getCurrency() == currency, + "ripple::creditBalance : result currency match"); return result; } diff --git a/src/xrpld/app/paths/Credit.h b/src/xrpld/app/paths/Credit.h index 1f9d5b04fe9..b71ec057ae1 100644 --- a/src/xrpld/app/paths/Credit.h +++ b/src/xrpld/app/paths/Credit.h @@ -21,7 +21,7 @@ #define RIPPLE_APP_PATHS_CREDIT_H_INCLUDED #include -#include +#include #include namespace ripple { diff --git a/src/xrpld/app/paths/Flow.cpp b/src/xrpld/app/paths/Flow.cpp index c21d40c33b5..3df8f6f9992 100644 --- a/src/xrpld/app/paths/Flow.cpp +++ b/src/xrpld/app/paths/Flow.cpp @@ -23,9 +23,9 @@ #include #include #include -#include #include -#include +#include +#include #include @@ -193,7 +193,7 @@ flow( flowDebugInfo)); } - assert(!srcIsXRP && !dstIsXRP); + XRPL_ASSERT(!srcIsXRP && !dstIsXRP, "ripple::flow : neither is XRP"); return finishFlow( sb, srcIssue, diff --git a/src/xrpld/app/paths/PathRequest.cpp b/src/xrpld/app/paths/PathRequest.cpp index bb6a104bca2..643923320a2 100644 --- a/src/xrpld/app/paths/PathRequest.cpp +++ b/src/xrpld/app/paths/PathRequest.cpp @@ -158,7 +158,8 @@ PathRequest::updateComplete() { std::lock_guard sl(mIndexLock); - assert(mInProgress); + XRPL_ASSERT( + mInProgress, "ripple::PathRequest::updateComplete : in progress"); mInProgress = false; if (fCompletion) diff --git a/src/xrpld/app/paths/Pathfinder.cpp b/src/xrpld/app/paths/Pathfinder.cpp index 5122bc7d6b8..5864357aec4 100644 --- a/src/xrpld/app/paths/Pathfinder.cpp +++ b/src/xrpld/app/paths/Pathfinder.cpp @@ -189,7 +189,9 @@ Pathfinder::Pathfinder( , app_(app) , j_(app.journal("Pathfinder")) { - assert(!uSrcIssuer || isXRP(uSrcCurrency) == isXRP(uSrcIssuer.value())); + XRPL_ASSERT( + !uSrcIssuer || isXRP(uSrcCurrency) == isXRP(uSrcIssuer.value()), + "ripple::Pathfinder::Pathfinder : valid inputs"); } bool @@ -577,7 +579,9 @@ Pathfinder::getBestPaths( if (mCompletePaths.empty() && extraPaths.empty()) return mCompletePaths; - assert(fullLiquidityPath.empty()); + XRPL_ASSERT( + fullLiquidityPath.empty(), + "ripple::Pathfinder::getBestPaths : first empty path result"); const bool issuerIsSender = isXRP(mSrcCurrency) || (srcIssuer == mSrcAccount); @@ -638,7 +642,7 @@ Pathfinder::getBestPaths( if (path.empty()) { - assert(false); + UNREACHABLE("ripple::Pathfinder::getBestPaths : path not found"); continue; } @@ -681,7 +685,9 @@ Pathfinder::getBestPaths( if (remaining > beast::zero) { - assert(fullLiquidityPath.empty()); + XRPL_ASSERT( + fullLiquidityPath.empty(), + "ripple::Pathfinder::getBestPaths : second empty path result"); JLOG(j_.info()) << "Paths could not send " << remaining << " of " << mDstAmount; } @@ -830,7 +836,9 @@ Pathfinder::addPathsForType( { case nt_SOURCE: // Source must always be at the start, so pathsOut has to be empty. - assert(pathsOut.empty()); + XRPL_ASSERT( + pathsOut.empty(), + "ripple::Pathfinder::addPathsForType : empty paths"); pathsOut.push_back(STPath()); break; @@ -1282,7 +1290,7 @@ void fillPaths(Pathfinder::PaymentType type, PathCostList const& costs) { auto& list = mPathTable[type]; - assert(list.empty()); + XRPL_ASSERT(list.empty(), "ripple::fillPaths : empty paths"); for (auto& cost : costs) list.push_back({cost.cost, makePath(cost.path)}); } diff --git a/src/xrpld/app/paths/RippleLineCache.cpp b/src/xrpld/app/paths/RippleLineCache.cpp index 0ff967c0821..38b630eeb7e 100644 --- a/src/xrpld/app/paths/RippleLineCache.cpp +++ b/src/xrpld/app/paths/RippleLineCache.cpp @@ -79,7 +79,9 @@ RippleLineCache::getRippleLines( // to be replaced by the full set. The full set will be built // below, and will be returned, if needed, on subsequent calls // for either value of outgoing. - assert(size <= totalLineCount_); + XRPL_ASSERT( + size <= totalLineCount_, + "ripple::RippleLineCache::getRippleLines : maximum lines"); totalLineCount_ -= size; lines_.erase(otheriter); } @@ -99,7 +101,9 @@ RippleLineCache::getRippleLines( if (inserted) { - assert(it->second == nullptr); + XRPL_ASSERT( + it->second == nullptr, + "ripple::RippleLineCache::getRippleLines : null lines"); auto lines = PathFindTrustLine::getItems(accountID, *ledger_, direction); if (lines.size()) @@ -110,7 +114,9 @@ RippleLineCache::getRippleLines( } } - assert(!it->second || (it->second->size() > 0)); + XRPL_ASSERT( + !it->second || (it->second->size() > 0), + "ripple::RippleLineCache::getRippleLines : null or nonempty lines"); auto const size = it->second ? it->second->size() : 0; JLOG(journal_.trace()) << "getRippleLines for ledger " << ledger_->info().seq << " found " << size diff --git a/src/xrpld/app/paths/detail/AMMLiquidity.cpp b/src/xrpld/app/paths/detail/AMMLiquidity.cpp index 7b1649c649e..813554ba7ff 100644 --- a/src/xrpld/app/paths/detail/AMMLiquidity.cpp +++ b/src/xrpld/app/paths/detail/AMMLiquidity.cpp @@ -77,7 +77,9 @@ AMMLiquidity::generateFibSeqOffer( 196418, 317811, 514229, 832040, 1346269}; // clang-format on - assert(!ammContext_.maxItersReached()); + XRPL_ASSERT( + !ammContext_.maxItersReached(), + "ripple::AMMLiquidity::generateFibSeqOffer : maximum iterations"); cur.out = toAmount( getIssue(balances.out), diff --git a/src/xrpld/app/paths/detail/AmountSpec.h b/src/xrpld/app/paths/detail/AmountSpec.h index 8a1117f9920..d57e9140f80 100644 --- a/src/xrpld/app/paths/detail/AmountSpec.h +++ b/src/xrpld/app/paths/detail/AmountSpec.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_PATH_IMPL_AMOUNTSPEC_H_INCLUDED #define RIPPLE_PATH_IMPL_AMOUNTSPEC_H_INCLUDED -#include -#include +#include #include +#include #include @@ -125,7 +125,8 @@ template <> inline IOUAmount& get(EitherAmount& amt) { - assert(!amt.native); + XRPL_ASSERT( + !amt.native, "ripple::get(EitherAmount&) : is not XRP"); return amt.iou; } @@ -133,7 +134,7 @@ template <> inline XRPAmount& get(EitherAmount& amt) { - assert(amt.native); + XRPL_ASSERT(amt.native, "ripple::get(EitherAmount&) : is XRP"); return amt.xrp; } @@ -149,7 +150,9 @@ template <> inline IOUAmount const& get(EitherAmount const& amt) { - assert(!amt.native); + XRPL_ASSERT( + !amt.native, + "ripple::get(EitherAmount const&) : is not XRP"); return amt.iou; } @@ -157,14 +160,17 @@ template <> inline XRPAmount const& get(EitherAmount const& amt) { - assert(amt.native); + XRPL_ASSERT( + amt.native, "ripple::get(EitherAmount const&) : is XRP"); return amt.xrp; } inline AmountSpec toAmountSpec(STAmount const& amt) { - assert(amt.mantissa() < std::numeric_limits::max()); + XRPL_ASSERT( + amt.mantissa() < std::numeric_limits::max(), + "ripple::toAmountSpec(STAmount const&) : maximum mantissa"); bool const isNeg = amt.negative(); std::int64_t const sMant = isNeg ? -std::int64_t(amt.mantissa()) : amt.mantissa(); @@ -199,7 +205,10 @@ toAmountSpec(EitherAmount const& ea, std::optional const& c) AmountSpec r; r.native = (!c || isXRP(*c)); r.currency = c; - assert(ea.native == r.native); + XRPL_ASSERT( + ea.native == r.native, + "ripple::toAmountSpec(EitherAmount const&&, std::optional) : " + "matching native"); if (r.native) { r.xrp = ea.xrp; diff --git a/src/xrpld/app/paths/detail/BookStep.cpp b/src/xrpld/app/paths/detail/BookStep.cpp index b22102119df..1d35f80b183 100644 --- a/src/xrpld/app/paths/detail/BookStep.cpp +++ b/src/xrpld/app/paths/detail/BookStep.cpp @@ -24,13 +24,14 @@ #include #include #include -#include #include -#include #include +#include #include #include +#include #include +#include #include @@ -379,7 +380,9 @@ class BookOfferCrossingStep getQuality(std::optional const& limitQuality) { // It's really a programming error if the quality is missing. - assert(limitQuality); + XRPL_ASSERT( + limitQuality, + "ripple::BookOfferCrossingStep::getQuality : nonzero quality"); if (!limitQuality) Throw(tefINTERNAL, "Offer requires quality."); return *limitQuality; @@ -1107,7 +1110,7 @@ BookStep::revImp( // something went very wrong JLOG(j_.error()) << "BookStep remainingOut < 0 " << to_string(remainingOut); - assert(0); + UNREACHABLE("ripple::BookStep::revImp : remaining less than zero"); cache_.emplace(beast::zero, beast::zero); return {beast::zero, beast::zero}; } @@ -1130,7 +1133,7 @@ BookStep::fwdImp( boost::container::flat_set& ofrsToRm, TIn const& in) { - assert(cache_); + XRPL_ASSERT(cache_, "ripple::BookStep::fwdImp : cache is set"); TAmounts result(beast::zero, beast::zero); @@ -1149,7 +1152,8 @@ BookStep::fwdImp( TOut const& ownerGives, std::uint32_t transferRateIn, std::uint32_t transferRateOut) mutable -> bool { - assert(cache_); + XRPL_ASSERT( + cache_, "ripple::BookStep::fwdImp::eachOffer : cache is set"); if (remainingIn <= beast::zero) return false; @@ -1277,7 +1281,7 @@ BookStep::fwdImp( // something went very wrong JLOG(j_.error()) << "BookStep remainingIn < 0 " << to_string(remainingIn); - assert(0); + UNREACHABLE("ripple::BookStep::fwdImp : remaining less than zero"); cache_.emplace(beast::zero, beast::zero); return {beast::zero, beast::zero}; } @@ -1412,7 +1416,7 @@ bookStepEqual(Step const& step, ripple::Book const& book) bool const outXRP = isXRP(book.out.currency); if (inXRP && outXRP) { - assert(0); + UNREACHABLE("ripple::test::bookStepEqual : no XRP to XRP book step"); return false; // no such thing as xrp/xrp book step } if (inXRP && !outXRP) diff --git a/src/xrpld/app/paths/detail/DirectStep.cpp b/src/xrpld/app/paths/detail/DirectStep.cpp index 7df06751140..95e64b337bc 100644 --- a/src/xrpld/app/paths/detail/DirectStep.cpp +++ b/src/xrpld/app/paths/detail/DirectStep.cpp @@ -21,9 +21,9 @@ #include #include #include -#include #include #include +#include #include #include @@ -514,7 +514,9 @@ DirectStepI::revImp( auto const [srcQOut, dstQIn] = qualities(sb, srcDebtDir, StrandDirection::reverse); - assert(static_cast(this)->verifyDstQualityIn(dstQIn)); + XRPL_ASSERT( + static_cast(this)->verifyDstQualityIn(dstQIn), + "ripple::DirectStepI : valid destination quality"); Issue const srcToDstIss(currency_, redeems(srcDebtDir) ? dst_ : src_); @@ -633,7 +635,7 @@ DirectStepI::fwdImp( boost::container::flat_set& /*ofrsToRm*/, IOUAmount const& in) { - assert(cache_); + XRPL_ASSERT(cache_, "ripple::DirectStepI::fwdImp : cache is set"); auto const [maxSrcToDst, srcDebtDir] = static_cast(this)->maxFlow(sb, cache_->srcToDst); @@ -720,7 +722,7 @@ DirectStepI::validFwd( auto const savCache = *cache_; - assert(!in.native); + XRPL_ASSERT(!in.native, "ripple::DirectStepI::validFwd : input is not XRP"); auto const [maxSrcToDst, srcDebtDir] = static_cast(this)->maxFlow(sb, cache_->srcToDst); @@ -784,8 +786,11 @@ DirectStepI::qualitiesSrcIssues( { // Charge a transfer rate when issuing and previous step redeems - assert(static_cast(this)->verifyPrevStepDebtDirection( - prevStepDebtDirection)); + XRPL_ASSERT( + static_cast(this)->verifyPrevStepDebtDirection( + prevStepDebtDirection), + "ripple::DirectStepI::qualitiesSrcIssues : will prevStepDebtDirection " + "issue"); std::uint32_t const srcQOut = redeems(prevStepDebtDirection) ? transferRate(sb, src_).value @@ -924,7 +929,9 @@ DirectStepI::check(StrandContext const& ctx) const { if (!ctx.prevStep) { - assert(0); // prev seen book without a prev step!?! + UNREACHABLE( + "ripple::DirectStepI::check : prev seen book without a " + "prev step"); return temBAD_PATH_LOOP; } diff --git a/src/xrpld/app/paths/detail/FlowDebugInfo.h b/src/xrpld/app/paths/detail/FlowDebugInfo.h index 000db4e5714..4c3ea5faf1b 100644 --- a/src/xrpld/app/paths/detail/FlowDebugInfo.h +++ b/src/xrpld/app/paths/detail/FlowDebugInfo.h @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include #include @@ -89,7 +89,10 @@ struct FlowDebugInfo void pushLiquiditySrc(EitherAmount const& eIn, EitherAmount const& eOut) { - assert(!liquiditySrcIn.empty()); + XRPL_ASSERT( + !liquiditySrcIn.empty(), + "ripple::path::detail::FlowDebugInfo::pushLiquiditySrc : " + "non-empty liquidity source"); liquiditySrcIn.back().push_back(eIn); liquiditySrcOut.back().push_back(eOut); } @@ -122,7 +125,9 @@ struct FlowDebugInfo auto i = timePoints.find(tag); if (i == timePoints.end()) { - assert(0); + UNREACHABLE( + "ripple::path::detail::FlowDebugInfo::duration : timepoint not " + "found"); return std::chrono::duration(0); } auto const& t = i->second; diff --git a/src/xrpld/app/paths/detail/PaySteps.cpp b/src/xrpld/app/paths/detail/PaySteps.cpp index f28c1b96a7c..b73b1ac8acc 100644 --- a/src/xrpld/app/paths/detail/PaySteps.cpp +++ b/src/xrpld/app/paths/detail/PaySteps.cpp @@ -19,11 +19,12 @@ #include #include -#include -#include #include +#include #include #include +#include +#include #include #include @@ -100,13 +101,14 @@ toStep( // should already be taken care of JLOG(j.error()) << "Found offer/account payment step. Aborting payment strand."; - assert(0); + UNREACHABLE("ripple::toStep : offer/account payment payment strand"); return {temBAD_PATH, std::unique_ptr{}}; } - assert( + XRPL_ASSERT( (e2->getNodeType() & STPathElement::typeCurrency) || - (e2->getNodeType() & STPathElement::typeIssuer)); + (e2->getNodeType() & STPathElement::typeIssuer), + "ripple::toStep : currency or issuer"); auto const outCurrency = e2->getNodeType() & STPathElement::typeCurrency ? e2->getCurrency() : curIssue.currency; @@ -120,7 +122,7 @@ toStep( return {temBAD_PATH, std::unique_ptr{}}; } - assert(e2->isOffer()); + XRPL_ASSERT(e2->isOffer(), "ripple::toStep : is offer"); if (isXRP(outCurrency)) return make_BookStepIX(ctx, curIssue); @@ -391,7 +393,7 @@ toStrand( next->getCurrency() != curIssue.currency) { // Should never happen - assert(0); + UNREACHABLE("ripple::toStrand : offer currency mismatch"); return {temBAD_PATH, Strand{}}; } @@ -457,7 +459,7 @@ toStrand( if (!checkStrand()) { JLOG(j.warn()) << "Flow check strand failed"; - assert(0); + UNREACHABLE("ripple::toStrand : invalid strand"); return {temBAD_PATH, Strand{}}; } diff --git a/src/xrpld/app/paths/detail/StepChecks.h b/src/xrpld/app/paths/detail/StepChecks.h index 140c9d1fe46..2c2fee91cf9 100644 --- a/src/xrpld/app/paths/detail/StepChecks.h +++ b/src/xrpld/app/paths/detail/StepChecks.h @@ -35,7 +35,7 @@ checkFreeze( AccountID const& dst, Currency const& currency) { - assert(src != dst); + XRPL_ASSERT(src != dst, "ripple::checkFreeze : unequal input accounts"); // check freeze if (auto sle = view.read(keylet::account(dst))) diff --git a/src/xrpld/app/paths/detail/StrandFlow.h b/src/xrpld/app/paths/detail/StrandFlow.h index 329a4cc643f..0e168b73cce 100644 --- a/src/xrpld/app/paths/detail/StrandFlow.h +++ b/src/xrpld/app/paths/detail/StrandFlow.h @@ -28,10 +28,11 @@ #include #include #include -#include #include -#include +#include #include +#include +#include #include @@ -171,7 +172,9 @@ flow( << "Re-executed limiting step failed. r.first: " << to_string(get(r.first)) << " maxIn: " << to_string(*maxIn); - assert(0); + UNREACHABLE( + "ripple::flow : first step re-executing the " + "limiting step failed"); return Result{strand, std::move(ofrsToRm)}; } } @@ -207,7 +210,9 @@ flow( #else JLOG(j.fatal()) << "Re-executed limiting step failed"; #endif - assert(0); + UNREACHABLE( + "ripple::flow : limiting step re-executing the " + "limiting step failed"); return Result{strand, std::move(ofrsToRm)}; } } @@ -241,7 +246,9 @@ flow( #else JLOG(j.fatal()) << "Re-executed forward pass failed"; #endif - assert(0); + UNREACHABLE( + "ripple::flow : non-limiting step re-executing the " + "forward pass failed"); return Result{strand, std::move(ofrsToRm)}; } stepIn = r.second; @@ -493,7 +500,7 @@ class ActiveStrands { if (i >= cur_.size()) { - assert(0); + UNREACHABLE("ripple::ActiveStrands::get : input out of range"); return nullptr; } return cur_[i]; @@ -700,9 +707,10 @@ flow( flowDebugInfo->pushLiquiditySrc( EitherAmount(f.in), EitherAmount(f.out)); - assert( + XRPL_ASSERT( f.out <= remainingOut && f.sandbox && - (!remainingIn || f.in <= *remainingIn)); + (!remainingIn || f.in <= *remainingIn), + "ripple::flow : remaining constraints"); Quality const q(f.out, f.in); @@ -725,7 +733,7 @@ flow( if (baseView.rules().enabled(featureFlowSortStrands)) { - assert(!best); + XRPL_ASSERT(!best, "ripple::flow : best is unset"); if (!f.inactive) activeStrands.push(strand); best.emplace(f.in, f.out, std::move(*f.sandbox), *strand, q); @@ -839,7 +847,7 @@ flow( // running debug builds of rippled. While this issue still needs to // be resolved, the assert is causing more harm than good at this // point. - // assert(0); + // UNREACHABLE("ripple::flow : rounding error"); return {tefEXCEPTION, std::move(ofrsToRmOnFail)}; } @@ -876,7 +884,7 @@ flow( // Handles both cases 1. and 2. // fixFillOrKill amendment: // Handles 2. 1. is handled above and falls through for tfSell. - assert(remainingIn); + XRPL_ASSERT(remainingIn, "ripple::flow : nonzero remainingIn"); if (remainingIn && *remainingIn != beast::zero) return { tecPATH_PARTIAL, diff --git a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp index ac178cbe2f2..ab211a7c856 100644 --- a/src/xrpld/app/paths/detail/XRPEndpointStep.cpp +++ b/src/xrpld/app/paths/detail/XRPEndpointStep.cpp @@ -22,11 +22,11 @@ #include #include #include -#include #include -#include #include +#include #include +#include #include @@ -281,7 +281,7 @@ XRPEndpointStep::fwdImp( boost::container::flat_set& ofrsToRm, XRPAmount const& in) { - assert(cache_); + XRPL_ASSERT(cache_, "ripple::XRPEndpointStep::fwdImp : cache is set"); auto const balance = static_cast(this)->xrpLiquid(sb); auto const result = isLast_ ? in : std::min(balance, in); @@ -309,7 +309,7 @@ XRPEndpointStep::validFwd( return {false, EitherAmount(XRPAmount(beast::zero))}; } - assert(in.native); + XRPL_ASSERT(in.native, "ripple::XRPEndpointStep::validFwd : input is XRP"); auto const& xrpIn = in.xrp; auto const balance = static_cast(this)->xrpLiquid(sb); diff --git a/src/xrpld/app/rdb/RelationalDatabase.h b/src/xrpld/app/rdb/RelationalDatabase.h index 5b06aa24d0e..a7528e2370d 100644 --- a/src/xrpld/app/rdb/RelationalDatabase.h +++ b/src/xrpld/app/rdb/RelationalDatabase.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -235,7 +236,7 @@ rangeCheckedCast(C c) c < std::numeric_limits::lowest())) { /* This should never happen */ - assert(0); + UNREACHABLE("ripple::rangeCheckedCast : domain error"); JLOG(debugLog().error()) << "rangeCheckedCast domain error:" << " value = " << c << " min = " << std::numeric_limits::lowest() diff --git a/src/xrpld/app/rdb/backend/detail/Node.cpp b/src/xrpld/app/rdb/backend/detail/Node.cpp index 2ea6bd12c62..493e277bfcd 100644 --- a/src/xrpld/app/rdb/backend/detail/Node.cpp +++ b/src/xrpld/app/rdb/backend/detail/Node.cpp @@ -58,7 +58,7 @@ to_string(TableType type) case TableType::AccountTransactions: return "AccountTransactions"; default: - assert(false); + UNREACHABLE("ripple::detail::to_string : invalid TableType"); return "Unknown"; } } @@ -202,7 +202,7 @@ saveValidatedLedger( if (!ledger->info().accountHash.isNonZero()) { JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}}); - assert(false); + UNREACHABLE("ripple::detail::saveValidatedLedger : zero account hash"); } if (ledger->info().accountHash != ledger->stateMap().getHash().as_uint256()) @@ -211,10 +211,13 @@ saveValidatedLedger( << " != " << ledger->stateMap().getHash(); JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq << ", current=" << current; - assert(false); + UNREACHABLE( + "ripple::detail::saveValidatedLedger : mismatched account hash"); } - assert(ledger->info().txHash == ledger->txMap().getHash().as_uint256()); + XRPL_ASSERT( + ledger->info().txHash == ledger->txMap().getHash().as_uint256(), + "ripple::detail::saveValidatedLedger : transaction hash match"); // Save the ledger header in the hashed object store { diff --git a/src/xrpld/app/rdb/detail/Vacuum.cpp b/src/xrpld/app/rdb/detail/Vacuum.cpp index cc7f01a8409..3c61fb5790a 100644 --- a/src/xrpld/app/rdb/detail/Vacuum.cpp +++ b/src/xrpld/app/rdb/detail/Vacuum.cpp @@ -28,7 +28,9 @@ doVacuumDB(DatabaseCon::Setup const& setup, beast::Journal j) boost::filesystem::path dbPath = setup.dataDir / TxDBName; uintmax_t const dbSize = file_size(dbPath); - assert(dbSize != static_cast(-1)); + XRPL_ASSERT( + dbSize != static_cast(-1), + "ripple:doVacuumDB : file_size succeeded"); if (auto available = space(dbPath.parent_path()).available; available < dbSize) @@ -54,7 +56,8 @@ doVacuumDB(DatabaseCon::Setup const& setup, beast::Journal j) std::cout << "VACUUM beginning. page_size: " << pageSize << std::endl; session << "VACUUM;"; - assert(setup.globalPragma); + XRPL_ASSERT( + setup.globalPragma, "ripple:doVacuumDB : non-null global pragma"); for (auto const& p : *setup.globalPragma) session << p; session << "PRAGMA page_size;", soci::into(pageSize); diff --git a/src/xrpld/app/tx/detail/AMMBid.cpp b/src/xrpld/app/tx/detail/AMMBid.cpp index 9de3762d2e3..e8a14c14922 100644 --- a/src/xrpld/app/tx/detail/AMMBid.cpp +++ b/src/xrpld/app/tx/detail/AMMBid.cpp @@ -46,7 +46,8 @@ AMMBid::preflight(PreflightContext const& ctx) return temINVALID_FLAG; } - if (auto const res = invalidAMMAssetPair(ctx.tx[sfAsset], ctx.tx[sfAsset2])) + if (auto const res = invalidAMMAssetPair( + ctx.tx[sfAsset].get(), ctx.tx[sfAsset2].get())) { JLOG(ctx.j.debug()) << "AMM Bid: Invalid asset pair."; return res; @@ -181,7 +182,9 @@ applyBid( } else { - assert(ammSle->isFieldPresent(sfAuctionSlot)); + XRPL_ASSERT( + ammSle->isFieldPresent(sfAuctionSlot), + "ripple::applyBid : has auction slot"); if (!ammSle->isFieldPresent(sfAuctionSlot)) return {tecINTERNAL, false}; } @@ -304,7 +307,7 @@ applyBid( { // Price the slot was purchased at. STAmount const pricePurchased = auctionSlot[sfPrice]; - assert(timeSlot); + XRPL_ASSERT(timeSlot, "ripple::applyBid : timeSlot is set"); auto const fractionUsed = (Number(*timeSlot) + 1) / AUCTION_SLOT_TIME_INTERVALS; auto const fractionRemaining = Number(1) - fractionUsed; diff --git a/src/xrpld/app/tx/detail/AMMClawback.cpp b/src/xrpld/app/tx/detail/AMMClawback.cpp index cd1e3008e97..162224ff913 100644 --- a/src/xrpld/app/tx/detail/AMMClawback.cpp +++ b/src/xrpld/app/tx/detail/AMMClawback.cpp @@ -57,8 +57,8 @@ AMMClawback::preflight(PreflightContext const& ctx) } std::optional const clawAmount = ctx.tx[~sfAmount]; - auto const asset = ctx.tx[sfAsset]; - auto const asset2 = ctx.tx[sfAsset2]; + auto const asset = ctx.tx[sfAsset].get(); + auto const asset2 = ctx.tx[sfAsset2].get(); if (isXRP(asset)) return temMALFORMED; @@ -78,7 +78,7 @@ AMMClawback::preflight(PreflightContext const& ctx) return temMALFORMED; } - if (clawAmount && clawAmount->issue() != asset) + if (clawAmount && clawAmount->get() != asset) { JLOG(ctx.j.trace()) << "AMMClawback: Amount's issuer/currency subfield " "does not match Asset field"; @@ -94,8 +94,8 @@ AMMClawback::preflight(PreflightContext const& ctx) TER AMMClawback::preclaim(PreclaimContext const& ctx) { - auto const asset = ctx.tx[sfAsset]; - auto const asset2 = ctx.tx[sfAsset2]; + auto const asset = ctx.tx[sfAsset].get(); + auto const asset2 = ctx.tx[sfAsset2].get(); auto const sleIssuer = ctx.view.read(keylet::account(ctx.tx[sfAccount])); if (!sleIssuer) return terNO_ACCOUNT; // LCOV_EXCL_LINE @@ -139,8 +139,8 @@ AMMClawback::applyGuts(Sandbox& sb) std::optional const clawAmount = ctx_.tx[~sfAmount]; AccountID const issuer = ctx_.tx[sfAccount]; AccountID const holder = ctx_.tx[sfHolder]; - Issue const asset = ctx_.tx[sfAsset]; - Issue const asset2 = ctx_.tx[sfAsset2]; + Issue const asset = ctx_.tx[sfAsset].get(); + Issue const asset2 = ctx_.tx[sfAsset2].get(); auto ammSle = sb.peek(keylet::amm(asset, asset2)); if (!ammSle) diff --git a/src/xrpld/app/tx/detail/AMMDelete.cpp b/src/xrpld/app/tx/detail/AMMDelete.cpp index 89ce34052d2..430ac17e87b 100644 --- a/src/xrpld/app/tx/detail/AMMDelete.cpp +++ b/src/xrpld/app/tx/detail/AMMDelete.cpp @@ -72,8 +72,8 @@ AMMDelete::doApply() // as we go on processing transactions. Sandbox sb(&ctx_.view()); - auto const ter = - deleteAMMAccount(sb, ctx_.tx[sfAsset], ctx_.tx[sfAsset2], j_); + auto const ter = deleteAMMAccount( + sb, ctx_.tx[sfAsset].get(), ctx_.tx[sfAsset2].get(), j_); if (ter == tesSUCCESS || ter == tecINCOMPLETE) sb.apply(ctx_.rawView()); diff --git a/src/xrpld/app/tx/detail/AMMDeposit.cpp b/src/xrpld/app/tx/detail/AMMDeposit.cpp index 3448401eb79..675f560098c 100644 --- a/src/xrpld/app/tx/detail/AMMDeposit.cpp +++ b/src/xrpld/app/tx/detail/AMMDeposit.cpp @@ -100,8 +100,8 @@ AMMDeposit::preflight(PreflightContext const& ctx) return temMALFORMED; } - auto const asset = ctx.tx[sfAsset]; - auto const asset2 = ctx.tx[sfAsset2]; + auto const asset = ctx.tx[sfAsset].get(); + auto const asset2 = ctx.tx[sfAsset2].get(); if (auto const res = invalidAMMAssetPair(asset, asset2)) { JLOG(ctx.j.debug()) << "AMM Deposit: invalid asset pair."; @@ -268,10 +268,10 @@ AMMDeposit::preclaim(PreclaimContext const& ctx) return tesSUCCESS; }; - if (auto const ter = checkAsset(ctx.tx[sfAsset])) + if (auto const ter = checkAsset(ctx.tx[sfAsset].get())) return ter; - if (auto const ter = checkAsset(ctx.tx[sfAsset2])) + if (auto const ter = checkAsset(ctx.tx[sfAsset2].get())) return ter; } @@ -466,7 +466,9 @@ AMMDeposit::applyGuts(Sandbox& sb) if (result == tesSUCCESS) { - assert(newLPTokenBalance > beast::zero); + XRPL_ASSERT( + newLPTokenBalance > beast::zero, + "ripple::AMMDeposit::applyGuts : valid new LP token balance"); ammSle->setFieldAmount(sfLPTokenBalance, newLPTokenBalance); // LP depositing into AMM empty state gets the auction slot // and the voting diff --git a/src/xrpld/app/tx/detail/AMMVote.cpp b/src/xrpld/app/tx/detail/AMMVote.cpp index c4b6c612c63..1b8b91e518a 100644 --- a/src/xrpld/app/tx/detail/AMMVote.cpp +++ b/src/xrpld/app/tx/detail/AMMVote.cpp @@ -38,7 +38,8 @@ AMMVote::preflight(PreflightContext const& ctx) if (auto const ret = preflight1(ctx); !isTesSuccess(ret)) return ret; - if (auto const res = invalidAMMAssetPair(ctx.tx[sfAsset], ctx.tx[sfAsset2])) + if (auto const res = invalidAMMAssetPair( + ctx.tx[sfAsset].get(), ctx.tx[sfAsset2].get())) { JLOG(ctx.j.debug()) << "AMM Vote: invalid asset pair."; return res; @@ -200,9 +201,10 @@ applyVote( } } - assert( + XRPL_ASSERT( !ctx_.view().rules().enabled(fixInnerObjTemplate) || - ammSle->isFieldPresent(sfAuctionSlot)); + ammSle->isFieldPresent(sfAuctionSlot), + "ripple::applyVote : has auction slot"); // Update the vote entries and the trading/discounted fee. ammSle->setFieldArray(sfVoteSlots, updatedVoteSlots); diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp index 118262905c1..23e8529cfc9 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.cpp +++ b/src/xrpld/app/tx/detail/AMMWithdraw.cpp @@ -100,8 +100,8 @@ AMMWithdraw::preflight(PreflightContext const& ctx) return temMALFORMED; } - auto const asset = ctx.tx[sfAsset]; - auto const asset2 = ctx.tx[sfAsset2]; + auto const asset = ctx.tx[sfAsset].get(); + auto const asset2 = ctx.tx[sfAsset2].get(); if (auto const res = invalidAMMAssetPair(asset, asset2)) { JLOG(ctx.j.debug()) << "AMM Withdraw: Invalid asset pair."; @@ -418,7 +418,12 @@ AMMWithdraw::applyGuts(Sandbox& sb) return {result, false}; auto const res = deleteAMMAccountIfEmpty( - sb, ammSle, newLPTokenBalance, ctx_.tx[sfAsset], ctx_.tx[sfAsset2], j_); + sb, + ammSle, + newLPTokenBalance, + ctx_.tx[sfAsset].get(), + ctx_.tx[sfAsset2].get(), + j_); // LCOV_EXCL_START if (!res.second) return {res.first, false}; @@ -877,7 +882,9 @@ AMMWithdraw::equalWithdrawLimit( frac = Number{amount2} / amount2Balance; auto const amountWithdraw = amountBalance * frac; - assert(amountWithdraw <= amount); + XRPL_ASSERT( + amountWithdraw <= amount, + "ripple::AMMWithdraw::equalWithdrawLimit : maximum amountWithdraw"); return withdraw( view, ammSle, diff --git a/src/xrpld/app/tx/detail/ApplyContext.cpp b/src/xrpld/app/tx/detail/ApplyContext.cpp index 969af7960eb..620c286bd73 100644 --- a/src/xrpld/app/tx/detail/ApplyContext.cpp +++ b/src/xrpld/app/tx/detail/ApplyContext.cpp @@ -21,10 +21,10 @@ #include #include #include +#include #include #include #include -#include namespace ripple { @@ -146,7 +146,9 @@ ApplyContext::checkInvariantsHelper( TER ApplyContext::checkInvariants(TER const result, XRPAmount const fee) { - assert(isTesSuccess(result) || isTecClaim(result)); + XRPL_ASSERT( + isTesSuccess(result) || isTecClaim(result), + "ripple::ApplyContext::checkInvariants : is tesSUCCESS or tecCLAIM"); return checkInvariantsHelper( result, diff --git a/src/xrpld/app/tx/detail/ApplyContext.h b/src/xrpld/app/tx/detail/ApplyContext.h index 45de05a73db..6ffe7a4d576 100644 --- a/src/xrpld/app/tx/detail/ApplyContext.h +++ b/src/xrpld/app/tx/detail/ApplyContext.h @@ -23,9 +23,9 @@ #include #include #include -#include #include #include +#include #include #include diff --git a/src/xrpld/app/tx/detail/Change.cpp b/src/xrpld/app/tx/detail/Change.cpp index 909f35fc799..45834742c8e 100644 --- a/src/xrpld/app/tx/detail/Change.cpp +++ b/src/xrpld/app/tx/detail/Change.cpp @@ -149,7 +149,7 @@ Change::doApply() case ttUNL_MODIFY: return applyUNLModify(); default: - assert(0); + UNREACHABLE("ripple::Change::doApply : invalid transaction type"); return tefFAILURE; } } @@ -157,7 +157,8 @@ Change::doApply() void Change::preCompute() { - assert(account_ == beast::zero); + XRPL_ASSERT( + account_ == beast::zero, "ripple::Change::preCompute : zero account"); } void diff --git a/src/xrpld/app/tx/detail/Clawback.cpp b/src/xrpld/app/tx/detail/Clawback.cpp index f1040790a42..d60acf9fd73 100644 --- a/src/xrpld/app/tx/detail/Clawback.cpp +++ b/src/xrpld/app/tx/detail/Clawback.cpp @@ -19,9 +19,9 @@ #include #include -#include #include #include +#include #include #include #include diff --git a/src/xrpld/app/tx/detail/CreateOffer.cpp b/src/xrpld/app/tx/detail/CreateOffer.cpp index 2a5145594a1..52ca602b956 100644 --- a/src/xrpld/app/tx/detail/CreateOffer.cpp +++ b/src/xrpld/app/tx/detail/CreateOffer.cpp @@ -210,7 +210,9 @@ CreateOffer::checkAcceptAsset( Issue const& issue) { // Only valid for custom currencies - assert(!isXRP(issue.currency)); + XRPL_ASSERT( + !isXRP(issue.currency), + "ripple::CreateOffer::checkAcceptAsset : input is not XRP"); auto const issuerAccount = view.read(keylet::account(issue.account)); @@ -283,7 +285,9 @@ CreateOffer::select_path( OfferStream const& leg2) { // If we don't have any viable path, why are we here?! - assert(have_direct || have_bridge); + XRPL_ASSERT( + have_direct || have_bridge, + "ripple::CreateOffer::select_path : valid inputs"); // If there's no bridged path, the direct is the best by default. if (!have_bridge) @@ -327,7 +331,9 @@ CreateOffer::bridged_cross( { auto const& takerAmount = taker.original_offer(); - assert(!isXRP(takerAmount.in) && !isXRP(takerAmount.out)); + XRPL_ASSERT( + !isXRP(takerAmount.in) && !isXRP(takerAmount.out), + "ripple::CreateOffer::bridged_cross : neither is XRP"); if (isXRP(takerAmount.in) || isXRP(takerAmount.out)) Throw("Bridging with XRP and an endpoint."); @@ -497,7 +503,9 @@ CreateOffer::bridged_cross( // Postcondition: If we aren't done, then we *must* have consumed at // least one offer fully. - assert(direct_consumed || leg1_consumed || leg2_consumed); + XRPL_ASSERT( + direct_consumed || leg1_consumed || leg2_consumed, + "ripple::CreateOffer::bridged_cross : consumed an offer"); if (!direct_consumed && !leg1_consumed && !leg2_consumed) Throw( @@ -587,7 +595,9 @@ CreateOffer::direct_cross( // Postcondition: If we aren't done, then we *must* have consumed the // offer on the books fully! - assert(direct_consumed); + XRPL_ASSERT( + direct_consumed, + "ripple::CreateOffer::direct_cross : consumed an offer"); if (!direct_consumed) Throw( @@ -849,7 +859,9 @@ CreateOffer::flowCross( // remaining output. This too preserves the offer // Quality. afterCross.out -= result.actualAmountOut; - assert(afterCross.out >= beast::zero); + XRPL_ASSERT( + afterCross.out >= beast::zero, + "ripple::CreateOffer::flowCross : minimum offer"); if (afterCross.out < beast::zero) afterCross.out.clear(); afterCross.in = mulRound( @@ -1046,7 +1058,10 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) // We expect the implementation of cross to succeed // or give a tec. - assert(result == tesSUCCESS || isTecClaim(result)); + XRPL_ASSERT( + result == tesSUCCESS || isTecClaim(result), + "ripple::CreateOffer::applyGuts : result is tesSUCCESS or " + "tecCLAIM"); if (auto stream = j_.trace()) { @@ -1064,8 +1079,12 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) return {result, true}; } - assert(saTakerGets.issue() == place_offer.in.issue()); - assert(saTakerPays.issue() == place_offer.out.issue()); + XRPL_ASSERT( + saTakerGets.issue() == place_offer.in.issue(), + "ripple::CreateOffer::applyGuts : taker gets issue match"); + XRPL_ASSERT( + saTakerPays.issue() == place_offer.out.issue(), + "ripple::CreateOffer::applyGuts : taker pays issue match"); if (takerAmount != place_offer) crossed = true; @@ -1093,7 +1112,9 @@ CreateOffer::applyGuts(Sandbox& sb, Sandbox& sbCancel) saTakerGets = place_offer.in; } - assert(saTakerPays > zero && saTakerGets > zero); + XRPL_ASSERT( + saTakerPays > zero && saTakerGets > zero, + "ripple::CreateOffer::applyGuts : taker pays and gets positive"); if (result != tesSUCCESS) { diff --git a/src/xrpld/app/tx/detail/DeleteAccount.cpp b/src/xrpld/app/tx/detail/DeleteAccount.cpp index a7f33a3d8dd..18ddf01a8d7 100644 --- a/src/xrpld/app/tx/detail/DeleteAccount.cpp +++ b/src/xrpld/app/tx/detail/DeleteAccount.cpp @@ -25,10 +25,11 @@ #include #include #include -#include #include #include +#include #include +#include #include #include #include @@ -242,7 +243,8 @@ DeleteAccount::preclaim(PreclaimContext const& ctx) } auto sleAccount = ctx.view.read(keylet::account(account)); - assert(sleAccount); + XRPL_ASSERT( + sleAccount, "ripple::DeleteAccount::preclaim : non-null account"); if (!sleAccount) return terNO_ACCOUNT; @@ -345,11 +347,13 @@ TER DeleteAccount::doApply() { auto src = view().peek(keylet::account(account_)); - assert(src); + XRPL_ASSERT( + src, "ripple::DeleteAccount::doApply : non-null source account"); auto const dstID = ctx_.tx[sfDestination]; auto dst = view().peek(keylet::account(dstID)); - assert(dst); + XRPL_ASSERT( + dst, "ripple::DeleteAccount::doApply : non-null destination account"); if (!src || !dst) return tefBAD_LEDGER; @@ -377,7 +381,9 @@ DeleteAccount::doApply() return {result, SkipEntry::No}; } - assert(!"Undeletable entry should be found in preclaim."); + UNREACHABLE( + "ripple::DeleteAccount::doApply : undeletable item not found " + "in preclaim"); JLOG(j_.error()) << "DeleteAccount undeletable item not " "found in preclaim."; return {tecHAS_OBLIGATIONS, SkipEntry::No}; @@ -391,7 +397,9 @@ DeleteAccount::doApply() (*src)[sfBalance] = (*src)[sfBalance] - mSourceBalance; ctx_.deliver(mSourceBalance); - assert((*src)[sfBalance] == XRPAmount(0)); + XRPL_ASSERT( + (*src)[sfBalance] == XRPAmount(0), + "ripple::DeleteAccount::doApply : source balance is zero"); // If there's still an owner directory associated with the source account // delete it. diff --git a/src/xrpld/app/tx/detail/Escrow.cpp b/src/xrpld/app/tx/detail/Escrow.cpp index f98e72f23dd..48b9867d3a0 100644 --- a/src/xrpld/app/tx/detail/Escrow.cpp +++ b/src/xrpld/app/tx/detail/Escrow.cpp @@ -26,12 +26,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index 90fc399b344..def7914a49b 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -22,9 +22,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -381,7 +381,8 @@ AccountRootsDeletedClean::finalize( // transaction processing results, however unlikely, only fail if the // feature is enabled. Enabled, or not, though, a fatal-level message will // be logged - bool const enforce = view.rules().enabled(featureInvariantsV1_1); + [[maybe_unused]] bool const enforce = + view.rules().enabled(featureInvariantsV1_1); auto const objectExists = [&view, enforce, &j](auto const& keylet) { if (auto const sle = view.read(keylet)) @@ -399,8 +400,10 @@ AccountRootsDeletedClean::finalize( JLOG(j.fatal()) << "Invariant failed: account deletion left behind a " << typeName << " object"; - (void)enforce; - assert(enforce); + XRPL_ASSERT( + enforce, + "ripple::AccountRootsDeletedClean::finalize::objectExists : " + "account deletion left no objects behind"); return true; } return false; diff --git a/src/xrpld/app/tx/detail/NFTokenMint.cpp b/src/xrpld/app/tx/detail/NFTokenMint.cpp index d5c3a8707c2..5699a29c039 100644 --- a/src/xrpld/app/tx/detail/NFTokenMint.cpp +++ b/src/xrpld/app/tx/detail/NFTokenMint.cpp @@ -160,7 +160,9 @@ NFTokenMint::createNFTokenID( std::memcpy(ptr, &tokenSeq, sizeof(tokenSeq)); ptr += sizeof(tokenSeq); - assert(std::distance(buf.data(), ptr) == buf.size()); + XRPL_ASSERT( + std::distance(buf.data(), ptr) == buf.size(), + "ripple::NFTokenMint::createNFTokenID : data size matches the buffer"); return uint256::fromVoid(buf.data()); } diff --git a/src/xrpld/app/tx/detail/NFTokenUtils.cpp b/src/xrpld/app/tx/detail/NFTokenUtils.cpp index 61ff8e200b3..07edfe1b79a 100644 --- a/src/xrpld/app/tx/detail/NFTokenUtils.cpp +++ b/src/xrpld/app/tx/detail/NFTokenUtils.cpp @@ -191,7 +191,9 @@ getPageForToken( : carr[0].getFieldH256(sfNFTokenID); auto np = std::make_shared(keylet::nftpage(base, tokenIDForNewPage)); - assert(np->key() > base.key); + XRPL_ASSERT( + np->key() > base.key, + "ripple::nft::getPageForToken : valid NFT page index"); np->setFieldArray(sfNFTokens, narr); np->setFieldH256(sfNextPageMin, cp->key()); @@ -243,7 +245,9 @@ compareTokens(uint256 const& a, uint256 const& b) TER insertToken(ApplyView& view, AccountID owner, STObject&& nft) { - assert(nft.isFieldPresent(sfNFTokenID)); + XRPL_ASSERT( + nft.isFieldPresent(sfNFTokenID), + "ripple::nft::insertToken : has NFT token"); // First, we need to locate the page the NFT belongs to, creating it // if necessary. This operation may fail if it is impossible to insert @@ -783,7 +787,9 @@ repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner) return didRepair; } - assert(nextPage); + XRPL_ASSERT( + nextPage, + "ripple::nft::repairNFTokenDirectoryLinks : next page is available"); if (nextPage->isFieldPresent(sfNextPageMin)) { didRepair = true; @@ -891,7 +897,8 @@ tokenOfferCreatePreclaim( if (nftIssuer != acctID && !(nftFlags & nft::flagTransferable)) { auto const root = view.read(keylet::account(nftIssuer)); - assert(root); + XRPL_ASSERT( + root, "ripple::nft::tokenOfferCreatePreclaim : non-null account"); if (auto minter = (*root)[~sfNFTokenMinter]; minter != acctID) return tefNFTOKEN_IS_NOT_TRANSFERABLE; diff --git a/src/xrpld/app/tx/detail/Offer.h b/src/xrpld/app/tx/detail/Offer.h index a6f707ba561..23129952c3d 100644 --- a/src/xrpld/app/tx/detail/Offer.h +++ b/src/xrpld/app/tx/detail/Offer.h @@ -209,7 +209,7 @@ void TOffer::setFieldAmounts() { #ifdef _MSC_VER - assert(0); + UNREACHABLE("ripple::TOffer::setFieldAmounts : must be specialized"); #else static_assert(sizeof(TOut) == -1, "Must be specialized"); #endif diff --git a/src/xrpld/app/tx/detail/OfferStream.cpp b/src/xrpld/app/tx/detail/OfferStream.cpp index b963195259a..ea18306234b 100644 --- a/src/xrpld/app/tx/detail/OfferStream.cpp +++ b/src/xrpld/app/tx/detail/OfferStream.cpp @@ -51,7 +51,8 @@ TOfferStreamBase::TOfferStreamBase( , tip_(view, book_) , counter_(counter) { - assert(validBook_); + XRPL_ASSERT( + validBook_, "ripple::TOfferStreamBase::TOfferStreamBase : valid book"); } // Handle the case where a directory item with no corresponding ledger entry @@ -339,7 +340,9 @@ TOfferStreamBase::step() std::is_same_v)) return shouldRmSmallIncreasedQOffer(); } - assert(0); // xrp/xrp offer!?! should never happen + UNREACHABLE( + "rippls::TOfferStreamBase::step::rmSmallIncreasedQOffer : XRP " + "vs XRP offer"); return false; }(); diff --git a/src/xrpld/app/tx/detail/PayChan.cpp b/src/xrpld/app/tx/detail/PayChan.cpp index b2d4c0c9449..aa248075d56 100644 --- a/src/xrpld/app/tx/detail/PayChan.cpp +++ b/src/xrpld/app/tx/detail/PayChan.cpp @@ -22,13 +22,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include @@ -150,7 +150,9 @@ closeChannel( if (!sle) return tefINTERNAL; - assert((*slep)[sfAmount] >= (*slep)[sfBalance]); + XRPL_ASSERT( + (*slep)[sfAmount] >= (*slep)[sfBalance], + "ripple::closeChannel : minimum channel amount"); (*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance]; adjustOwnerCount(view, sle, -1, j); @@ -546,7 +548,9 @@ PayChanClaim::doApply() (*slep)[sfBalance] = ctx_.tx[sfBalance]; XRPAmount const reqDelta = reqBalance - chanBalance; - assert(reqDelta >= beast::zero); + XRPL_ASSERT( + reqDelta >= beast::zero, + "ripple::PayChanClaim::doApply : minimum balance delta"); (*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta; ctx_.view().update(sled); ctx_.view().update(slep); diff --git a/src/xrpld/app/tx/detail/Payment.cpp b/src/xrpld/app/tx/detail/Payment.cpp index 2be784306cd..1ed3bacbbd8 100644 --- a/src/xrpld/app/tx/detail/Payment.cpp +++ b/src/xrpld/app/tx/detail/Payment.cpp @@ -525,7 +525,7 @@ Payment::doApply() return res; } - assert(dstAmount.native()); + XRPL_ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP"); // Direct XRP payment. diff --git a/src/xrpld/app/tx/detail/SetSignerList.cpp b/src/xrpld/app/tx/detail/SetSignerList.cpp index 0949fbbe775..a74b0f7351c 100644 --- a/src/xrpld/app/tx/detail/SetSignerList.cpp +++ b/src/xrpld/app/tx/detail/SetSignerList.cpp @@ -128,7 +128,7 @@ SetSignerList::doApply() default: break; } - assert(false); // Should not be possible to get here. + UNREACHABLE("ripple::SetSignerList::doApply : invalid operation"); return temMALFORMED; } @@ -137,8 +137,12 @@ SetSignerList::preCompute() { // Get the quorum and operation info. auto result = determineOperation(ctx_.tx, view().flags(), j_); - assert(std::get<0>(result) == tesSUCCESS); - assert(std::get<3>(result) != unknown); + XRPL_ASSERT( + std::get<0>(result) == tesSUCCESS, + "ripple::SetSignerList::preCompute : result is tesSUCCESS"); + XRPL_ASSERT( + std::get<3>(result) != unknown, + "ripple::SetSignerList::preCompute : result is known operation"); quorum_ = std::get<1>(result); signers_ = std::get<2>(result); @@ -171,8 +175,12 @@ signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules) // The static_cast should always be safe since entryCount should always // be in the range from 1 to 8 (or 32 if ExpandedSignerList is enabled). // We've got a lot of room to grow. - assert(entryCount >= STTx::minMultiSigners); - assert(entryCount <= STTx::maxMultiSigners(&rules)); + XRPL_ASSERT( + entryCount >= STTx::minMultiSigners, + "ripple::signerCountBasedOwnerCountDelta : minimum signers"); + XRPL_ASSERT( + entryCount <= STTx::maxMultiSigners(&rules), + "ripple::signerCountBasedOwnerCountDelta : maximum signers"); return 2 + static_cast(entryCount); } @@ -260,7 +268,10 @@ SetSignerList::validateQuorumAndSignerEntries( } // Make sure there are no duplicate signers. - assert(std::is_sorted(signers.begin(), signers.end())); + XRPL_ASSERT( + std::is_sorted(signers.begin(), signers.end()), + "ripple::SetSignerList::validateQuorumAndSignerEntries : sorted " + "signers"); if (std::adjacent_find(signers.begin(), signers.end()) != signers.end()) { JLOG(j.trace()) << "Duplicate signers in signer list"; diff --git a/src/xrpld/app/tx/detail/Taker.cpp b/src/xrpld/app/tx/detail/Taker.cpp index 9d335de2846..e98d65fd114 100644 --- a/src/xrpld/app/tx/detail/Taker.cpp +++ b/src/xrpld/app/tx/detail/Taker.cpp @@ -54,24 +54,34 @@ BasicTaker::BasicTaker( , cross_type_(cross_type) , journal_(journal) { - assert(remaining_.in > beast::zero); - assert(remaining_.out > beast::zero); - - assert(m_rate_in.value != 0); - assert(m_rate_out.value != 0); + XRPL_ASSERT( + remaining_.in > beast::zero, + "ripple::BasicTaker::BasicTaker : positive remaining in"); + XRPL_ASSERT( + remaining_.out > beast::zero, + "ripple::BasicTaker::BasicTaker : positive remaining out"); + + XRPL_ASSERT( + m_rate_in.value, "ripple::BasicTaker::BasicTaker : nonzero rate in"); + XRPL_ASSERT( + m_rate_out.value, "ripple::BasicTaker::BasicTaker : nonzero rate out"); // If we are dealing with a particular flavor, make sure that it's the // flavor we expect: - assert( + XRPL_ASSERT( cross_type != CrossType::XrpToIou || - (isXRP(issue_in()) && !isXRP(issue_out()))); + (isXRP(issue_in()) && !isXRP(issue_out())), + "ripple::BasicTaker::BasicTaker : valid cross to IOU"); - assert( + XRPL_ASSERT( cross_type != CrossType::IouToXrp || - (!isXRP(issue_in()) && isXRP(issue_out()))); + (!isXRP(issue_in()) && isXRP(issue_out())), + "ripple::BasicTaker::BasicTaker : valid cross to XRP"); // And make sure we're not crossing XRP for XRP - assert(!isXRP(issue_in()) || !isXRP(issue_out())); + XRPL_ASSERT( + !isXRP(issue_in()) || !isXRP(issue_out()), + "ripple::BasicTaker::BasicTaker : not crossing XRP for XRP"); // If this is a passive order, we adjust the quality so as to prevent offers // at the same quality level from being consumed. @@ -150,7 +160,9 @@ BasicTaker::remaining_offer() const if (sell_) { - assert(remaining_.in > beast::zero); + XRPL_ASSERT( + remaining_.in > beast::zero, + "ripple::BasicTaker::remaining_offer : positive remaining in"); // We scale the output based on the remaining input: return Amounts( @@ -158,7 +170,9 @@ BasicTaker::remaining_offer() const divRound(remaining_.in, quality_.rate(), issue_out_, true)); } - assert(remaining_.out > beast::zero); + XRPL_ASSERT( + remaining_.out > beast::zero, + "ripple::BasicTaker::remaining_offer : positive remaining out"); // We scale the input based on the remaining output: return Amounts( @@ -424,7 +438,9 @@ BasicTaker::do_cross(Amounts offer, Quality quality, AccountID const& owner) remaining_.out -= result.order.out; remaining_.in -= result.order.in; - assert(remaining_.in >= beast::zero); + XRPL_ASSERT( + remaining_.in >= beast::zero, + "ripple::BasicTaker::do_cross : minimum remaining in"); return result; } @@ -439,10 +455,17 @@ BasicTaker::do_cross( Quality quality2, AccountID const& owner2) { - assert(!offer1.in.native()); - assert(offer1.out.native()); - assert(offer2.in.native()); - assert(!offer2.out.native()); + XRPL_ASSERT( + !offer1.in.native(), + "ripple::BasicTaker::do_cross : offer1 in is not XRP"); + XRPL_ASSERT( + offer1.out.native(), + "ripple::BasicTaker::do_cross : offer1 out is XRP"); + XRPL_ASSERT( + offer2.in.native(), "ripple::BasicTaker::do_cross : offer2 in is XRP"); + XRPL_ASSERT( + !offer2.out.native(), + "ripple::BasicTaker::do_cross : offer2 out is not XRP"); // If the taker owns the first leg of the offer, then the taker's available // funds aren't the limiting factor for the input - the offer itself is. @@ -559,8 +582,12 @@ Taker::Taker( , direct_crossings_(0) , bridge_crossings_(0) { - assert(issue_in() == offer.in.issue()); - assert(issue_out() == offer.out.issue()); + XRPL_ASSERT( + issue_in() == offer.in.issue(), + "ripple::Taker::Taker : issue in is a match"); + XRPL_ASSERT( + issue_out() == offer.out.issue(), + "ripple::Taker::Taker : issue out is a match"); if (auto stream = journal_.debug()) { @@ -689,7 +716,8 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer) if (cross_type() != CrossType::XrpToIou) { - assert(!isXRP(flow.order.in)); + XRPL_ASSERT( + !isXRP(flow.order.in), "ripple::Taker::fill : order in is not XRP"); if (result == tesSUCCESS) result = @@ -701,7 +729,8 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer) } else { - assert(isXRP(flow.order.in)); + XRPL_ASSERT( + isXRP(flow.order.in), "ripple::Taker::fill : order in is XRP"); if (result == tesSUCCESS) result = transferXRP(account(), offer.owner(), flow.order.in); @@ -710,7 +739,9 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer) // Now send funds from the account whose offer we're taking if (cross_type() != CrossType::IouToXrp) { - assert(!isXRP(flow.order.out)); + XRPL_ASSERT( + !isXRP(flow.order.out), + "ripple::Taker::fill : order out is not XRP"); if (result == tesSUCCESS) result = redeemIOU( @@ -722,7 +753,8 @@ Taker::fill(BasicTaker::Flow const& flow, Offer& offer) } else { - assert(isXRP(flow.order.out)); + XRPL_ASSERT( + isXRP(flow.order.out), "ripple::Taker::fill : order out is XRP"); if (result == tesSUCCESS) result = transferXRP(offer.owner(), account(), flow.order.out); diff --git a/src/xrpld/app/tx/detail/Transactor.cpp b/src/xrpld/app/tx/detail/Transactor.cpp index 052a735a2fd..df3d32f8a58 100644 --- a/src/xrpld/app/tx/detail/Transactor.cpp +++ b/src/xrpld/app/tx/detail/Transactor.cpp @@ -227,9 +227,9 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee) if (balance < feePaid) { - JLOG(ctx.j.trace()) << "Insufficient balance:" - << " balance=" << to_string(balance) - << " paid=" << to_string(feePaid); + JLOG(ctx.j.trace()) + << "Insufficient balance:" << " balance=" << to_string(balance) + << " paid=" << to_string(feePaid); if ((balance > beast::zero) && !ctx.view.open()) { @@ -368,7 +368,8 @@ Transactor::checkPriorTxAndLastLedger(PreclaimContext const& ctx) TER Transactor::consumeSeqProxy(SLE::pointer const& sleAccount) { - assert(sleAccount); + XRPL_ASSERT( + sleAccount, "ripple::Transactor::consumeSeqProxy : non-null account"); SeqProxy const seqProx = ctx_.tx.getSeqProxy(); if (seqProx.isSeq()) { @@ -440,7 +441,9 @@ Transactor::ticketDelete( void Transactor::preCompute() { - assert(account_ != beast::zero); + XRPL_ASSERT( + account_ != beast::zero, + "ripple::Transactor::preCompute : nonzero account"); } TER @@ -454,7 +457,9 @@ Transactor::apply() // sle must exist except for transactions // that allow zero account. - assert(sle != nullptr || account_ == beast::zero); + XRPL_ASSERT( + sle != nullptr || account_ == beast::zero, + "ripple::Transactor::apply : non-null SLE or zero account"); if (sle) { @@ -579,8 +584,12 @@ Transactor::checkMultiSign(PreclaimContext const& ctx) // We have plans to support multiple SignerLists in the future. The // presence and defaulted value of the SignerListID field will enable that. - assert(sleAccountSigners->isFieldPresent(sfSignerListID)); - assert(sleAccountSigners->getFieldU32(sfSignerListID) == 0); + XRPL_ASSERT( + sleAccountSigners->isFieldPresent(sfSignerListID), + "ripple::Transactor::checkMultiSign : has signer list ID"); + XRPL_ASSERT( + sleAccountSigners->getFieldU32(sfSignerListID) == 0, + "ripple::Transactor::checkMultiSign : signer list ID is 0"); auto accountSigners = SignerEntries::deserialize(*sleAccountSigners, ctx.j, "ledger"); @@ -816,7 +825,9 @@ Transactor::reset(XRPAmount fee) auto const balance = txnAcct->getFieldAmount(sfBalance).xrp(); // balance should have already been checked in checkFee / preFlight. - assert(balance != beast::zero && (!view().open() || balance >= fee)); + XRPL_ASSERT( + balance != beast::zero && (!view().open() || balance >= fee), + "ripple::Transactor::reset : valid balance"); // We retry/reject the transaction if the account balance is zero or we're // applying against an open ledger and the balance is less than the fee @@ -831,7 +842,8 @@ Transactor::reset(XRPAmount fee) // reject the transaction. txnAcct->setFieldAmount(sfBalance, balance - fee); TER const ter{consumeSeqProxy(txnAcct)}; - assert(isTesSuccess(ter)); + XRPL_ASSERT( + isTesSuccess(ter), "ripple::Transactor::reset : result is tesSUCCESS"); if (isTesSuccess(ter)) view().update(txnAcct); @@ -871,7 +883,8 @@ Transactor::operator()() JLOG(j_.fatal()) << "Transaction serdes mismatch"; JLOG(j_.info()) << to_string(ctx_.tx.getJson(JsonOptions::none)); JLOG(j_.fatal()) << s2.getJson(JsonOptions::none); - assert(false); + UNREACHABLE( + "ripple::Transactor::operator() : transaction serdes mismatch"); } } #endif @@ -888,7 +901,9 @@ Transactor::operator()() // No transaction can return temUNKNOWN from apply, // and it can't be passed in from a preclaim. - assert(result != temUNKNOWN); + XRPL_ASSERT( + result != temUNKNOWN, + "ripple::Transactor::operator() : result is not temUNKNOWN"); if (auto stream = j_.trace()) stream << "preclaim result: " << transToken(result); @@ -944,7 +959,10 @@ Transactor::operator()() std::shared_ptr const& after) { if (isDelete) { - assert(before && after); + XRPL_ASSERT( + before && after, + "ripple::Transactor::operator()::visit : non-null SLE " + "inputs"); if (doOffers && before && after && (before->getType() == ltOFFER) && (before->getFieldAmount(sfTakerPays) == diff --git a/src/xrpld/app/tx/detail/Transactor.h b/src/xrpld/app/tx/detail/Transactor.h index c587e5e1994..d7908749efd 100644 --- a/src/xrpld/app/tx/detail/Transactor.h +++ b/src/xrpld/app/tx/detail/Transactor.h @@ -22,8 +22,8 @@ #include #include -#include #include +#include namespace ripple { diff --git a/src/xrpld/app/tx/detail/XChainBridge.cpp b/src/xrpld/app/tx/detail/XChainBridge.cpp index f5633903567..0c6be61040c 100644 --- a/src/xrpld/app/tx/detail/XChainBridge.cpp +++ b/src/xrpld/app/tx/detail/XChainBridge.cpp @@ -26,9 +26,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -222,7 +223,9 @@ claimHelper( auto i = signersList.find(a.keyAccount); if (i == signersList.end()) { - assert(0); // should have already been checked + UNREACHABLE( + "ripple::claimHelper : invalid inputs"); // should have already + // been checked continue; } weight += i->second; @@ -437,7 +440,7 @@ transferHelper( if (amt.native()) { auto const sleSrc = psb.peek(keylet::account(src)); - assert(sleSrc); + XRPL_ASSERT(sleSrc, "ripple::transferHelper : non-null source account"); if (!sleSrc) return tecINTERNAL; diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index b3c711084dc..bf492f540ba 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -157,7 +157,7 @@ invoke_preflight(PreflightContext const& ctx) // Should never happen JLOG(ctx.j.fatal()) << "Unknown transaction type in preflight: " << e.txnType; - assert(false); + UNREACHABLE("ripple::invoke_preflight : unknown transaction type"); return {temUNKNOWN, TxConsequences{temUNKNOWN}}; } } @@ -206,7 +206,7 @@ invoke_preclaim(PreclaimContext const& ctx) // Should never happen JLOG(ctx.j.fatal()) << "Unknown transaction type in preclaim: " << e.txnType; - assert(false); + UNREACHABLE("ripple::invoke_preclaim : unknown transaction type"); return temUNKNOWN; } } @@ -222,7 +222,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx) } catch (UnknownTxnType const& e) { - assert(false); + UNREACHABLE( + "ripple::invoke_calculateBaseFee : unknown transaction type"); return XRPAmount{0}; } } @@ -234,7 +235,9 @@ TxConsequences::TxConsequences(NotTEC pfresult) , seqProx_(SeqProxy::sequence(0)) , sequencesConsumed_(0) { - assert(!isTesSuccess(pfresult)); + XRPL_ASSERT( + !isTesSuccess(pfresult), + "ripple::TxConsequences::TxConsequences : is not tesSUCCESS"); } TxConsequences::TxConsequences(STTx const& tx) @@ -281,7 +284,7 @@ invoke_apply(ApplyContext& ctx) // Should never happen JLOG(ctx.journal.fatal()) << "Unknown transaction type in apply: " << e.txnType; - assert(false); + UNREACHABLE("ripple::invoke_apply : unknown transaction type"); return {temUNKNOWN, false}; } } diff --git a/src/xrpld/consensus/Consensus.h b/src/xrpld/consensus/Consensus.h index 06c12b4f150..daad520c77f 100644 --- a/src/xrpld/consensus/Consensus.h +++ b/src/xrpld/consensus/Consensus.h @@ -863,7 +863,9 @@ Consensus::gotTxSet( { // Our position is added to acquired_ as soon as we create it, // so this txSet must differ - assert(id != result_->position.position()); + XRPL_ASSERT( + id != result_->position.position(), + "ripple::Consensus::gotTxSet : updated transaction set"); bool any = false; for (auto const& [nodeId, peerPos] : currPeerPositions_) { @@ -1008,7 +1010,9 @@ template void Consensus::handleWrongLedger(typename Ledger_t::ID const& lgrId) { - assert(lgrId != prevLedgerID_ || previousLedger_.id() != lgrId); + XRPL_ASSERT( + lgrId != prevLedgerID_ || previousLedger_.id() != lgrId, + "ripple::Consensus::handleWrongLedger : have wrong ledger"); // Stop proposing because we are out of sync leaveConsensus(); @@ -1259,7 +1263,7 @@ void Consensus::phaseEstablish() { // can only establish consensus if we already took a stance - assert(result_); + XRPL_ASSERT(result_, "ripple::Consensus::phaseEstablish : result is set"); using namespace std::chrono; ConsensusParms const& parms = adaptor_.parms(); @@ -1307,7 +1311,7 @@ void Consensus::closeLedger() { // We should not be closing if we already have a position - assert(!result_); + XRPL_ASSERT(!result_, "ripple::Consensus::closeLedger : result is not set"); phase_ = ConsensusPhase::establish; JLOG(j_.debug()) << "transitioned to ConsensusPhase::establish"; @@ -1360,7 +1364,8 @@ void Consensus::updateOurPositions() { // We must have a position if we are updating it - assert(result_); + XRPL_ASSERT( + result_, "ripple::Consensus::updateOurPositions : result is set"); ConsensusParms const& parms = adaptor_.parms(); // Compute a cutoff time @@ -1544,7 +1549,7 @@ bool Consensus::haveConsensus() { // Must have a stance if we are checking for consensus - assert(result_); + XRPL_ASSERT(result_, "ripple::Consensus::haveConsensus : has result"); // CHECKME: should possibly count unacquired TX sets as disagreeing int agree = 0, disagree = 0; @@ -1619,7 +1624,7 @@ void Consensus::createDisputes(TxSet_t const& o) { // Cannot create disputes without our stance - assert(result_); + XRPL_ASSERT(result_, "ripple::Consensus::createDisputes : result is set"); // Only create disputes if this is a new set if (!result_->compares.emplace(o.id()).second) @@ -1640,9 +1645,10 @@ Consensus::createDisputes(TxSet_t const& o) { ++dc; // create disputed transactions (from the ledger that has them) - assert( + XRPL_ASSERT( (inThisSet && result_->txns.find(txId) && !o.find(txId)) || - (!inThisSet && !result_->txns.find(txId) && o.find(txId))); + (!inThisSet && !result_->txns.find(txId) && o.find(txId)), + "ripple::Consensus::createDisputes : has disputed transactions"); Tx_t tx = inThisSet ? result_->txns.find(txId) : o.find(txId); auto txID = tx.id(); @@ -1678,7 +1684,7 @@ void Consensus::updateDisputes(NodeID_t const& node, TxSet_t const& other) { // Cannot updateDisputes without our stance - assert(result_); + XRPL_ASSERT(result_, "ripple::Consensus::updateDisputes : result is set"); // Ensure we have created disputes against this set if we haven't seen // it before diff --git a/src/xrpld/consensus/ConsensusTypes.h b/src/xrpld/consensus/ConsensusTypes.h index da03fc4875a..ba8e0a8b1ac 100644 --- a/src/xrpld/consensus/ConsensusTypes.h +++ b/src/xrpld/consensus/ConsensusTypes.h @@ -214,7 +214,9 @@ struct ConsensusResult ConsensusResult(TxSet_t&& s, Proposal_t&& p) : txns{std::move(s)}, position{std::move(p)} { - assert(txns.id() == position.position()); + XRPL_ASSERT( + txns.id() == position.position(), + "ripple::ConsensusResult : valid inputs"); } //! The set of transactions consensus agrees go in the ledger diff --git a/src/xrpld/consensus/LedgerTiming.h b/src/xrpld/consensus/LedgerTiming.h index 1bb5bfd730f..b3ef5ee59c2 100644 --- a/src/xrpld/consensus/LedgerTiming.h +++ b/src/xrpld/consensus/LedgerTiming.h @@ -82,7 +82,9 @@ getNextLedgerTimeResolution( bool previousAgree, Seq ledgerSeq) { - assert(ledgerSeq != Seq{0}); + XRPL_ASSERT( + ledgerSeq != Seq{0}, + "ripple:getNextLedgerTimeResolution : valid ledger sequence"); using namespace std::chrono; // Find the current resolution: @@ -90,7 +92,9 @@ getNextLedgerTimeResolution( std::begin(ledgerPossibleTimeResolutions), std::end(ledgerPossibleTimeResolutions), previousResolution); - assert(iter != std::end(ledgerPossibleTimeResolutions)); + XRPL_ASSERT( + iter != std::end(ledgerPossibleTimeResolutions), + "ripple:getNextLedgerTimeResolution : found time resolution"); // This should never happen, but just as a precaution if (iter == std::end(ledgerPossibleTimeResolutions)) diff --git a/src/xrpld/consensus/LedgerTrie.h b/src/xrpld/consensus/LedgerTrie.h index 32bae28cc07..17f9e570b0e 100644 --- a/src/xrpld/consensus/LedgerTrie.h +++ b/src/xrpld/consensus/LedgerTrie.h @@ -21,7 +21,9 @@ #define RIPPLE_APP_CONSENSUS_LEDGERS_TRIE_H_INCLUDED #include +#include #include + #include #include #include @@ -62,7 +64,7 @@ class SpanTip ID ancestor(Seq const& s) const { - assert(s <= seq); + XRPL_ASSERT(s <= seq, "ripple::SpanTip::ancestor : valid input"); return ledger[s]; } @@ -88,7 +90,8 @@ class Span Span() : ledger_{typename Ledger::MakeGenesis{}} { // Require default ledger to be genesis seq - assert(ledger_.seq() == start_); + XRPL_ASSERT( + ledger_.seq() == start_, "ripple::Span::Span : ledger is genesis"); } Span(Ledger ledger) @@ -157,7 +160,7 @@ class Span : start_{start}, end_{end}, ledger_{l} { // Spans cannot be empty - assert(start < end); + XRPL_ASSERT(start < end, "ripple::Span::Span : non-empty span input"); } Seq @@ -230,7 +233,7 @@ struct Node [child](std::unique_ptr const& curr) { return curr.get() == child; }); - assert(it != children.end()); + XRPL_ASSERT(it != children.end(), "ripple::Node::erase : valid input"); std::swap(*it, children.back()); children.pop_back(); } @@ -371,7 +374,7 @@ class LedgerTrie Node* curr = root.get(); // Root is always defined and is in common with all ledgers - assert(curr); + XRPL_ASSERT(curr, "ripple::LedgerTrie::find : non-null root"); Seq pos = curr->span.diff(ledger); bool done = false; @@ -452,7 +455,7 @@ class LedgerTrie auto const [loc, diffSeq] = find(ledger); // There is always a place to insert - assert(loc); + XRPL_ASSERT(loc, "ripple::LedgerTrie::insert : valid input ledger"); // Node from which to start incrementing branchSupport Node* incNode = loc; @@ -487,12 +490,14 @@ class LedgerTrie newNode->tipSupport = loc->tipSupport; newNode->branchSupport = loc->branchSupport; newNode->children = std::move(loc->children); - assert(loc->children.empty()); + XRPL_ASSERT( + loc->children.empty(), + "ripple::LedgerTrie::insert : moved-from children"); for (std::unique_ptr& child : newNode->children) child->parent = newNode.get(); // Loc truncates to prefix and newNode is its child - assert(prefix); + XRPL_ASSERT(prefix, "ripple::LedgerTrie::insert : prefix is set"); loc->span = *prefix; newNode->parent = loc; loc->children.emplace_back(std::move(newNode)); @@ -545,7 +550,9 @@ class LedgerTrie loc->tipSupport -= count; auto const it = seqSupport.find(ledger.seq()); - assert(it != seqSupport.end() && it->second >= count); + XRPL_ASSERT( + it != seqSupport.end() && it->second >= count, + "ripple::LedgerTrie::remove : valid input ledger"); it->second -= count; if (it->second == 0) seqSupport.erase(it->first); diff --git a/src/xrpld/consensus/Validations.h b/src/xrpld/consensus/Validations.h index a1171effb56..582d36cbcd9 100644 --- a/src/xrpld/consensus/Validations.h +++ b/src/xrpld/consensus/Validations.h @@ -434,7 +434,9 @@ class Validations Validation const& val, std::optional> prior) { - assert(val.trusted()); + XRPL_ASSERT( + val.trusted(), + "ripple::Validations::updateTrie : trusted input validation"); // Clear any prior acquiring ledger for this node if (prior) @@ -713,7 +715,8 @@ class Validations setSeqToKeep(Seq const& low, Seq const& high) { std::lock_guard lock{mutex_}; - assert(low < high); + XRPL_ASSERT( + low < high, "ripple::Validations::setSeqToKeep : valid inputs"); toKeep_ = {low, high}; } diff --git a/src/xrpld/core/Config.h b/src/xrpld/core/Config.h index 16950901f0f..37a853483d2 100644 --- a/src/xrpld/core/Config.h +++ b/src/xrpld/core/Config.h @@ -21,10 +21,10 @@ #define RIPPLE_CORE_CONFIG_H_INCLUDED #include -#include #include #include #include +#include #include // VFALCO Breaks levelization #include diff --git a/src/xrpld/core/Coro.ipp b/src/xrpld/core/Coro.ipp index a936dd896ae..5901e07c684 100644 --- a/src/xrpld/core/Coro.ipp +++ b/src/xrpld/core/Coro.ipp @@ -53,7 +53,7 @@ JobQueue::Coro::Coro( inline JobQueue::Coro::~Coro() { #ifndef NDEBUG - assert(finished_); + XRPL_ASSERT(finished_, "ripple::JobQueue::Coro::~Coro : is finished"); #endif } @@ -103,7 +103,9 @@ JobQueue::Coro::resume() auto saved = detail::getLocalValues().release(); detail::getLocalValues().reset(&lvs_); std::lock_guard lock(mutex_); - assert(coro_); + XRPL_ASSERT( + static_cast(coro_), + "ripple::JobQueue::Coro::resume : is runnable"); coro_(); detail::getLocalValues().release(); detail::getLocalValues().reset(saved); diff --git a/src/xrpld/core/DatabaseCon.h b/src/xrpld/core/DatabaseCon.h index c8c40dec662..8c6ba730320 100644 --- a/src/xrpld/core/DatabaseCon.h +++ b/src/xrpld/core/DatabaseCon.h @@ -97,7 +97,10 @@ class DatabaseCon std::vector const* commonPragma() const { - assert(!useGlobalPragma || globalPragma); + XRPL_ASSERT( + !useGlobalPragma || globalPragma, + "ripple::DatabaseCon::Setup::commonPragma : consistent global " + "pragma"); return useGlobalPragma && globalPragma ? globalPragma.get() : nullptr; } diff --git a/src/xrpld/core/JobTypes.h b/src/xrpld/core/JobTypes.h index 3b41ce7ff47..29b096b7a3b 100644 --- a/src/xrpld/core/JobTypes.h +++ b/src/xrpld/core/JobTypes.h @@ -53,17 +53,22 @@ class JobTypes int limit, std::chrono::milliseconds avgLatency, std::chrono::milliseconds peakLatency) { - assert(m_map.find(jt) == m_map.end()); - - auto const [_, inserted] = m_map.emplace( - std::piecewise_construct, - std::forward_as_tuple(jt), - std::forward_as_tuple( - jt, name, limit, avgLatency, peakLatency)); - - assert(inserted == true); - (void)_; - (void)inserted; + XRPL_ASSERT( + m_map.find(jt) == m_map.end(), + "ripple::JobTypes::JobTypes::add : unique job type input"); + + [[maybe_unused]] auto const inserted = + m_map + .emplace( + std::piecewise_construct, + std::forward_as_tuple(jt), + std::forward_as_tuple( + jt, name, limit, avgLatency, peakLatency)) + .second; + + XRPL_ASSERT( + inserted == true, + "ripple::JobTypes::JobTypes::add : input is inserted"); }; // clang-format off @@ -137,7 +142,7 @@ class JobTypes get(JobType jt) const { Map::const_iterator const iter(m_map.find(jt)); - assert(iter != m_map.end()); + XRPL_ASSERT(iter != m_map.end(), "ripple::JobTypes::get : valid input"); if (iter != m_map.end()) return iter->second; diff --git a/src/xrpld/core/detail/Config.cpp b/src/xrpld/core/detail/Config.cpp index 885951111c0..957ccc767f8 100644 --- a/src/xrpld/core/detail/Config.cpp +++ b/src/xrpld/core/detail/Config.cpp @@ -266,7 +266,8 @@ Config::Config() void Config::setupControl(bool bQuiet, bool bSilent, bool bStandalone) { - assert(NODE_SIZE == 0); + XRPL_ASSERT( + NODE_SIZE == 0, "ripple::Config::setupControl : node size not set"); QUIET = bQuiet || bSilent; SILENT = bSilent; @@ -287,7 +288,9 @@ Config::setupControl(bool bQuiet, bool bSilent, bool bStandalone) return (limit == 0) || (ramSize_ < limit); }); - assert(ns != threshold.second.end()); + XRPL_ASSERT( + ns != threshold.second.end(), + "ripple::Config::setupControl : valid node size"); if (ns != threshold.second.end()) NODE_SIZE = std::distance(threshold.second.begin(), ns); @@ -298,7 +301,8 @@ Config::setupControl(bool bQuiet, bool bSilent, bool bStandalone) NODE_SIZE = std::min(hc / 2, NODE_SIZE); } - assert(NODE_SIZE <= 4); + XRPL_ASSERT( + NODE_SIZE <= 4, "ripple::Config::setupControl : node size is set"); } void @@ -1004,8 +1008,12 @@ int Config::getValueFor(SizedItem item, std::optional node) const { auto const index = static_cast>(item); - assert(index < sizedItems.size()); - assert(!node || *node <= 4); + XRPL_ASSERT( + index < sizedItems.size(), + "ripple::Config::getValueFor : valid index input"); + XRPL_ASSERT( + !node || *node <= 4, + "ripple::Config::getValueFor : unset or valid node"); return sizedItems.at(index).second.at(node.value_or(NODE_SIZE)); } diff --git a/src/xrpld/core/detail/DatabaseCon.cpp b/src/xrpld/core/detail/DatabaseCon.cpp index 7000899b1f6..6d49c647a6f 100644 --- a/src/xrpld/core/detail/DatabaseCon.cpp +++ b/src/xrpld/core/detail/DatabaseCon.cpp @@ -231,7 +231,9 @@ setup_DatabaseCon(Config const& c, std::optional j) "nodes storing large amounts of history, because of the " "difficulty inherent in rebuilding corrupted data."; } - assert(result->size() == 3); + XRPL_ASSERT( + result->size() == 3, + "ripple::setup_DatabaseCon::globalPragma : result size is 3"); return result; }(); } diff --git a/src/xrpld/core/detail/Job.cpp b/src/xrpld/core/detail/Job.cpp index 0782fd05a66..17f600a4f41 100644 --- a/src/xrpld/core/detail/Job.cpp +++ b/src/xrpld/core/detail/Job.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include namespace ripple { diff --git a/src/xrpld/core/detail/JobQueue.cpp b/src/xrpld/core/detail/JobQueue.cpp index 1c859d724f4..5eb1f24d43a 100644 --- a/src/xrpld/core/detail/JobQueue.cpp +++ b/src/xrpld/core/detail/JobQueue.cpp @@ -55,7 +55,9 @@ JobQueue::JobQueue( std::piecewise_construct, std::forward_as_tuple(jt.type()), std::forward_as_tuple(jt, m_collector, logs))); - assert(result.second == true); + XRPL_ASSERT( + result.second == true, + "ripple::JobQueue::JobQueue : jobs added"); (void)result.second; } } @@ -80,10 +82,14 @@ JobQueue::addRefCountedJob( std::string const& name, JobFunction const& func) { - assert(type != jtINVALID); + XRPL_ASSERT( + type != jtINVALID, + "ripple::JobQueue::addRefCountedJob : valid input job type"); auto iter(m_jobData.find(type)); - assert(iter != m_jobData.end()); + XRPL_ASSERT( + iter != m_jobData.end(), + "ripple::JobQueue::addRefCountedJob : job type found in jobs"); if (iter == m_jobData.end()) return false; @@ -93,9 +99,11 @@ JobQueue::addRefCountedJob( // FIXME: Workaround incorrect client shutdown ordering // do not add jobs to a queue with no threads - assert( + XRPL_ASSERT( (type >= jtCLIENT && type <= jtCLIENT_WEBSOCKET) || - m_workers.getNumberOfThreads() > 0); + m_workers.getNumberOfThreads() > 0, + "ripple::JobQueue::addRefCountedJob : threads available or job " + "requires no threads"); { std::lock_guard lock(m_mutex); @@ -104,8 +112,12 @@ JobQueue::addRefCountedJob( auto const& job = *result.first; JobType const type(job.getType()); - assert(type != jtINVALID); - assert(m_jobSet.find(job) != m_jobSet.end()); + XRPL_ASSERT( + type != jtINVALID, + "ripple::JobQueue::addRefCountedJob : has valid job type"); + XRPL_ASSERT( + m_jobSet.find(job) != m_jobSet.end(), + "ripple::JobQueue::addRefCountedJob : job found"); perfLog_.jobQueue(type); JobTypeData& data(getJobTypeData(type)); @@ -165,7 +177,9 @@ std::unique_ptr JobQueue::makeLoadEvent(JobType t, std::string const& name) { JobDataMap::iterator iter(m_jobData.find(t)); - assert(iter != m_jobData.end()); + XRPL_ASSERT( + iter != m_jobData.end(), + "ripple::JobQueue::makeLoadEvent : valid job type input"); if (iter == m_jobData.end()) return {}; @@ -180,7 +194,9 @@ JobQueue::addLoadEvents(JobType t, int count, std::chrono::milliseconds elapsed) LogicError("JobQueue::addLoadEvents() called after JobQueue stopped"); JobDataMap::iterator iter(m_jobData.find(t)); - assert(iter != m_jobData.end()); + XRPL_ASSERT( + iter != m_jobData.end(), + "ripple::JobQueue::addLoadEvents : valid job type input"); iter->second.load().addSamples(count, elapsed); } @@ -206,7 +222,8 @@ JobQueue::getJson(int c) for (auto& x : m_jobData) { - assert(x.first != jtINVALID); + XRPL_ASSERT( + x.first != jtINVALID, "ripple::JobQueue::getJson : valid job type"); if (x.first == jtGENERIC) continue; @@ -261,7 +278,9 @@ JobTypeData& JobQueue::getJobTypeData(JobType type) { JobDataMap::iterator c(m_jobData.find(type)); - assert(c != m_jobData.end()); + XRPL_ASSERT( + c != m_jobData.end(), + "ripple::JobQueue::getJobTypeData : valid job type input"); // NIKB: This is ugly and I hate it. We must remove jtINVALID completely // and use something sane. @@ -286,9 +305,13 @@ JobQueue::stop() std::unique_lock lock(m_mutex); cv_.wait( lock, [this] { return m_processCount == 0 && m_jobSet.empty(); }); - assert(m_processCount == 0); - assert(m_jobSet.empty()); - assert(nSuspend_ == 0); + XRPL_ASSERT( + m_processCount == 0, + "ripple::JobQueue::stop : all processes completed"); + XRPL_ASSERT( + m_jobSet.empty(), "ripple::JobQueue::stop : all jobs completed"); + XRPL_ASSERT( + nSuspend_ == 0, "ripple::JobQueue::stop : no coros suspended"); stopped_ = true; } } @@ -302,28 +325,36 @@ JobQueue::isStopped() const void JobQueue::getNextJob(Job& job) { - assert(!m_jobSet.empty()); + XRPL_ASSERT( + !m_jobSet.empty(), "ripple::JobQueue::getNextJob : non-empty jobs"); std::set::const_iterator iter; for (iter = m_jobSet.begin(); iter != m_jobSet.end(); ++iter) { JobType const type = iter->getType(); - assert(type != jtINVALID); + XRPL_ASSERT( + type != jtINVALID, "ripple::JobQueue::getNextJob : valid job type"); JobTypeData& data(getJobTypeData(type)); - assert(data.running <= getJobLimit(type)); + XRPL_ASSERT( + data.running <= getJobLimit(type), + "ripple::JobQueue::getNextJob : maximum jobs running"); // Run this job if we're running below the limit. if (data.running < getJobLimit(data.type())) { - assert(data.waiting > 0); + XRPL_ASSERT( + data.waiting > 0, + "ripple::JobQueue::getNextJob : positive data waiting"); --data.waiting; ++data.running; break; } } - assert(iter != m_jobSet.end()); + XRPL_ASSERT( + iter != m_jobSet.end(), + "ripple::JobQueue::getNextJob : found next job"); job = *iter; m_jobSet.erase(iter); } @@ -331,14 +362,18 @@ JobQueue::getNextJob(Job& job) void JobQueue::finishJob(JobType type) { - assert(type != jtINVALID); + XRPL_ASSERT( + type != jtINVALID, + "ripple::JobQueue::finishJob : valid input job type"); JobTypeData& data = getJobTypeData(type); // Queue a deferred task if possible if (data.deferred > 0) { - assert(data.running + data.waiting >= getJobLimit(type)); + XRPL_ASSERT( + data.running + data.waiting >= getJobLimit(type), + "ripple::JobQueue::finishJob : job limit"); --data.deferred; m_workers.addTask(); @@ -404,7 +439,9 @@ int JobQueue::getJobLimit(JobType type) { JobTypeInfo const& j(JobTypes::instance().get(type)); - assert(j.type() != jtINVALID); + XRPL_ASSERT( + j.type() != jtINVALID, + "ripple::JobQueue::getJobLimit : valid job type"); return j.limit(); } diff --git a/src/xrpld/core/detail/LoadEvent.cpp b/src/xrpld/core/detail/LoadEvent.cpp index ca78fdb19cc..2602c0691fc 100644 --- a/src/xrpld/core/detail/LoadEvent.cpp +++ b/src/xrpld/core/detail/LoadEvent.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include namespace ripple { @@ -83,7 +83,7 @@ LoadEvent::start() void LoadEvent::stop() { - assert(running_); + XRPL_ASSERT(running_, "ripple::LoadEvent::stop : is running"); auto const now = std::chrono::steady_clock::now(); diff --git a/src/xrpld/core/detail/Workers.cpp b/src/xrpld/core/detail/Workers.cpp index ff861010d95..7286f378e85 100644 --- a/src/xrpld/core/detail/Workers.cpp +++ b/src/xrpld/core/detail/Workers.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include namespace ripple { @@ -119,7 +119,9 @@ Workers::stop() m_cv.wait(lk, [this] { return m_allPaused; }); lk.unlock(); - assert(numberOfCurrentlyRunningTasks() == 0); + XRPL_ASSERT( + numberOfCurrentlyRunningTasks() == 0, + "ripple::Workers::stop : zero running tasks"); } void diff --git a/src/xrpld/ledger/ApplyView.h b/src/xrpld/ledger/ApplyView.h index f0166cd0b38..12626824308 100644 --- a/src/xrpld/ledger/ApplyView.h +++ b/src/xrpld/ledger/ApplyView.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace ripple { @@ -276,8 +277,11 @@ class ApplyView : public ReadView { if (key.type != ltOFFER) { - assert(!"Only Offers are appended to book directories. " - "Call dirInsert() instead."); + UNREACHABLE( + "ripple::ApplyView::dirAppend : only Offers are appended to " + "book directories"); + // Only Offers are appended to book directories. Call dirInsert() + // instead return std::nullopt; } return dirAdd(true, directory, key.key, describe); diff --git a/src/xrpld/ledger/OpenView.h b/src/xrpld/ledger/OpenView.h index bd8627a18b2..c8e1911bf96 100644 --- a/src/xrpld/ledger/OpenView.h +++ b/src/xrpld/ledger/OpenView.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/xrpld/ledger/ReadView.h b/src/xrpld/ledger/ReadView.h index 50f1a7d98c1..fb695b9a360 100644 --- a/src/xrpld/ledger/ReadView.h +++ b/src/xrpld/ledger/ReadView.h @@ -21,13 +21,13 @@ #define RIPPLE_LEDGER_READVIEW_H_INCLUDED #include -#include -#include -#include #include #include #include +#include +#include #include +#include #include #include #include @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/xrpld/ledger/detail/ApplyStateTable.cpp b/src/xrpld/ledger/detail/ApplyStateTable.cpp index b849365c83f..25ac5d00560 100644 --- a/src/xrpld/ledger/detail/ApplyStateTable.cpp +++ b/src/xrpld/ledger/detail/ApplyStateTable.cpp @@ -19,10 +19,10 @@ #include #include +#include #include #include #include -#include namespace ripple { namespace detail { @@ -155,7 +155,10 @@ ApplyStateTable::apply( meta.setAffectedNode(item.first, *type, nodeType); if (type == &sfDeletedNode) { - assert(origNode && curNode); + XRPL_ASSERT( + origNode && curNode, + "ripple::detail::ApplyStateTable::apply : valid nodes for " + "deletion"); threadOwners(to, meta, origNode, newMod, j); STObject prevs(sfPreviousFields); @@ -187,7 +190,10 @@ ApplyStateTable::apply( } else if (type == &sfModifiedNode) { - assert(curNode && origNode); + XRPL_ASSERT( + curNode && origNode, + "ripple::detail::ApplyStateTable::apply : valid nodes for " + "modification"); if (curNode->isThreadedType( to.rules())) // thread transaction to node @@ -222,7 +228,10 @@ ApplyStateTable::apply( } else if (type == &sfCreatedNode) // if created, thread to owner(s) { - assert(curNode && !origNode); + XRPL_ASSERT( + curNode && !origNode, + "ripple::detail::ApplyStateTable::apply : valid nodes for " + "creation"); threadOwners(to, meta, curNode, newMod, j); if (curNode->isThreadedType( @@ -245,7 +254,9 @@ ApplyStateTable::apply( } else { - assert(false); + UNREACHABLE( + "ripple::detail::ApplyStateTable::apply : unsupported " + "operation type"); } } @@ -536,13 +547,21 @@ ApplyStateTable::threadItem(TxMeta& meta, std::shared_ptr const& sle) if (node.getFieldIndex(sfPreviousTxnID) == -1) { - assert(node.getFieldIndex(sfPreviousTxnLgrSeq) == -1); + XRPL_ASSERT( + node.getFieldIndex(sfPreviousTxnLgrSeq) == -1, + "ripple::ApplyStateTable::threadItem : previous ledger is not " + "set"); node.setFieldH256(sfPreviousTxnID, prevTxID); node.setFieldU32(sfPreviousTxnLgrSeq, prevLgrID); } - assert(node.getFieldH256(sfPreviousTxnID) == prevTxID); - assert(node.getFieldU32(sfPreviousTxnLgrSeq) == prevLgrID); + XRPL_ASSERT( + node.getFieldH256(sfPreviousTxnID) == prevTxID, + "ripple::ApplyStateTable::threadItem : previous transaction is a " + "match"); + XRPL_ASSERT( + node.getFieldU32(sfPreviousTxnLgrSeq) == prevLgrID, + "ripple::ApplyStateTable::threadItem : previous ledger is a match"); } } @@ -557,7 +576,9 @@ ApplyStateTable::getForMod( auto miter = mods.find(key); if (miter != mods.end()) { - assert(miter->second); + XRPL_ASSERT( + miter->second, + "ripple::ApplyStateTable::getForMod : non-null result"); return miter->second; } } @@ -613,7 +634,9 @@ ApplyStateTable::threadTx( return; } // threadItem only applied to AccountRoot - assert(sle->isThreadedType(base.rules())); + XRPL_ASSERT( + sle->isThreadedType(base.rules()), + "ripple::ApplyStateTable::threadTx : SLE is threaded"); threadItem(meta, sle); } diff --git a/src/xrpld/ledger/detail/ApplyStateTable.h b/src/xrpld/ledger/detail/ApplyStateTable.h index d1616d095e5..e4c8b9ad656 100644 --- a/src/xrpld/ledger/detail/ApplyStateTable.h +++ b/src/xrpld/ledger/detail/ApplyStateTable.h @@ -23,10 +23,10 @@ #include #include #include -#include #include #include #include +#include #include namespace ripple { diff --git a/src/xrpld/ledger/detail/ApplyView.cpp b/src/xrpld/ledger/detail/ApplyView.cpp index 735aa9906e0..8b491bdcb2b 100644 --- a/src/xrpld/ledger/detail/ApplyView.cpp +++ b/src/xrpld/ledger/detail/ApplyView.cpp @@ -19,8 +19,8 @@ #include #include +#include #include -#include namespace ripple { @@ -133,7 +133,7 @@ ApplyView::emptyDirDelete(Keylet const& directory) if (directory.type != ltDIR_NODE || node->getFieldH256(sfRootIndex) != directory.key) { - assert(!"emptyDirDelete() called with wrong node type"); + UNREACHABLE("ripple::ApplyView::emptyDirDelete : invalid node type"); return false; } diff --git a/src/xrpld/ledger/detail/ApplyViewBase.h b/src/xrpld/ledger/detail/ApplyViewBase.h index 8305731b29e..8cc38e41430 100644 --- a/src/xrpld/ledger/detail/ApplyViewBase.h +++ b/src/xrpld/ledger/detail/ApplyViewBase.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include namespace ripple { namespace detail { diff --git a/src/xrpld/ledger/detail/ApplyViewImpl.cpp b/src/xrpld/ledger/detail/ApplyViewImpl.cpp index ffbf681cd20..e01b8bfe3ba 100644 --- a/src/xrpld/ledger/detail/ApplyViewImpl.cpp +++ b/src/xrpld/ledger/detail/ApplyViewImpl.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include namespace ripple { diff --git a/src/xrpld/ledger/detail/BookDirs.cpp b/src/xrpld/ledger/detail/BookDirs.cpp index 58527b02ff2..f584db89e84 100644 --- a/src/xrpld/ledger/detail/BookDirs.cpp +++ b/src/xrpld/ledger/detail/BookDirs.cpp @@ -30,12 +30,13 @@ BookDirs::BookDirs(ReadView const& view, Book const& book) , next_quality_(getQualityNext(root_)) , key_(view_->succ(root_, next_quality_).value_or(beast::zero)) { - assert(root_ != beast::zero); + XRPL_ASSERT( + root_ != beast::zero, "ripple::BookDirs::BookDirs : nonzero root"); if (key_ != beast::zero) { if (!cdirFirst(*view_, key_, sle_, entry_, index_)) { - assert(false); + UNREACHABLE("ripple::BookDirs::BookDirs : directory is empty"); } } } @@ -70,7 +71,10 @@ BookDirs::const_iterator::operator==( if (view_ == nullptr || other.view_ == nullptr) return false; - assert(view_ == other.view_ && root_ == other.root_); + XRPL_ASSERT( + view_ == other.view_ && root_ == other.root_, + "ripple::BookDirs::const_iterator::operator== : views and roots are " + "matching"); return entry_ == other.entry_ && cur_key_ == other.cur_key_ && index_ == other.index_; } @@ -78,7 +82,9 @@ BookDirs::const_iterator::operator==( BookDirs::const_iterator::reference BookDirs::const_iterator::operator*() const { - assert(index_ != beast::zero); + XRPL_ASSERT( + index_ != beast::zero, + "ripple::BookDirs::const_iterator::operator* : nonzero index"); if (!cache_) cache_ = view_->read(keylet::offer(index_)); return *cache_; @@ -89,7 +95,9 @@ BookDirs::const_iterator::operator++() { using beast::zero; - assert(index_ != zero); + XRPL_ASSERT( + index_ != zero, + "ripple::BookDirs::const_iterator::operator++ : nonzero index"); if (!cdirNext(*view_, cur_key_, sle_, entry_, index_)) { if (index_ != 0 || @@ -102,7 +110,9 @@ BookDirs::const_iterator::operator++() } else if (!cdirFirst(*view_, cur_key_, sle_, entry_, index_)) { - assert(false); + UNREACHABLE( + "ripple::BookDirs::const_iterator::operator++ : directory is " + "empty"); } } @@ -113,7 +123,9 @@ BookDirs::const_iterator::operator++() BookDirs::const_iterator BookDirs::const_iterator::operator++(int) { - assert(index_ != beast::zero); + XRPL_ASSERT( + index_ != beast::zero, + "ripple::BookDirs::const_iterator::operator++(int) : nonzero index"); const_iterator tmp(*this); ++(*this); return tmp; diff --git a/src/xrpld/ledger/detail/Dir.cpp b/src/xrpld/ledger/detail/Dir.cpp index 6004a73095c..01d44872762 100644 --- a/src/xrpld/ledger/detail/Dir.cpp +++ b/src/xrpld/ledger/detail/Dir.cpp @@ -60,14 +60,18 @@ const_iterator::operator==(const_iterator const& other) const if (view_ == nullptr || other.view_ == nullptr) return false; - assert(view_ == other.view_ && root_.key == other.root_.key); + XRPL_ASSERT( + view_ == other.view_ && root_.key == other.root_.key, + "ripple::const_iterator::operator== : views and roots are matching"); return page_.key == other.page_.key && index_ == other.index_; } const_iterator::reference const_iterator::operator*() const { - assert(index_ != beast::zero); + XRPL_ASSERT( + index_ != beast::zero, + "ripple::const_iterator::operator* : nonzero index"); if (!cache_) cache_ = view_->read(keylet::child(index_)); return *cache_; @@ -76,7 +80,9 @@ const_iterator::operator*() const const_iterator& const_iterator::operator++() { - assert(index_ != beast::zero); + XRPL_ASSERT( + index_ != beast::zero, + "ripple::const_iterator::operator++ : nonzero index"); if (++it_ != std::end(*indexes_)) { index_ = *it_; @@ -90,7 +96,9 @@ const_iterator::operator++() const_iterator const_iterator::operator++(int) { - assert(index_ != beast::zero); + XRPL_ASSERT( + index_ != beast::zero, + "ripple::const_iterator::operator++(int) : nonzero index"); const_iterator tmp(*this); ++(*this); return tmp; @@ -109,7 +117,7 @@ const_iterator::next_page() { page_ = keylet::page(root_, next); sle_ = view_->read(page_); - assert(sle_); + XRPL_ASSERT(sle_, "ripple::const_iterator::next_page : non-null SLE"); indexes_ = &sle_->getFieldV256(sfIndexes); if (indexes_->empty()) { diff --git a/src/xrpld/ledger/detail/PaymentSandbox.cpp b/src/xrpld/ledger/detail/PaymentSandbox.cpp index d182d22b56c..745d8a90c7a 100644 --- a/src/xrpld/ledger/detail/PaymentSandbox.cpp +++ b/src/xrpld/ledger/detail/PaymentSandbox.cpp @@ -20,12 +20,11 @@ #include #include #include +#include #include #include #include -#include - namespace ripple { namespace detail { @@ -49,8 +48,12 @@ DeferredCredits::credit( STAmount const& amount, STAmount const& preCreditSenderBalance) { - assert(sender != receiver); - assert(!amount.negative()); + XRPL_ASSERT( + sender != receiver, + "ripple::detail::DeferredCredits::credit : sender is not receiver"); + XRPL_ASSERT( + !amount.negative(), + "ripple::detail::DeferredCredits::credit : positive amount"); auto const k = makeKey(sender, receiver, amount.getCurrency()); auto i = credits_.find(k); @@ -253,14 +256,14 @@ PaymentSandbox::adjustOwnerCountHook( void PaymentSandbox::apply(RawView& to) { - assert(!ps_); + XRPL_ASSERT(!ps_, "ripple::PaymentSandbox::apply : non-null sandbox"); items_.apply(to); } void PaymentSandbox::apply(PaymentSandbox& to) { - assert(ps_ == &to); + XRPL_ASSERT(ps_ == &to, "ripple::PaymentSandbox::apply : matching sandbox"); items_.apply(to); tab_.apply(to.tab_); } @@ -344,7 +347,10 @@ PaymentSandbox::balanceChanges(ReadView const& view) const { // modify auto const at = after->getType(); - assert(at == before->getType()); + XRPL_ASSERT( + at == before->getType(), + "ripple::PaymentSandbox::balanceChanges : after and before " + "types matching"); switch (at) { case ltACCOUNT_ROOT: diff --git a/src/xrpld/ledger/detail/RawStateTable.cpp b/src/xrpld/ledger/detail/RawStateTable.cpp index 4d3732f8a45..b93fc4a2aa6 100644 --- a/src/xrpld/ledger/detail/RawStateTable.cpp +++ b/src/xrpld/ledger/detail/RawStateTable.cpp @@ -63,7 +63,10 @@ class RawStateTable::sles_iter_impl : public ReadView::sles_type::iter_base { if (auto const p = dynamic_cast(&impl)) { - assert(end1_ == p->end1_ && end0_ == p->end0_); + XRPL_ASSERT( + end1_ == p->end1_ && end0_ == p->end0_, + "ripple::detail::RawStateTable::equal : matching end " + "iterators"); return iter1_ == p->iter1_ && iter0_ == p->iter0_; } @@ -73,7 +76,10 @@ class RawStateTable::sles_iter_impl : public ReadView::sles_type::iter_base void increment() override { - assert(sle1_ || sle0_); + XRPL_ASSERT( + sle1_ || sle0_, + "ripple::detail::RawStateTable::increment : either SLE is " + "non-null"); if (sle1_ && !sle0_) { @@ -179,7 +185,9 @@ RawStateTable::apply(RawView& to) const bool RawStateTable::exists(ReadView const& base, Keylet const& k) const { - assert(k.key.isNonZero()); + XRPL_ASSERT( + k.key.isNonZero(), + "ripple::detail::RawStateTable::exists : nonzero key"); auto const iter = items_.find(k.key); if (iter == items_.end()) return base.exists(k); diff --git a/src/xrpld/ledger/detail/ReadViewFwdRange.ipp b/src/xrpld/ledger/detail/ReadViewFwdRange.ipp index ae84259d7ce..86c1eedfddc 100644 --- a/src/xrpld/ledger/detail/ReadViewFwdRange.ipp +++ b/src/xrpld/ledger/detail/ReadViewFwdRange.ipp @@ -80,7 +80,10 @@ template bool ReadViewFwdRange::iterator::operator==(iterator const& other) const { - assert(view_ == other.view_); + XRPL_ASSERT( + view_ == other.view_, + "ripple::detail::ReadViewFwdRange::iterator::operator==(iterator) " + "const : input view match"); if (impl_ != nullptr && other.impl_ != nullptr) return impl_->equal(*other.impl_); diff --git a/src/xrpld/ledger/detail/View.cpp b/src/xrpld/ledger/detail/View.cpp index ae4eb095017..ebf307f1535 100644 --- a/src/xrpld/ledger/detail/View.cpp +++ b/src/xrpld/ledger/detail/View.cpp @@ -22,11 +22,11 @@ #include #include #include +#include #include #include #include #include -#include #include namespace ripple { @@ -48,7 +48,9 @@ internalDirNext( uint256& entry) { auto const& svIndexes = page->getFieldV256(sfIndexes); - assert(index <= svIndexes.size()); + XRPL_ASSERT( + index <= svIndexes.size(), + "ripple::detail::internalDirNext : index inside range"); if (index >= svIndexes.size()) { @@ -65,7 +67,7 @@ internalDirNext( else page = view.peek(keylet::page(root, next)); - assert(page); + XRPL_ASSERT(page, "ripple::detail::internalDirNext : non-null root"); if (!page) return false; @@ -418,7 +420,7 @@ confineOwnerCount( << "Account " << *id << " owner count set below 0!"; } adjusted = 0; - assert(!id); + XRPL_ASSERT(!id, "ripple::confineOwnerCount : id is not set"); } } return adjusted; @@ -467,7 +469,8 @@ forEachItem( Keylet const& root, std::function const&)> const& f) { - assert(root.type == ltDIR_NODE); + XRPL_ASSERT( + root.type == ltDIR_NODE, "ripple::forEachItem : valid root type"); if (root.type != ltDIR_NODE) return; @@ -497,7 +500,8 @@ forEachItemAfter( unsigned int limit, std::function const&)> const& f) { - assert(root.type == ltDIR_NODE); + XRPL_ASSERT( + root.type == ltDIR_NODE, "ripple::forEachItemAfter : valid root type"); if (root.type != ltDIR_NODE) return false; @@ -772,9 +776,10 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) auto const hashIndex = ledger.read(keylet::skip()); if (hashIndex) { - assert( + XRPL_ASSERT( hashIndex->getFieldU32(sfLastLedgerSequence) == - (ledger.seq() - 1)); + (ledger.seq() - 1), + "ripple::hashOfSeq : matching ledger sequence"); STVector256 vec = hashIndex->getFieldV256(sfHashes); if (vec.size() >= diff) return vec[vec.size() - diff]; @@ -802,8 +807,9 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal) if (hashIndex) { auto const lastSeq = hashIndex->getFieldU32(sfLastLedgerSequence); - assert(lastSeq >= seq); - assert((lastSeq & 0xff) == 0); + XRPL_ASSERT(lastSeq >= seq, "ripple::hashOfSeq : minimum last ledger"); + XRPL_ASSERT( + (lastSeq & 0xff) == 0, "ripple::hashOfSeq : valid last ledger"); auto const diff = (lastSeq - seq) >> 8; STVector256 vec = hashIndex->getFieldV256(sfHashes); if (vec.size() > diff) @@ -829,7 +835,7 @@ adjustOwnerCount( { if (!sle) return; - assert(amount != 0); + XRPL_ASSERT(amount, "ripple::adjustOwnerCount : nonzero amount input"); std::uint32_t const current{sle->getFieldU32(sfOwnerCount)}; AccountID const id = (*sle)[sfAccount]; std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j); @@ -894,13 +900,14 @@ trustCreate( const bool bSetDst = saLimit.getIssuer() == uDstAccountID; const bool bSetHigh = bSrcHigh ^ bSetDst; - assert(sleAccount); + XRPL_ASSERT(sleAccount, "ripple::trustCreate : non-null SLE"); if (!sleAccount) return tefINTERNAL; - assert( + XRPL_ASSERT( sleAccount->getAccountID(sfAccount) == - (bSetHigh ? uHighAccountID : uLowAccountID)); + (bSetHigh ? uHighAccountID : uLowAccountID), + "ripple::trustCreate : matching account ID"); auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID)); if (!slePeer) @@ -1052,17 +1059,25 @@ rippleCreditIOU( Currency const& currency = saAmount.getCurrency(); // Make sure issuer is involved. - assert(!bCheckIssuer || uSenderID == issuer || uReceiverID == issuer); + XRPL_ASSERT( + !bCheckIssuer || uSenderID == issuer || uReceiverID == issuer, + "ripple::rippleCreditIOU : matching issuer or don't care"); (void)issuer; // Disallow sending to self. - assert(uSenderID != uReceiverID); + XRPL_ASSERT( + uSenderID != uReceiverID, + "ripple::rippleCreditIOU : sender is not receiver"); bool const bSenderHigh = uSenderID > uReceiverID; auto const index = keylet::line(uSenderID, uReceiverID, currency); - assert(!isXRP(uSenderID) && uSenderID != noAccount()); - assert(!isXRP(uReceiverID) && uReceiverID != noAccount()); + XRPL_ASSERT( + !isXRP(uSenderID) && uSenderID != noAccount(), + "ripple::rippleCreditIOU : sender is not XRP"); + XRPL_ASSERT( + !isXRP(uReceiverID) && uReceiverID != noAccount(), + "ripple::rippleCreditIOU : receiver is not XRP"); // If the line exists, modify it accordingly. if (auto const sleRippleState = view.peek(index)) @@ -1196,8 +1211,12 @@ rippleSendIOU( { auto const issuer = saAmount.getIssuer(); - assert(!isXRP(uSenderID) && !isXRP(uReceiverID)); - assert(uSenderID != uReceiverID); + XRPL_ASSERT( + !isXRP(uSenderID) && !isXRP(uReceiverID), + "ripple::rippleSendIOU : neither sender nor receiver is XRP"); + XRPL_ASSERT( + uSenderID != uReceiverID, + "ripple::rippleSendIOU : sender is not receiver"); if (uSenderID == issuer || uReceiverID == issuer || issuer == noAccount()) { @@ -1250,7 +1269,9 @@ accountSendIOU( } else { - assert(saAmount >= beast::zero && !saAmount.holds()); + XRPL_ASSERT( + saAmount >= beast::zero && !saAmount.holds(), + "ripple::accountSendIOU : minimum amount and not MPT"); } /* If we aren't sending anything or if the sender is the same as the @@ -1420,7 +1441,9 @@ rippleSendMPT( beast::Journal j, WaiveTransferFee waiveFee) { - assert(uSenderID != uReceiverID); + XRPL_ASSERT( + uSenderID != uReceiverID, + "ripple::rippleSendMPT : sender is not receiver"); // Safe to get MPT since rippleSendMPT is only called by accountSendMPT auto const issuer = saAmount.getIssuer(); @@ -1483,7 +1506,9 @@ accountSendMPT( beast::Journal j, WaiveTransferFee waiveFee) { - assert(saAmount >= beast::zero && saAmount.holds()); + XRPL_ASSERT( + saAmount >= beast::zero && saAmount.holds(), + "ripple::accountSendMPT : minimum amount and MPT"); /* If we aren't sending anything or if the sender is the same as the * receiver then we don't need to do anything. @@ -1579,13 +1604,16 @@ issueIOU( Issue const& issue, beast::Journal j) { - assert(!isXRP(account) && !isXRP(issue.account)); + XRPL_ASSERT( + !isXRP(account) && !isXRP(issue.account), + "ripple::issueIOU : neither account nor issuer is XRP"); // Consistency check - assert(issue == amount.issue()); + XRPL_ASSERT(issue == amount.issue(), "ripple::issueIOU : matching issue"); // Can't send to self! - assert(issue.account != account); + XRPL_ASSERT( + issue.account != account, "ripple::issueIOU : not issuer account"); JLOG(j.trace()) << "issueIOU: " << to_string(account) << ": " << amount.getFullText(); @@ -1675,13 +1703,16 @@ redeemIOU( Issue const& issue, beast::Journal j) { - assert(!isXRP(account) && !isXRP(issue.account)); + XRPL_ASSERT( + !isXRP(account) && !isXRP(issue.account), + "ripple::redeemIOU : neither account nor issuer is XRP"); // Consistency check - assert(issue == amount.issue()); + XRPL_ASSERT(issue == amount.issue(), "ripple::redeemIOU : matching issue"); // Can't send to self! - assert(issue.account != account); + XRPL_ASSERT( + issue.account != account, "ripple::redeemIOU : not issuer account"); JLOG(j.trace()) << "redeemIOU: " << to_string(account) << ": " << amount.getFullText(); @@ -1745,10 +1776,11 @@ transferXRP( STAmount const& amount, beast::Journal j) { - assert(from != beast::zero); - assert(to != beast::zero); - assert(from != to); - assert(amount.native()); + XRPL_ASSERT( + from != beast::zero, "ripple::transferXRP : nonzero from account"); + XRPL_ASSERT(to != beast::zero, "ripple::transferXRP : nonzero to account"); + XRPL_ASSERT(from != to, "ripple::transferXRP : sender is not receiver"); + XRPL_ASSERT(amount.native(), "ripple::transferXRP : amount is XRP"); SLE::pointer const sender = view.peek(keylet::account(from)); SLE::pointer const receiver = view.peek(keylet::account(to)); @@ -1911,7 +1943,9 @@ cleanupOnAccountDelete( // // 3. So we verify that uDirEntry is indeed 'it'+1. Then we jam it // back to 'it' to "un-invalidate" the iterator. - assert(uDirEntry >= 1); + XRPL_ASSERT( + uDirEntry >= 1, + "ripple::cleanupOnAccountDelete : minimum dir entries"); if (uDirEntry == 0) { JLOG(j.error()) @@ -1995,7 +2029,9 @@ rippleCredit( } else { - assert(!bCheckIssuer); + XRPL_ASSERT( + !bCheckIssuer, + "ripple::rippleCredit : not checking issuer"); return rippleCreditMPT( view, uSenderID, uReceiverID, saAmount, j); } diff --git a/src/xrpld/net/detail/InfoSub.cpp b/src/xrpld/net/detail/InfoSub.cpp index 3dc891cb5f9..e22a3704802 100644 --- a/src/xrpld/net/detail/InfoSub.cpp +++ b/src/xrpld/net/detail/InfoSub.cpp @@ -145,7 +145,8 @@ InfoSub::setApiVersion(unsigned int apiVersion) unsigned int InfoSub::getApiVersion() const noexcept { - assert(apiVersion_ > 0); + XRPL_ASSERT( + apiVersion_ > 0, "ripple::InfoSub::getApiVersion : valid API version"); return apiVersion_; } diff --git a/src/xrpld/net/detail/RPCCall.cpp b/src/xrpld/net/detail/RPCCall.cpp index b92f4b1a205..e6e6540b14f 100644 --- a/src/xrpld/net/detail/RPCCall.cpp +++ b/src/xrpld/net/detail/RPCCall.cpp @@ -668,6 +668,21 @@ class RPCParser return jvRequest; } + // ledger_entry [id] [] + Json::Value + parseLedgerEntry(Json::Value const& jvParams) + { + Json::Value jvRequest{Json::objectValue}; + + jvRequest[jss::index] = jvParams[0u].asString(); + + if (jvParams.size() == 2 && + !jvParseLedger(jvRequest, jvParams[1u].asString())) + return rpcError(rpcLGR_IDX_MALFORMED); + + return jvRequest; + } + // log_level: Get log levels // log_level : Set master log level to the // specified severity log_level : Set specified @@ -962,7 +977,9 @@ class RPCParser parseTransactionEntry(Json::Value const& jvParams) { // Parameter count should have already been verified. - assert(jvParams.size() == 2); + XRPL_ASSERT( + jvParams.size() == 2, + "ripple::RPCParser::parseTransactionEntry : valid parameter count"); std::string const txHash = jvParams[0u].asString(); if (txHash.length() != 64) @@ -1181,8 +1198,7 @@ class RPCParser {"ledger_accept", &RPCParser::parseAsIs, 0, 0}, {"ledger_closed", &RPCParser::parseAsIs, 0, 0}, {"ledger_current", &RPCParser::parseAsIs, 0, 0}, - // { "ledger_entry", &RPCParser::parseLedgerEntry, - // -1, -1 }, + {"ledger_entry", &RPCParser::parseLedgerEntry, 1, 2}, {"ledger_header", &RPCParser::parseLedgerId, 1, 1}, {"ledger_request", &RPCParser::parseLedgerId, 1, 1}, {"log_level", &RPCParser::parseLogLevel, 0, 2}, diff --git a/src/xrpld/nodestore/Database.h b/src/xrpld/nodestore/Database.h index bd25046fee2..c22ede82481 100644 --- a/src/xrpld/nodestore/Database.h +++ b/src/xrpld/nodestore/Database.h @@ -246,7 +246,9 @@ class Database void storeStats(std::uint64_t count, std::uint64_t sz) { - assert(count <= sz); + XRPL_ASSERT( + count <= sz, + "ripple::NodeStore::Database::storeStats : valid inputs"); storeCount_ += count; storeSz_ += sz; } diff --git a/src/xrpld/nodestore/backend/MemoryFactory.cpp b/src/xrpld/nodestore/backend/MemoryFactory.cpp index 767db9d1695..aac305cea07 100644 --- a/src/xrpld/nodestore/backend/MemoryFactory.cpp +++ b/src/xrpld/nodestore/backend/MemoryFactory.cpp @@ -131,7 +131,8 @@ class MemoryBackend : public Backend Status fetch(void const* key, std::shared_ptr* pObject) override { - assert(db_); + XRPL_ASSERT( + db_, "ripple::NodeStore::MemoryBackend::fetch : non-null database"); uint256 const hash(uint256::fromVoid(key)); std::lock_guard _(db_->mutex); @@ -167,7 +168,8 @@ class MemoryBackend : public Backend void store(std::shared_ptr const& object) override { - assert(db_); + XRPL_ASSERT( + db_, "ripple::NodeStore::MemoryBackend::store : non-null database"); std::lock_guard _(db_->mutex); db_->table.emplace(object->getHash(), object); } @@ -187,7 +189,9 @@ class MemoryBackend : public Backend void for_each(std::function)> f) override { - assert(db_); + XRPL_ASSERT( + db_, + "ripple::NodeStore::MemoryBackend::for_each : non-null database"); for (auto const& e : db_->table) f(e.second); } diff --git a/src/xrpld/nodestore/backend/NuDBFactory.cpp b/src/xrpld/nodestore/backend/NuDBFactory.cpp index 14cd84a1ad7..24ebffd33a2 100644 --- a/src/xrpld/nodestore/backend/NuDBFactory.cpp +++ b/src/xrpld/nodestore/backend/NuDBFactory.cpp @@ -23,8 +23,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -117,7 +117,9 @@ class NuDBBackend : public Backend using namespace boost::filesystem; if (db_.is_open()) { - assert(false); + UNREACHABLE( + "ripple::NodeStore::NuDBBackend::open : database is already " + "open"); JLOG(j_.error()) << "database is already open"; return; } diff --git a/src/xrpld/nodestore/backend/RocksDBFactory.cpp b/src/xrpld/nodestore/backend/RocksDBFactory.cpp index 9ba9fffe1db..2034128949f 100644 --- a/src/xrpld/nodestore/backend/RocksDBFactory.cpp +++ b/src/xrpld/nodestore/backend/RocksDBFactory.cpp @@ -228,7 +228,9 @@ class RocksDBBackend : public Backend, public BatchWriter::Callback { if (m_db) { - assert(false); + UNREACHABLE( + "ripple::NodeStore::RocksDBBackend::open : database is already " + "open"); JLOG(m_journal.error()) << "database is already open"; return; } @@ -273,7 +275,9 @@ class RocksDBBackend : public Backend, public BatchWriter::Callback Status fetch(void const* key, std::shared_ptr* pObject) override { - assert(m_db); + XRPL_ASSERT( + m_db, + "ripple::NodeStore::RocksDBBackend::fetch : non-null database"); pObject->reset(); Status status(ok); @@ -349,7 +353,10 @@ class RocksDBBackend : public Backend, public BatchWriter::Callback void storeBatch(Batch const& batch) override { - assert(m_db); + XRPL_ASSERT( + m_db, + "ripple::NodeStore::RocksDBBackend::storeBatch : non-null " + "database"); rocksdb::WriteBatch wb; for (auto const& e : batch) @@ -381,7 +388,9 @@ class RocksDBBackend : public Backend, public BatchWriter::Callback void for_each(std::function)> f) override { - assert(m_db); + XRPL_ASSERT( + m_db, + "ripple::NodeStore::RocksDBBackend::for_each : non-null database"); rocksdb::ReadOptions const options; std::unique_ptr it(m_db->NewIterator(options)); diff --git a/src/xrpld/nodestore/detail/BatchWriter.cpp b/src/xrpld/nodestore/detail/BatchWriter.cpp index 1c5067d5bed..9fd90f82e74 100644 --- a/src/xrpld/nodestore/detail/BatchWriter.cpp +++ b/src/xrpld/nodestore/detail/BatchWriter.cpp @@ -83,7 +83,9 @@ BatchWriter::writeBatch() std::lock_guard sl(mWriteMutex); mWriteSet.swap(set); - assert(mWriteSet.empty()); + XRPL_ASSERT( + mWriteSet.empty(), + "ripple::NodeStore::BatchWriter::writeBatch : writes not set"); mWriteLoad = set.size(); if (set.empty()) diff --git a/src/xrpld/nodestore/detail/Database.cpp b/src/xrpld/nodestore/detail/Database.cpp index da15088e895..7564ca60b52 100644 --- a/src/xrpld/nodestore/detail/Database.cpp +++ b/src/xrpld/nodestore/detail/Database.cpp @@ -40,7 +40,9 @@ Database::Database( , requestBundle_(get(config, "rq_bundle", 4)) , readThreads_(std::max(1, readThreads)) { - assert(readThreads != 0); + XRPL_ASSERT( + readThreads, + "ripple::NodeStore::Database::Database : nonzero threads input"); if (earliestLedgerSeq_ < 1) Throw("Invalid earliest_seq"); @@ -87,7 +89,10 @@ Database::Database( for (auto it = read.begin(); it != read.end(); ++it) { - assert(!it->second.empty()); + XRPL_ASSERT( + !it->second.empty(), + "ripple::NodeStore::Database::Database : non-empty " + "data"); auto const& hash = it->first; auto const& data = it->second; @@ -161,7 +166,9 @@ Database::stop() while (readThreads_.load() != 0) { - assert(steady_clock::now() - start < 30s); + XRPL_ASSERT( + steady_clock::now() - start < 30s, + "ripple::NodeStore::Database::stop : maximum stop duration"); std::this_thread::yield(); } @@ -212,7 +219,9 @@ Database::importInternal(Backend& dstBackend, Database& srcDB) }; srcDB.for_each([&](std::shared_ptr nodeObject) { - assert(nodeObject); + XRPL_ASSERT( + nodeObject, + "ripple::NodeStore::Database::importInternal : non-null node"); if (!nodeObject) // This should never happen return; @@ -256,7 +265,9 @@ Database::fetchNodeObject( void Database::getCountsJson(Json::Value& obj) { - assert(obj.isObject()); + XRPL_ASSERT( + obj.isObject(), + "ripple::NodeStore::Database::getCountsJson : valid input type"); { std::unique_lock lock(readLock_); diff --git a/src/xrpld/nodestore/detail/DatabaseNodeImp.h b/src/xrpld/nodestore/detail/DatabaseNodeImp.h index 326db38a661..d90f02ce877 100644 --- a/src/xrpld/nodestore/detail/DatabaseNodeImp.h +++ b/src/xrpld/nodestore/detail/DatabaseNodeImp.h @@ -76,7 +76,10 @@ class DatabaseNodeImp : public Database j); } - assert(backend_); + XRPL_ASSERT( + backend_, + "ripple::NodeStore::DatabaseNodeImp::DatabaseNodeImp : non-null " + "backend"); } ~DatabaseNodeImp() diff --git a/src/xrpld/nodestore/detail/DecodedBlob.cpp b/src/xrpld/nodestore/detail/DecodedBlob.cpp index b71f2c543b1..fbf9f532a0a 100644 --- a/src/xrpld/nodestore/detail/DecodedBlob.cpp +++ b/src/xrpld/nodestore/detail/DecodedBlob.cpp @@ -19,8 +19,8 @@ #include #include +#include #include -#include namespace ripple { namespace NodeStore { @@ -72,7 +72,9 @@ DecodedBlob::DecodedBlob(void const* key, void const* value, int valueBytes) std::shared_ptr DecodedBlob::createObject() { - assert(m_success); + XRPL_ASSERT( + m_success, + "ripple::NodeStore::DecodedBlob::createObject : valid object type"); std::shared_ptr object; diff --git a/src/xrpld/nodestore/detail/EncodedBlob.h b/src/xrpld/nodestore/detail/EncodedBlob.h index 2b506a0df3f..01b167159e7 100644 --- a/src/xrpld/nodestore/detail/EncodedBlob.h +++ b/src/xrpld/nodestore/detail/EncodedBlob.h @@ -22,10 +22,10 @@ #include #include +#include #include #include #include -#include #include namespace ripple { @@ -80,7 +80,9 @@ class EncodedBlob public: explicit EncodedBlob(std::shared_ptr const& obj) : size_([&obj]() { - assert(obj); + XRPL_ASSERT( + obj, + "ripple::NodeStore::EncodedBlob::EncodedBlob : non-null input"); if (!obj) throw std::runtime_error( @@ -100,9 +102,11 @@ class EncodedBlob ~EncodedBlob() { - assert( + XRPL_ASSERT( ((ptr_ == payload_.data()) && (size_ <= payload_.size())) || - ((ptr_ != payload_.data()) && (size_ > payload_.size()))); + ((ptr_ != payload_.data()) && (size_ > payload_.size())), + "ripple::NodeStore::EncodedBlob::~EncodedBlob : valid payload " + "pointer"); if (ptr_ != payload_.data()) delete[] ptr_; diff --git a/src/xrpld/nodestore/detail/ManagerImp.cpp b/src/xrpld/nodestore/detail/ManagerImp.cpp index 56dc66ee644..24371dd58c3 100644 --- a/src/xrpld/nodestore/detail/ManagerImp.cpp +++ b/src/xrpld/nodestore/detail/ManagerImp.cpp @@ -91,7 +91,9 @@ ManagerImp::erase(Factory& factory) std::find_if(list_.begin(), list_.end(), [&factory](Factory* other) { return other == &factory; }); - assert(iter != list_.end()); + XRPL_ASSERT( + iter != list_.end(), + "ripple::NodeStore::ManagerImp::erase : valid input"); list_.erase(iter); } diff --git a/src/xrpld/overlay/Compression.h b/src/xrpld/overlay/Compression.h index 1cf13fcb185..c7437badc4d 100644 --- a/src/xrpld/overlay/Compression.h +++ b/src/xrpld/overlay/Compression.h @@ -64,7 +64,9 @@ decompress( JLOG(debugLog().warn()) << "decompress: invalid compression algorithm " << static_cast(algorithm); - assert(0); + UNREACHABLE( + "ripple::compression::decompress : invalid compression " + "algorithm"); } } catch (...) @@ -99,7 +101,9 @@ compress( { JLOG(debugLog().warn()) << "compress: invalid compression algorithm" << static_cast(algorithm); - assert(0); + UNREACHABLE( + "ripple::compression::compress : invalid compression " + "algorithm"); } } catch (...) diff --git a/src/xrpld/overlay/Slot.h b/src/xrpld/overlay/Slot.h index 2a8b2146a02..92ec09de124 100644 --- a/src/xrpld/overlay/Slot.h +++ b/src/xrpld/overlay/Slot.h @@ -362,7 +362,9 @@ Slot::update( << consideredPoolSize << " selected " << *s << " " << *std::next(s, 1) << " " << *std::next(s, 2); - assert(peers_.size() >= MAX_SELECTED_PEERS); + XRPL_ASSERT( + peers_.size() >= MAX_SELECTED_PEERS, + "ripple::reduce_relay::Slot::update : minimum peers"); // squelch peers which are not selected and // not already squelched diff --git a/src/xrpld/overlay/detail/ConnectAttempt.cpp b/src/xrpld/overlay/detail/ConnectAttempt.cpp index 6a3ebdd5b98..4bb76369c4c 100644 --- a/src/xrpld/overlay/detail/ConnectAttempt.cpp +++ b/src/xrpld/overlay/detail/ConnectAttempt.cpp @@ -90,7 +90,9 @@ ConnectAttempt::run() void ConnectAttempt::close() { - assert(strand_.running_in_this_thread()); + XRPL_ASSERT( + strand_.running_in_this_thread(), + "ripple::ConnectAttempt::close : strand in this thread"); if (socket_.is_open()) { error_code ec; diff --git a/src/xrpld/overlay/detail/Message.cpp b/src/xrpld/overlay/detail/Message.cpp index 71917db0506..cdcf433f610 100644 --- a/src/xrpld/overlay/detail/Message.cpp +++ b/src/xrpld/overlay/detail/Message.cpp @@ -34,7 +34,8 @@ Message::Message( auto const messageBytes = messageSize(message); - assert(messageBytes != 0); + XRPL_ASSERT( + messageBytes, "ripple::Message::Message : non-empty message input"); buffer_.resize(headerBytes + messageBytes); @@ -43,7 +44,9 @@ Message::Message( if (messageBytes != 0) message.SerializeToArray(buffer_.data() + headerBytes, messageBytes); - assert(getBufferSize() == totalSize(message)); + XRPL_ASSERT( + getBufferSize() == totalSize(message), + "ripple::Message::Message : message size matches the buffer"); } // static diff --git a/src/xrpld/overlay/detail/OverlayImpl.cpp b/src/xrpld/overlay/detail/OverlayImpl.cpp index e41a08a43d1..e27b752ae10 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.cpp +++ b/src/xrpld/overlay/detail/OverlayImpl.cpp @@ -294,7 +294,9 @@ OverlayImpl::onHandoff( std::lock_guard lock(mutex_); { auto const result = m_peers.emplace(peer->slot(), peer); - assert(result.second); + XRPL_ASSERT( + result.second, + "ripple::OverlayImpl::onHandoff : peer is inserted"); (void)result.second; } list_.emplace(peer.get(), peer); @@ -387,7 +389,7 @@ OverlayImpl::makeErrorResponse( void OverlayImpl::connect(beast::IP::Endpoint const& remote_endpoint) { - assert(work_); + XRPL_ASSERT(work_, "ripple::OverlayImpl::connect : work is set"); auto usage = resourceManager().newOutboundEndpoint(remote_endpoint); if (usage.disconnect(journal_)) @@ -429,7 +431,9 @@ OverlayImpl::add_active(std::shared_ptr const& peer) { auto const result = m_peers.emplace(peer->slot(), peer); - assert(result.second); + XRPL_ASSERT( + result.second, + "ripple::OverlayImpl::add_active : peer is inserted"); (void)result.second; } @@ -438,7 +442,9 @@ OverlayImpl::add_active(std::shared_ptr const& peer) std::piecewise_construct, std::make_tuple(peer->id()), std::make_tuple(peer)); - assert(result.second); + XRPL_ASSERT( + result.second, + "ripple::OverlayImpl::add_active : peer ID is inserted"); (void)result.second; } @@ -461,7 +467,8 @@ OverlayImpl::remove(std::shared_ptr const& slot) { std::lock_guard lock(mutex_); auto const iter = m_peers.find(slot); - assert(iter != m_peers.end()); + XRPL_ASSERT( + iter != m_peers.end(), "ripple::OverlayImpl::remove : valid input"); m_peers.erase(iter); } @@ -598,7 +605,9 @@ OverlayImpl::activate(std::shared_ptr const& peer) std::piecewise_construct, std::make_tuple(peer->id()), std::make_tuple(peer))); - assert(result.second); + XRPL_ASSERT( + result.second, + "ripple::OverlayImpl::activate : peer ID is inserted"); (void)result.second; } @@ -609,7 +618,7 @@ OverlayImpl::activate(std::shared_ptr const& peer) << ")"; // We just accepted this peer so we have non-zero active peers - assert(size() != 0); + XRPL_ASSERT(size(), "ripple::OverlayImpl::activate : nonzero peers"); } void @@ -648,7 +657,10 @@ OverlayImpl::onManifests( // the loaded Manifest out of the optional so we need to // reload it here. mo = deserializeManifest(serialized); - assert(mo); + XRPL_ASSERT( + mo, + "ripple::OverlayImpl::onManifests : manifest " + "deserialization succeeded"); app_.getOPs().pubManifest(*mo); diff --git a/src/xrpld/overlay/detail/OverlayImpl.h b/src/xrpld/overlay/detail/OverlayImpl.h index a50dfc5e905..f1458702fe6 100644 --- a/src/xrpld/overlay/detail/OverlayImpl.h +++ b/src/xrpld/overlay/detail/OverlayImpl.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #include #include #include -#include #include #include #include @@ -600,7 +600,9 @@ class OverlayImpl : public Overlay, public reduce_relay::SquelchHandler { auto counts = m_traffic.getCounts(); std::lock_guard lock(m_statsMutex); - assert(counts.size() == m_stats.trafficGauges.size()); + XRPL_ASSERT( + counts.size() == m_stats.trafficGauges.size(), + "ripple::OverlayImpl::collect_metrics : counts size do match"); for (std::size_t i = 0; i < counts.size(); ++i) { diff --git a/src/xrpld/overlay/detail/PeerImp.cpp b/src/xrpld/overlay/detail/PeerImp.cpp index 4f5f1470f8e..b04e1a6b024 100644 --- a/src/xrpld/overlay/detail/PeerImp.cpp +++ b/src/xrpld/overlay/detail/PeerImp.cpp @@ -565,7 +565,9 @@ PeerImp::hasRange(std::uint32_t uMin, std::uint32_t uMax) void PeerImp::close() { - assert(strand_.running_in_this_thread()); + XRPL_ASSERT( + strand_.running_in_this_thread(), + "ripple::PeerImp::close : strand in this thread"); if (socket_.is_open()) { detaching_ = true; // DEPRECATED @@ -606,7 +608,9 @@ PeerImp::fail(std::string const& reason) void PeerImp::fail(std::string const& name, error_code ec) { - assert(strand_.running_in_this_thread()); + XRPL_ASSERT( + strand_.running_in_this_thread(), + "ripple::PeerImp::fail : strand in this thread"); if (socket_.is_open()) { JLOG(journal_.warn()) @@ -619,9 +623,14 @@ PeerImp::fail(std::string const& name, error_code ec) void PeerImp::gracefulClose() { - assert(strand_.running_in_this_thread()); - assert(socket_.is_open()); - assert(!gracefulClose_); + XRPL_ASSERT( + strand_.running_in_this_thread(), + "ripple::PeerImp::gracefulClose : strand in this thread"); + XRPL_ASSERT( + socket_.is_open(), "ripple::PeerImp::gracefulClose : socket is open"); + XRPL_ASSERT( + !gracefulClose_, + "ripple::PeerImp::gracefulClose : socket is not closing"); gracefulClose_ = true; if (send_queue_.size() > 0) return; @@ -747,7 +756,9 @@ PeerImp::onShutdown(error_code ec) void PeerImp::doAccept() { - assert(read_buffer_.size() == 0); + XRPL_ASSERT( + read_buffer_.size() == 0, + "ripple::PeerImp::doAccept : empty read buffer"); JLOG(journal_.debug()) << "doAccept: " << remote_address_; @@ -948,7 +959,9 @@ PeerImp::onWriteMessage(error_code ec, std::size_t bytes_transferred) metrics_.sent.add_message(bytes_transferred); - assert(!send_queue_.empty()); + XRPL_ASSERT( + !send_queue_.empty(), + "ripple::PeerImp::onWriteMessage : non-empty send buffer"); send_queue_.pop(); if (!send_queue_.empty()) { @@ -2002,13 +2015,18 @@ PeerImp::onValidatorListMessage( case ListDisposition::pending: { std::lock_guard sl(recentLock_); - assert(applyResult.publisherKey); + XRPL_ASSERT( + applyResult.publisherKey, + "ripple::PeerImp::onValidatorListMessage : publisher key is " + "set"); auto const& pubKey = *applyResult.publisherKey; #ifndef NDEBUG if (auto const iter = publisherListSequences_.find(pubKey); iter != publisherListSequences_.end()) { - assert(iter->second < applyResult.sequence); + XRPL_ASSERT( + iter->second < applyResult.sequence, + "ripple::PeerImp::onValidatorListMessage : lower sequence"); } #endif publisherListSequences_[pubKey] = applyResult.sequence; @@ -2019,10 +2037,14 @@ PeerImp::onValidatorListMessage( #ifndef NDEBUG { std::lock_guard sl(recentLock_); - assert(applyResult.sequence && applyResult.publisherKey); - assert( + XRPL_ASSERT( + applyResult.sequence && applyResult.publisherKey, + "ripple::PeerImp::onValidatorListMessage : nonzero sequence " + "and set publisher key"); + XRPL_ASSERT( publisherListSequences_[*applyResult.publisherKey] <= - applyResult.sequence); + applyResult.sequence, + "ripple::PeerImp::onValidatorListMessage : maximum sequence"); } #endif // !NDEBUG @@ -2033,7 +2055,9 @@ PeerImp::onValidatorListMessage( case ListDisposition::unsupported_version: break; default: - assert(false); + UNREACHABLE( + "ripple::PeerImp::onValidatorListMessage : invalid best list " + "disposition"); } // Charge based on the worst result @@ -2072,7 +2096,9 @@ PeerImp::onValidatorListMessage( fee_ = Resource::feeBadData; break; default: - assert(false); + UNREACHABLE( + "ripple::PeerImp::onValidatorListMessage : invalid worst list " + "disposition"); } // Log based on all the results. @@ -2130,7 +2156,9 @@ PeerImp::onValidatorListMessage( << "(s) from peer " << remote_address_; break; default: - assert(false); + UNREACHABLE( + "ripple::PeerImp::onValidatorListMessage : invalid list " + "disposition"); } } } @@ -2805,7 +2833,7 @@ PeerImp::checkPropose( JLOG(p_journal_.trace()) << "Checking " << (isTrusted ? "trusted" : "UNTRUSTED") << " proposal"; - assert(packet); + XRPL_ASSERT(packet, "ripple::PeerImp::checkPropose : non-null packet"); if (!cluster() && !peerPos.checkSign()) { diff --git a/src/xrpld/overlay/detail/ProtocolMessage.h b/src/xrpld/overlay/detail/ProtocolMessage.h index 8a7512afb31..54f99eb73d0 100644 --- a/src/xrpld/overlay/detail/ProtocolMessage.h +++ b/src/xrpld/overlay/detail/ProtocolMessage.h @@ -24,11 +24,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -175,7 +175,9 @@ parseMessageHeader( MessageHeader hdr; auto iter = buffersBegin(bufs); - assert(iter != buffersEnd(bufs)); + XRPL_ASSERT( + iter != buffersEnd(bufs), + "ripple::detail::parseMessageHeader : non-empty buffer"); // Check valid header compressed message: // - 4 bits are the compression algorithm, 1st bit is always set to 1 diff --git a/src/xrpld/overlay/detail/TrafficCount.h b/src/xrpld/overlay/detail/TrafficCount.h index 7dd5cbba901..9b4fabdc344 100644 --- a/src/xrpld/overlay/detail/TrafficCount.h +++ b/src/xrpld/overlay/detail/TrafficCount.h @@ -21,6 +21,7 @@ #define RIPPLE_OVERLAY_TRAFFIC_H_INCLUDED #include +#include #include #include @@ -171,7 +172,9 @@ class TrafficCount void addCount(category cat, bool inbound, int bytes) { - assert(cat <= category::unknown); + XRPL_ASSERT( + cat <= category::unknown, + "ripple::TrafficCount::addCount : valid category input"); if (inbound) { diff --git a/src/xrpld/overlay/detail/ZeroCopyStream.h b/src/xrpld/overlay/detail/ZeroCopyStream.h index da0f0d380d8..ac210bf6b9e 100644 --- a/src/xrpld/overlay/detail/ZeroCopyStream.h +++ b/src/xrpld/overlay/detail/ZeroCopyStream.h @@ -20,6 +20,8 @@ #ifndef RIPPLE_OVERLAY_ZEROCOPYSTREAM_H_INCLUDED #define RIPPLE_OVERLAY_ZEROCOPYSTREAM_H_INCLUDED +#include + #include #include #include @@ -204,7 +206,8 @@ template void ZeroCopyOutputStream::BackUp(int count) { - assert(count <= commit_); + XRPL_ASSERT( + count <= commit_, "ripple::ZeroCopyOutputStream::BackUp : valid input"); auto const n = commit_ - count; streambuf_.commit(n); count_ += n; diff --git a/src/xrpld/peerfinder/detail/Bootcache.cpp b/src/xrpld/peerfinder/detail/Bootcache.cpp index 9e94a12e619..1af5f0e1c97 100644 --- a/src/xrpld/peerfinder/detail/Bootcache.cpp +++ b/src/xrpld/peerfinder/detail/Bootcache.cpp @@ -159,7 +159,9 @@ Bootcache::on_success(beast::IP::Endpoint const& endpoint) ++entry.valence(); m_map.erase(result.first); result = m_map.insert(value_type(endpoint, entry)); - assert(result.second); + XRPL_ASSERT( + result.second, + "ripple:PeerFinder::Bootcache::on_success : endpoint inserted"); } Entry const& entry(result.first->right); JLOG(m_journal.info()) << beast::leftw(18) << "Bootcache connect " @@ -185,7 +187,9 @@ Bootcache::on_failure(beast::IP::Endpoint const& endpoint) --entry.valence(); m_map.erase(result.first); result = m_map.insert(value_type(endpoint, entry)); - assert(result.second); + XRPL_ASSERT( + result.second, + "ripple:PeerFinder::Bootcache::on_failure : endpoint inserted"); } Entry const& entry(result.first->right); auto const n(std::abs(entry.valence())); diff --git a/src/xrpld/peerfinder/detail/Counts.h b/src/xrpld/peerfinder/detail/Counts.h index 1ea6ff976de..0078ae28411 100644 --- a/src/xrpld/peerfinder/detail/Counts.h +++ b/src/xrpld/peerfinder/detail/Counts.h @@ -71,7 +71,9 @@ class Counts can_activate(Slot const& s) const { // Must be handshaked and in the right state - assert(s.state() == Slot::connected || s.state() == Slot::accept); + XRPL_ASSERT( + s.state() == Slot::connected || s.state() == Slot::accept, + "ripple::PeerFinder::Counts::can_activate : valid input state"); if (s.fixed() || s.reserved()) return true; @@ -262,13 +264,18 @@ class Counts switch (s.state()) { case Slot::accept: - assert(s.inbound()); + XRPL_ASSERT( + s.inbound(), + "ripple::PeerFinder::Counts::adjust : input is inbound"); m_acceptCount += n; break; case Slot::connect: case Slot::connected: - assert(!s.inbound()); + XRPL_ASSERT( + !s.inbound(), + "ripple::PeerFinder::Counts::adjust : input is not " + "inbound"); m_attempts += n; break; @@ -290,7 +297,8 @@ class Counts break; default: - assert(false); + UNREACHABLE( + "ripple::PeerFinder::Counts::adjust : invalid input state"); break; }; } diff --git a/src/xrpld/peerfinder/detail/Handouts.h b/src/xrpld/peerfinder/detail/Handouts.h index 0b54dc205fa..36e9c712e38 100644 --- a/src/xrpld/peerfinder/detail/Handouts.h +++ b/src/xrpld/peerfinder/detail/Handouts.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -43,7 +43,9 @@ template std::size_t handout_one(Target& t, HopContainer& h) { - assert(!t.full()); + XRPL_ASSERT( + !t.full(), + "ripple::PeerFinder::detail::handout_one : target is not full"); for (auto it = h.begin(); it != h.end(); ++it) { auto const& e = *it; diff --git a/src/xrpld/peerfinder/detail/Livecache.h b/src/xrpld/peerfinder/detail/Livecache.h index 1583ccd96a3..03d99592107 100644 --- a/src/xrpld/peerfinder/detail/Livecache.h +++ b/src/xrpld/peerfinder/detail/Livecache.h @@ -432,7 +432,9 @@ Livecache::insert(Endpoint const& ep) // but we will use it to make connections and hand it out // when redirecting. // - assert(ep.hops <= (Tuning::maxHops + 1)); + XRPL_ASSERT( + ep.hops <= (Tuning::maxHops + 1), + "ripple::PeerFinder::Livecache::insert : maximum input hops"); auto result = m_cache.emplace(ep.address, ep); Element& e(result.first->second); if (result.second) @@ -530,7 +532,9 @@ template void Livecache::hops_t::insert(Element& e) { - assert(e.endpoint.hops <= Tuning::maxHops + 1); + XRPL_ASSERT( + e.endpoint.hops <= Tuning::maxHops + 1, + "ripple::PeerFinder::Livecache::hops_t::insert : maximum input hops"); // This has security implications without a shuffle m_lists[e.endpoint.hops].push_front(e); ++m_hist[e.endpoint.hops]; @@ -540,7 +544,9 @@ template void Livecache::hops_t::reinsert(Element& e, std::uint32_t numHops) { - assert(numHops <= Tuning::maxHops + 1); + XRPL_ASSERT( + numHops <= Tuning::maxHops + 1, + "ripple::PeerFinder::Livecache::hops_t::reinsert : maximum hops input"); auto& list = m_lists[e.endpoint.hops]; list.erase(list.iterator_to(e)); diff --git a/src/xrpld/peerfinder/detail/Logic.h b/src/xrpld/peerfinder/detail/Logic.h index 3bfb9942c3a..01f38ad7fd4 100644 --- a/src/xrpld/peerfinder/detail/Logic.h +++ b/src/xrpld/peerfinder/detail/Logic.h @@ -304,7 +304,10 @@ class Logic // Add slot to table auto const result(slots_.emplace(slot->remote_endpoint(), slot)); // Remote address must not already exist - assert(result.second); + XRPL_ASSERT( + result.second, + "ripple::PeerFinder::Logic::new_inbound_slot : remote endpoint " + "inserted"); // Add to the connected address list connectedAddresses_.emplace(remote_endpoint.address()); @@ -339,7 +342,10 @@ class Logic // Add slot to table auto const result = slots_.emplace(slot->remote_endpoint(), slot); // Remote address must not already exist - assert(result.second); + XRPL_ASSERT( + result.second, + "ripple::PeerFinder::Logic::new_outbound_slot : remote endpoint " + "inserted"); // Add to the connected address list connectedAddresses_.emplace(remote_endpoint.address()); @@ -362,7 +368,9 @@ class Logic std::lock_guard _(lock_); // The object must exist in our table - assert(slots_.find(slot->remote_endpoint()) != slots_.end()); + XRPL_ASSERT( + slots_.find(slot->remote_endpoint()) != slots_.end(), + "ripple::PeerFinder::Logic::onConnected : valid slot input"); // Assign the local endpoint now that it's known slot->local_endpoint(local_endpoint); @@ -371,8 +379,10 @@ class Logic auto const iter(slots_.find(local_endpoint)); if (iter != slots_.end()) { - assert( - iter->second->local_endpoint() == slot->remote_endpoint()); + XRPL_ASSERT( + iter->second->local_endpoint() == slot->remote_endpoint(), + "ripple::PeerFinder::Logic::onConnected : local and remote " + "endpoints do match"); JLOG(m_journal.warn()) << beast::leftw(18) << "Logic dropping " << slot->remote_endpoint() << " as self connect"; @@ -397,10 +407,13 @@ class Logic std::lock_guard _(lock_); // The object must exist in our table - assert(slots_.find(slot->remote_endpoint()) != slots_.end()); + XRPL_ASSERT( + slots_.find(slot->remote_endpoint()) != slots_.end(), + "ripple::PeerFinder::Logic::activate : valid slot input"); // Must be accepted or connected - assert( - slot->state() == Slot::accept || slot->state() == Slot::connected); + XRPL_ASSERT( + slot->state() == Slot::accept || slot->state() == Slot::connected, + "ripple::PeerFinder::Logic::activate : valid slot state"); // Check for duplicate connection by key if (keys_.find(key) != keys_.end()) @@ -426,7 +439,9 @@ class Logic { [[maybe_unused]] bool const inserted = keys_.insert(key).second; // Public key must not already exist - assert(inserted); + XRPL_ASSERT( + inserted, + "ripple::PeerFinder::Logic::activate : public key inserted"); } // Change state and update counts @@ -788,10 +803,14 @@ class Logic std::lock_guard _(lock_); // The object must exist in our table - assert(slots_.find(slot->remote_endpoint()) != slots_.end()); + XRPL_ASSERT( + slots_.find(slot->remote_endpoint()) != slots_.end(), + "ripple::PeerFinder::Logic::on_endpoints : valid slot input"); // Must be handshaked! - assert(slot->state() == Slot::active); + XRPL_ASSERT( + slot->state() == Slot::active, + "ripple::PeerFinder::Logic::on_endpoints : valid slot state"); clock_type::time_point const now(m_clock.now()); @@ -803,7 +822,9 @@ class Logic for (auto const& ep : list) { - assert(ep.hops != 0); + XRPL_ASSERT( + ep.hops, + "ripple::PeerFinder::Logic::on_endpoints : nonzero hops"); slot->recent.insert(ep.address, ep.hops); @@ -956,7 +977,9 @@ class Logic break; default: - assert(false); + UNREACHABLE( + "ripple::PeerFinder::Logic::on_closed : invalid slot " + "state"); break; } } diff --git a/src/xrpld/peerfinder/detail/SlotImp.cpp b/src/xrpld/peerfinder/detail/SlotImp.cpp index a5d13aa729e..c1950aac508 100644 --- a/src/xrpld/peerfinder/detail/SlotImp.cpp +++ b/src/xrpld/peerfinder/detail/SlotImp.cpp @@ -64,19 +64,32 @@ void SlotImp::state(State state_) { // Must go through activate() to set active state - assert(state_ != active); + XRPL_ASSERT( + state_ != active, + "ripple::PeerFinder::SlotImp::state : input state is not active"); // The state must be different - assert(state_ != m_state); + XRPL_ASSERT( + state_ != m_state, + "ripple::PeerFinder::SlotImp::state : input state is different from " + "current"); // You can't transition into the initial states - assert(state_ != accept && state_ != connect); + XRPL_ASSERT( + state_ != accept && state_ != connect, + "ripple::PeerFinder::SlotImp::state : input state is not an initial"); // Can only become connected from outbound connect state - assert(state_ != connected || (!m_inbound && m_state == connect)); + XRPL_ASSERT( + state_ != connected || (!m_inbound && m_state == connect), + "ripple::PeerFinder::SlotImp::state : input state is not connected an " + "invalid state"); // Can't gracefully close on an outbound connection attempt - assert(state_ != closing || m_state != connect); + XRPL_ASSERT( + state_ != closing || m_state != connect, + "ripple::PeerFinder::SlotImp::state : input state is not closing an " + "invalid state"); m_state = state_; } @@ -85,7 +98,9 @@ void SlotImp::activate(clock_type::time_point const& now) { // Can only become active from the accept or connected state - assert(m_state == accept || m_state == connected); + XRPL_ASSERT( + m_state == accept || m_state == connected, + "ripple::PeerFinder::SlotImp::activate : valid state"); m_state = active; whenAcceptEndpoints = now; diff --git a/src/xrpld/perflog/detail/PerfLogImp.cpp b/src/xrpld/perflog/detail/PerfLogImp.cpp index a4773b33e10..559bdb1743c 100644 --- a/src/xrpld/perflog/detail/PerfLogImp.cpp +++ b/src/xrpld/perflog/detail/PerfLogImp.cpp @@ -54,7 +54,9 @@ PerfLogImp::Counters::Counters( if (!inserted) { // Ensure that no other function populates this entry. - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::Counters::Counters : failed to " + "insert label"); } } } @@ -67,7 +69,9 @@ PerfLogImp::Counters::Counters( if (!inserted) { // Ensure that no other function populates this entry. - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::Counters::Counters : failed to " + "insert job type"); } } } @@ -326,7 +330,7 @@ PerfLogImp::rpcStart(std::string const& method, std::uint64_t const requestId) auto counter = counters_.rpc_.find(method); if (counter == counters_.rpc_.end()) { - assert(false); + UNREACHABLE("ripple::perf::PerfLogImp::rpcStart : valid method input"); return; } @@ -348,7 +352,7 @@ PerfLogImp::rpcEnd( auto counter = counters_.rpc_.find(method); if (counter == counters_.rpc_.end()) { - assert(false); + UNREACHABLE("ripple::perf::PerfLogImp::rpcEnd : valid method input"); return; } steady_time_point startTime; @@ -362,7 +366,8 @@ PerfLogImp::rpcEnd( } else { - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::rpcEnd : valid requestId input"); } } std::lock_guard lock(counter->second.mutex); @@ -380,7 +385,8 @@ PerfLogImp::jobQueue(JobType const type) auto counter = counters_.jq_.find(type); if (counter == counters_.jq_.end()) { - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::jobQueue : valid job type input"); return; } std::lock_guard lock(counter->second.mutex); @@ -397,7 +403,8 @@ PerfLogImp::jobStart( auto counter = counters_.jq_.find(type); if (counter == counters_.jq_.end()) { - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::jobStart : valid job type input"); return; } { @@ -416,7 +423,8 @@ PerfLogImp::jobFinish(JobType const type, microseconds dur, int instance) auto counter = counters_.jq_.find(type); if (counter == counters_.jq_.end()) { - assert(false); + UNREACHABLE( + "ripple::perf::PerfLogImp::jobFinish : valid job type input"); return; } { diff --git a/src/xrpld/rpc/Status.h b/src/xrpld/rpc/Status.h index 1d94a6837a8..8edbb13ed36 100644 --- a/src/xrpld/rpc/Status.h +++ b/src/xrpld/rpc/Status.h @@ -20,9 +20,9 @@ #ifndef RIPPLE_RPC_STATUS_H_INCLUDED #define RIPPLE_RPC_STATUS_H_INCLUDED +#include #include #include -#include namespace ripple { namespace RPC { @@ -95,7 +95,8 @@ struct Status : public std::exception TER toTER() const { - assert(type_ == Type::TER); + XRPL_ASSERT( + type_ == Type::TER, "ripple::RPC::Status::toTER : type is TER"); return TER::fromInt(code_); } @@ -104,7 +105,9 @@ struct Status : public std::exception error_code_i toErrorCode() const { - assert(type_ == Type::error_code_i); + XRPL_ASSERT( + type_ == Type::error_code_i, + "ripple::RPC::Status::toTER : type is error code"); return error_code_i(code_); } diff --git a/src/xrpld/rpc/detail/Handler.cpp b/src/xrpld/rpc/detail/Handler.cpp index 90dee4475a1..4847f5e0d6b 100644 --- a/src/xrpld/rpc/detail/Handler.cpp +++ b/src/xrpld/rpc/detail/Handler.cpp @@ -38,7 +38,7 @@ byRef(Function const& f) result = f(context); if (result.type() != Json::objectValue) { - assert(false); + UNREACHABLE("ripple::RPC::byRef : result is object"); result = RPC::makeObjectValue(result); } @@ -50,9 +50,10 @@ template Status handle(JsonContext& context, Object& object) { - assert( + XRPL_ASSERT( context.apiVersion >= HandlerImpl::minApiVer && - context.apiVersion <= HandlerImpl::maxApiVer); + context.apiVersion <= HandlerImpl::maxApiVer, + "ripple::RPC::handle : valid API version"); HandlerImpl handler(context); auto status = handler.check(); @@ -204,8 +205,12 @@ class HandlerTable unsigned minVer, unsigned maxVer) { - assert(minVer <= maxVer); - assert(maxVer <= RPC::apiMaximumValidVersion); + XRPL_ASSERT( + minVer <= maxVer, + "ripple::RPC::HandlerTable : valid API version range"); + XRPL_ASSERT( + maxVer <= RPC::apiMaximumValidVersion, + "ripple::RPC::HandlerTable : valid max API version"); return std::any_of( range.first, diff --git a/src/xrpld/rpc/detail/RPCHelpers.cpp b/src/xrpld/rpc/detail/RPCHelpers.cpp index af204eaedf7..4c0a8ee3689 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.cpp +++ b/src/xrpld/rpc/detail/RPCHelpers.cpp @@ -544,19 +544,22 @@ getLedger(T& ledger, LedgerShortcut shortcut, Context& context) return {rpcNOT_SYNCED, "notSynced"}; } - assert(!ledger->open()); + XRPL_ASSERT( + !ledger->open(), "ripple::RPC::getLedger : validated is not open"); } else { if (shortcut == LedgerShortcut::CURRENT) { ledger = context.ledgerMaster.getCurrentLedger(); - assert(ledger->open()); + XRPL_ASSERT( + ledger->open(), "ripple::RPC::getLedger : current is open"); } else if (shortcut == LedgerShortcut::CLOSED) { ledger = context.ledgerMaster.getClosedLedger(); - assert(!ledger->open()); + XRPL_ASSERT( + !ledger->open(), "ripple::RPC::getLedger : closed is not open"); } else { @@ -945,27 +948,29 @@ chooseLedgerEntryType(Json::Value const& params) {jss::escrow, ltESCROW}, {jss::fee, ltFEE_SETTINGS}, {jss::hashes, ltLEDGER_HASHES}, - {jss::nunl, ltNEGATIVE_UNL}, - {jss::oracle, ltORACLE}, + {jss::mpt_issuance, ltMPTOKEN_ISSUANCE}, + {jss::mptoken, ltMPTOKEN}, {jss::nft_offer, ltNFTOKEN_OFFER}, {jss::nft_page, ltNFTOKEN_PAGE}, + {jss::nunl, ltNEGATIVE_UNL}, {jss::offer, ltOFFER}, + {jss::oracle, ltORACLE}, {jss::payment_channel, ltPAYCHAN}, {jss::signer_list, ltSIGNER_LIST}, {jss::state, ltRIPPLE_STATE}, {jss::ticket, ltTICKET}, {jss::xchain_owned_claim_id, ltXCHAIN_OWNED_CLAIM_ID}, {jss::xchain_owned_create_account_claim_id, - ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, - {jss::mpt_issuance, ltMPTOKEN_ISSUANCE}, - {jss::mptoken, ltMPTOKEN}}}; + ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}}}; auto const& p = params[jss::type]; if (!p.isString()) { result.first = RPC::Status{ rpcINVALID_PARAMS, "Invalid field 'type', not string."}; - assert(result.first.type() == RPC::Status::Type::error_code_i); + XRPL_ASSERT( + result.first.type() == RPC::Status::Type::error_code_i, + "ripple::RPC::chooseLedgerEntryType : first valid result type"); return result; } @@ -978,7 +983,10 @@ chooseLedgerEntryType(Json::Value const& params) { result.first = RPC::Status{rpcINVALID_PARAMS, "Invalid field 'type'."}; - assert(result.first.type() == RPC::Status::Type::error_code_i); + XRPL_ASSERT( + result.first.type() == RPC::Status::Type::error_code_i, + "ripple::RPC::chooseLedgerEntryType : second valid result " + "type"); return result; } result.second = iter->second; @@ -1084,7 +1092,9 @@ getLedgerByContext(RPC::JsonContext& context) // ledger auto const refIndex = getCandidateLedger(ledgerIndex); auto refHash = hashOfSeq(*ledger, refIndex, j); - assert(refHash); + XRPL_ASSERT( + refHash, + "ripple::RPC::getLedgerByContext : nonzero ledger hash"); ledger = ledgerMaster.getLedgerByHash(*refHash); if (!ledger) @@ -1118,7 +1128,9 @@ getLedgerByContext(RPC::JsonContext& context) neededHash = hashOfSeq(*ledger, ledgerIndex, j); } - assert(neededHash); + XRPL_ASSERT( + neededHash, + "ripple::RPC::getLedgerByContext : nonzero needed hash"); ledgerHash = neededHash ? *neededHash : beast::zero; // kludge } diff --git a/src/xrpld/rpc/detail/RPCHelpers.h b/src/xrpld/rpc/detail/RPCHelpers.h index 54c426b17c3..74171af28e3 100644 --- a/src/xrpld/rpc/detail/RPCHelpers.h +++ b/src/xrpld/rpc/detail/RPCHelpers.h @@ -213,7 +213,9 @@ template void setVersion(Object& parent, unsigned int apiVersion, bool betaEnabled) { - assert(apiVersion != apiInvalidVersion); + XRPL_ASSERT( + apiVersion != apiInvalidVersion, + "ripple::RPC::setVersion : input is valid"); auto&& object = addObject(parent, jss::version); if (apiVersion == apiVersionIfUnspecified) { diff --git a/src/xrpld/rpc/detail/Role.cpp b/src/xrpld/rpc/detail/Role.cpp index 5cfe30b26e6..b374f035884 100644 --- a/src/xrpld/rpc/detail/Role.cpp +++ b/src/xrpld/rpc/detail/Role.cpp @@ -28,7 +28,9 @@ namespace ripple { bool passwordUnrequiredOrSentCorrect(Port const& port, Json::Value const& params) { - assert(!(port.admin_nets_v4.empty() && port.admin_nets_v6.empty())); + XRPL_ASSERT( + !(port.admin_nets_v4.empty() && port.admin_nets_v6.empty()), + "ripple::passwordUnrequiredOrSentCorrect : non-empty admin nets"); bool const passwordRequired = (!port.admin_user.empty() || !port.admin_password.empty()); diff --git a/src/xrpld/rpc/detail/Status.cpp b/src/xrpld/rpc/detail/Status.cpp index af212d37f14..7b23c2cc13a 100644 --- a/src/xrpld/rpc/detail/Status.cpp +++ b/src/xrpld/rpc/detail/Status.cpp @@ -36,9 +36,8 @@ Status::codeString() const { std::string s1, s2; - auto success = transResultInfo(toTER(), s1, s2); - assert(success); - (void)success; + [[maybe_unused]] auto const success = transResultInfo(toTER(), s1, s2); + XRPL_ASSERT(success, "ripple::RPC::codeString : valid TER result"); return s1 + ": " + s2; } @@ -51,7 +50,7 @@ Status::codeString() const return sStr.str(); } - assert(false); + UNREACHABLE("ripple::RPC::codeString : invalid type"); return ""; } diff --git a/src/xrpld/rpc/detail/TransactionSign.cpp b/src/xrpld/rpc/detail/TransactionSign.cpp index 2f10387bc81..f7c04e356c3 100644 --- a/src/xrpld/rpc/detail/TransactionSign.cpp +++ b/src/xrpld/rpc/detail/TransactionSign.cpp @@ -1031,7 +1031,9 @@ transactionSignFor( if (!preprocResult.second) return preprocResult.first; - assert(signForParams.validMultiSign()); + XRPL_ASSERT( + signForParams.validMultiSign(), + "ripple::RPC::transactionSignFor : valid multi-signature"); { std::shared_ptr account_state = diff --git a/src/xrpld/rpc/handlers/AMMInfo.cpp b/src/xrpld/rpc/handlers/AMMInfo.cpp index 9d5b20f1d63..1990cdafd3e 100644 --- a/src/xrpld/rpc/handlers/AMMInfo.cpp +++ b/src/xrpld/rpc/handlers/AMMInfo.cpp @@ -147,14 +147,15 @@ doAMMInfo(RPC::JsonContext& context) if (context.apiVersion >= 3 && invalid(params)) return Unexpected(rpcINVALID_PARAMS); - assert( + XRPL_ASSERT( (issue1.has_value() == issue2.has_value()) && - (issue1.has_value() != ammID.has_value())); + (issue1.has_value() != ammID.has_value()), + "ripple::doAMMInfo : issue1 and issue2 do match"); auto const ammKeylet = [&]() { if (issue1 && issue2) return keylet::amm(*issue1, *issue2); - assert(ammID); + XRPL_ASSERT(ammID, "ripple::doAMMInfo::ammKeylet : ammID is set"); return keylet::amm(*ammID); }(); auto const amm = ledger->read(ammKeylet); @@ -162,8 +163,8 @@ doAMMInfo(RPC::JsonContext& context) return Unexpected(rpcACT_NOT_FOUND); if (!issue1 && !issue2) { - issue1 = (*amm)[sfAsset]; - issue2 = (*amm)[sfAsset2]; + issue1 = (*amm)[sfAsset].get(); + issue2 = (*amm)[sfAsset2].get(); } return ValuesFromContextParams{ @@ -213,9 +214,10 @@ doAMMInfo(RPC::JsonContext& context) } if (voteSlots.size() > 0) ammResult[jss::vote_slots] = std::move(voteSlots); - assert( + XRPL_ASSERT( !ledger->rules().enabled(fixInnerObjTemplate) || - amm->isFieldPresent(sfAuctionSlot)); + amm->isFieldPresent(sfAuctionSlot), + "ripple::doAMMInfo : auction slot is set"); if (amm->isFieldPresent(sfAuctionSlot)) { auto const& auctionSlot = diff --git a/src/xrpld/rpc/handlers/AccountChannels.cpp b/src/xrpld/rpc/handlers/AccountChannels.cpp index ad591b04a1c..4b9ff7e43c5 100644 --- a/src/xrpld/rpc/handlers/AccountChannels.cpp +++ b/src/xrpld/rpc/handlers/AccountChannels.cpp @@ -169,7 +169,7 @@ doAccountChannels(RPC::JsonContext& context) std::shared_ptr const& sleCur) { if (!sleCur) { - assert(false); + UNREACHABLE("ripple::doAccountChannels : null SLE"); return false; } diff --git a/src/xrpld/rpc/handlers/AccountInfo.cpp b/src/xrpld/rpc/handlers/AccountInfo.cpp index dab0274e9dd..90e3a8d46e0 100644 --- a/src/xrpld/rpc/handlers/AccountInfo.cpp +++ b/src/xrpld/rpc/handlers/AccountInfo.cpp @@ -214,7 +214,9 @@ doAccountInfo(RPC::JsonContext& context) if (tx.seqProxy.isSeq()) { - assert(prevSeqProxy < tx.seqProxy); + XRPL_ASSERT( + prevSeqProxy < tx.seqProxy, + "rpple::doAccountInfo : first sorted proxy"); prevSeqProxy = tx.seqProxy; jvTx[jss::seq] = tx.seqProxy.value(); ++seqCount; @@ -224,7 +226,9 @@ doAccountInfo(RPC::JsonContext& context) } else { - assert(prevSeqProxy < tx.seqProxy); + XRPL_ASSERT( + prevSeqProxy < tx.seqProxy, + "rpple::doAccountInfo : second sorted proxy"); prevSeqProxy = tx.seqProxy; jvTx[jss::ticket] = tx.seqProxy.value(); ++ticketCount; diff --git a/src/xrpld/rpc/handlers/AccountLines.cpp b/src/xrpld/rpc/handlers/AccountLines.cpp index 64ca95ebe56..e2e6ce19ded 100644 --- a/src/xrpld/rpc/handlers/AccountLines.cpp +++ b/src/xrpld/rpc/handlers/AccountLines.cpp @@ -189,7 +189,7 @@ doAccountLines(RPC::JsonContext& context) std::shared_ptr const& sleCur) { if (!sleCur) { - assert(false); + UNREACHABLE("ripple::doAccountLines : null SLE"); return false; } diff --git a/src/xrpld/rpc/handlers/AccountOffers.cpp b/src/xrpld/rpc/handlers/AccountOffers.cpp index 3c4a4404984..86559a79f4f 100644 --- a/src/xrpld/rpc/handlers/AccountOffers.cpp +++ b/src/xrpld/rpc/handlers/AccountOffers.cpp @@ -145,7 +145,7 @@ doAccountOffers(RPC::JsonContext& context) std::shared_ptr const& sle) { if (!sle) { - assert(false); + UNREACHABLE("ripple::doAccountOffers : null SLE"); return false; } diff --git a/src/xrpld/rpc/handlers/AccountTx.cpp b/src/xrpld/rpc/handlers/AccountTx.cpp index 887694daf21..ae50401b630 100644 --- a/src/xrpld/rpc/handlers/AccountTx.cpp +++ b/src/xrpld/rpc/handlers/AccountTx.cpp @@ -307,7 +307,9 @@ populateJsonResponse( if (auto txnsData = std::get_if(&result.transactions)) { - assert(!args.binary); + XRPL_ASSERT( + !args.binary, + "ripple::populateJsonResponse : binary is not set"); for (auto const& [txn, txnMeta] : *txnsData) { @@ -354,13 +356,16 @@ populateJsonResponse( jvObj[jss::meta], sttx, *txnMeta); } else - assert(false && "Missing transaction medatata"); + UNREACHABLE( + "ripple::populateJsonResponse : missing " + "transaction medatata"); } } } else { - assert(args.binary); + XRPL_ASSERT( + args.binary, "ripple::populateJsonResponse : binary is set"); for (auto const& binaryData : std::get(result.transactions)) diff --git a/src/xrpld/rpc/handlers/Fee1.cpp b/src/xrpld/rpc/handlers/Fee1.cpp index da766fdbb32..de5bdc4f6ca 100644 --- a/src/xrpld/rpc/handlers/Fee1.cpp +++ b/src/xrpld/rpc/handlers/Fee1.cpp @@ -32,7 +32,7 @@ doFee(RPC::JsonContext& context) auto result = context.app.getTxQ().doRPC(context.app); if (result.type() == Json::objectValue) return result; - assert(false); + UNREACHABLE("ripple::doFee : invalid result type"); RPC::inject_error(rpcINTERNAL, context.params); return context.params; } diff --git a/src/xrpld/rpc/handlers/LedgerClosed.cpp b/src/xrpld/rpc/handlers/LedgerClosed.cpp index 9bc9315f648..b5644d9910e 100644 --- a/src/xrpld/rpc/handlers/LedgerClosed.cpp +++ b/src/xrpld/rpc/handlers/LedgerClosed.cpp @@ -29,7 +29,7 @@ Json::Value doLedgerClosed(RPC::JsonContext& context) { auto ledger = context.ledgerMaster.getClosedLedger(); - assert(ledger); + XRPL_ASSERT(ledger, "ripple::doLedgerClosed : non-null closed ledger"); Json::Value jvResult; jvResult[jss::ledger_index] = ledger->info().seq; diff --git a/src/xrpld/rpc/handlers/LedgerDiff.cpp b/src/xrpld/rpc/handlers/LedgerDiff.cpp index 6398be60973..d713f43bfdf 100644 --- a/src/xrpld/rpc/handlers/LedgerDiff.cpp +++ b/src/xrpld/rpc/handlers/LedgerDiff.cpp @@ -73,7 +73,9 @@ doLedgerDiffGrpc( } else { - assert(inDesired->size() > 0); + XRPL_ASSERT( + inDesired->size() > 0, + "ripple::doLedgerDiffGrpc : non-empty desired"); diff->set_key(k.data(), k.size()); if (request.include_blobs()) { diff --git a/src/xrpld/rpc/handlers/LedgerEntry.cpp b/src/xrpld/rpc/handlers/LedgerEntry.cpp index 5d03bbb189d..4401b4dacd0 100644 --- a/src/xrpld/rpc/handlers/LedgerEntry.cpp +++ b/src/xrpld/rpc/handlers/LedgerEntry.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace ripple { @@ -66,814 +67,890 @@ parseAuthorizeCredentials(Json::Value const& jv) return arr; } -// { -// ledger_hash : -// ledger_index : -// ... -// } -Json::Value -doLedgerEntry(RPC::JsonContext& context) +std::optional +parseIndex(Json::Value const& params, Json::Value& jvResult) { - std::shared_ptr lpLedger; - auto jvResult = RPC::lookupLedger(lpLedger, context); + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - if (!lpLedger) - return jvResult; + return uNodeIndex; +} +std::optional +parseAccountRoot(Json::Value const& params, Json::Value& jvResult) +{ + auto const account = parseBase58(params.asString()); + if (!account || account->isZero()) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + return keylet::account(*account).key; +} + +std::optional +parseCheck(Json::Value const& params, Json::Value& jvResult) +{ uint256 uNodeIndex; - bool bNodeBinary = false; - LedgerEntryType expectedType = ltANY; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - try + return uNodeIndex; +} + +std::optional +parseDepositPreauth(Json::Value const& dp, Json::Value& jvResult) +{ + if (!dp.isObject()) { - if (context.params.isMember(jss::index)) + uint256 uNodeIndex; + if (!dp.isString() || !uNodeIndex.parseHex(dp.asString())) { - if (!uNodeIndex.parseHex(context.params[jss::index].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::account_root)) + return uNodeIndex; + } + + // clang-format off + if ( + (!dp.isMember(jss::owner) || !dp[jss::owner].isString()) || + (dp.isMember(jss::authorized) == dp.isMember(jss::authorized_credentials)) || + (dp.isMember(jss::authorized) && !dp[jss::authorized].isString()) || + (dp.isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].isArray()) + ) + // clang-format on + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const owner = parseBase58(dp[jss::owner].asString()); + if (!owner) + { + jvResult[jss::error] = "malformedOwner"; + return std::nullopt; + } + + if (dp.isMember(jss::authorized)) + { + auto const authorized = + parseBase58(dp[jss::authorized].asString()); + if (!authorized) { - expectedType = ltACCOUNT_ROOT; - auto const account = parseBase58( - context.params[jss::account_root].asString()); - if (!account || account->isZero()) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = keylet::account(*account).key; + jvResult[jss::error] = "malformedAuthorized"; + return std::nullopt; } - else if (context.params.isMember(jss::check)) + return keylet::depositPreauth(*owner, *authorized).key; + } + + auto const& ac(dp[jss::authorized_credentials]); + STArray const arr = parseAuthorizeCredentials(ac); + + if (arr.empty() || (arr.size() > maxCredentialsArraySize)) + { + jvResult[jss::error] = "malformedAuthorizedCredentials"; + return std::nullopt; + } + + auto const& sorted = credentials::makeSorted(arr); + if (sorted.empty()) + { + jvResult[jss::error] = "malformedAuthorizedCredentials"; + return std::nullopt; + } + + return keylet::depositPreauth(*owner, sorted).key; +} + +std::optional +parseDirectory(Json::Value const& params, Json::Value& jvResult) +{ + if (params.isNull()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltCHECK; - if (!uNodeIndex.parseHex(context.params[jss::check].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::deposit_preauth)) - { - expectedType = ltDEPOSIT_PREAUTH; - auto const& dp = context.params[jss::deposit_preauth]; + return uNodeIndex; + } - if (!dp.isObject()) - { - if (!dp.isString() || !uNodeIndex.parseHex(dp.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - // clang-format off - else if ( - (!dp.isMember(jss::owner) || !dp[jss::owner].isString()) || - (dp.isMember(jss::authorized) == dp.isMember(jss::authorized_credentials)) || - (dp.isMember(jss::authorized) && !dp[jss::authorized].isString()) || - (dp.isMember(jss::authorized_credentials) && !dp[jss::authorized_credentials].isArray()) - ) - // clang-format on - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const owner = - parseBase58(dp[jss::owner].asString()); - if (!owner) - { - jvResult[jss::error] = "malformedOwner"; - } - else if (dp.isMember(jss::authorized)) - { - auto const authorized = - parseBase58(dp[jss::authorized].asString()); - if (!authorized) - jvResult[jss::error] = "malformedAuthorized"; - else - uNodeIndex = - keylet::depositPreauth(*owner, *authorized).key; - } - else - { - auto const& ac(dp[jss::authorized_credentials]); - STArray const arr = parseAuthorizeCredentials(ac); - - if (arr.empty() || (arr.size() > maxCredentialsArraySize)) - jvResult[jss::error] = "malformedAuthorizedCredentials"; - else - { - auto sorted = credentials::makeSorted(arr); - if (sorted.empty()) - jvResult[jss::error] = - "malformedAuthorizedCredentials"; - else - uNodeIndex = - keylet::depositPreauth(*owner, sorted).key; - } - } - } - } - else if (context.params.isMember(jss::directory)) + if (params.isMember(jss::sub_index) && !params[jss::sub_index].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + std::uint64_t uSubIndex = + params.isMember(jss::sub_index) ? params[jss::sub_index].asUInt() : 0; + + if (params.isMember(jss::dir_root)) + { + uint256 uDirRoot; + + if (params.isMember(jss::owner)) { - expectedType = ltDIR_NODE; - if (context.params[jss::directory].isNull()) - { - jvResult[jss::error] = "malformedRequest"; - } - else if (!context.params[jss::directory].isObject()) - { - if (!uNodeIndex.parseHex( - context.params[jss::directory].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - context.params[jss::directory].isMember(jss::sub_index) && - !context.params[jss::directory][jss::sub_index].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - std::uint64_t uSubIndex = - context.params[jss::directory].isMember(jss::sub_index) - ? context.params[jss::directory][jss::sub_index].asUInt() - : 0; + // May not specify both dir_root and owner. + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - if (context.params[jss::directory].isMember(jss::dir_root)) - { - uint256 uDirRoot; - - if (context.params[jss::directory].isMember(jss::owner)) - { - // May not specify both dir_root and owner. - jvResult[jss::error] = "malformedRequest"; - } - else if (!uDirRoot.parseHex( - context.params[jss::directory][jss::dir_root] - .asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - else - { - uNodeIndex = keylet::page(uDirRoot, uSubIndex).key; - } - } - else if (context.params[jss::directory].isMember(jss::owner)) - { - auto const ownerID = parseBase58( - context.params[jss::directory][jss::owner].asString()); - - if (!ownerID) - { - jvResult[jss::error] = "malformedAddress"; - } - else - { - uNodeIndex = - keylet::page(keylet::ownerDir(*ownerID), uSubIndex) - .key; - } - } - else - { - jvResult[jss::error] = "malformedRequest"; - } - } + if (!uDirRoot.parseHex(params[jss::dir_root].asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::escrow)) + return keylet::page(uDirRoot, uSubIndex).key; + } + + if (params.isMember(jss::owner)) + { + auto const ownerID = + parseBase58(params[jss::owner].asString()); + + if (!ownerID) { - expectedType = ltESCROW; - if (!context.params[jss::escrow].isObject()) - { - if (!uNodeIndex.parseHex( - context.params[jss::escrow].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::escrow].isMember(jss::owner) || - !context.params[jss::escrow].isMember(jss::seq) || - !context.params[jss::escrow][jss::seq].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const id = parseBase58( - context.params[jss::escrow][jss::owner].asString()); - if (!id) - jvResult[jss::error] = "malformedOwner"; - else - uNodeIndex = - keylet::escrow( - *id, context.params[jss::escrow][jss::seq].asUInt()) - .key; - } + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; } - else if (context.params.isMember(jss::offer)) + + return keylet::page(keylet::ownerDir(*ownerID), uSubIndex).key; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseEscrow(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltOFFER; - if (!context.params[jss::offer].isObject()) - { - if (!uNodeIndex.parseHex(context.params[jss::offer].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::offer].isMember(jss::account) || - !context.params[jss::offer].isMember(jss::seq) || - !context.params[jss::offer][jss::seq].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const id = parseBase58( - context.params[jss::offer][jss::account].asString()); - if (!id) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = - keylet::offer( - *id, context.params[jss::offer][jss::seq].asUInt()) - .key; - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::payment_channel)) + + return uNodeIndex; + } + + if (!params.isMember(jss::owner) || !params.isMember(jss::seq) || + !params[jss::seq].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id = parseBase58(params[jss::owner].asString()); + + if (!id) + { + jvResult[jss::error] = "malformedOwner"; + return std::nullopt; + } + + return keylet::escrow(*id, params[jss::seq].asUInt()).key; +} + +std::optional +parseOffer(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltPAYCHAN; + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + return uNodeIndex; + } - if (!uNodeIndex.parseHex( - context.params[jss::payment_channel].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + if (!params.isMember(jss::account) || !params.isMember(jss::seq) || + !params[jss::seq].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id = parseBase58(params[jss::account].asString()); + if (!id) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + return keylet::offer(*id, params[jss::seq].asUInt()).key; +} + +std::optional +parsePaymentChannel(Json::Value const& params, Json::Value& jvResult) +{ + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + return uNodeIndex; +} + +std::optional +parseRippleState(Json::Value const& jvRippleState, Json::Value& jvResult) +{ + Currency uCurrency; + + if (!jvRippleState.isObject() || !jvRippleState.isMember(jss::currency) || + !jvRippleState.isMember(jss::accounts) || + !jvRippleState[jss::accounts].isArray() || + 2 != jvRippleState[jss::accounts].size() || + !jvRippleState[jss::accounts][0u].isString() || + !jvRippleState[jss::accounts][1u].isString() || + (jvRippleState[jss::accounts][0u].asString() == + jvRippleState[jss::accounts][1u].asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id1 = + parseBase58(jvRippleState[jss::accounts][0u].asString()); + auto const id2 = + parseBase58(jvRippleState[jss::accounts][1u].asString()); + if (!id1 || !id2) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + if (!to_currency(uCurrency, jvRippleState[jss::currency].asString())) + { + jvResult[jss::error] = "malformedCurrency"; + return std::nullopt; + } + + return keylet::line(*id1, *id2, uCurrency).key; +} + +std::optional +parseTicket(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::ripple_state)) + return uNodeIndex; + } + + if (!params.isMember(jss::account) || !params.isMember(jss::ticket_seq) || + !params[jss::ticket_seq].isIntegral()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const id = parseBase58(params[jss::account].asString()); + if (!id) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + return getTicketIndex(*id, params[jss::ticket_seq].asUInt()); +} + +std::optional +parseNFTokenPage(Json::Value const& params, Json::Value& jvResult) +{ + if (params.isString()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltRIPPLE_STATE; - Currency uCurrency; - Json::Value jvRippleState = context.params[jss::ripple_state]; - - if (!jvRippleState.isObject() || - !jvRippleState.isMember(jss::currency) || - !jvRippleState.isMember(jss::accounts) || - !jvRippleState[jss::accounts].isArray() || - 2 != jvRippleState[jss::accounts].size() || - !jvRippleState[jss::accounts][0u].isString() || - !jvRippleState[jss::accounts][1u].isString() || - (jvRippleState[jss::accounts][0u].asString() == - jvRippleState[jss::accounts][1u].asString())) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const id1 = parseBase58( - jvRippleState[jss::accounts][0u].asString()); - auto const id2 = parseBase58( - jvRippleState[jss::accounts][1u].asString()); - if (!id1 || !id2) - { - jvResult[jss::error] = "malformedAddress"; - } - else if (!to_currency( - uCurrency, - jvRippleState[jss::currency].asString())) - { - jvResult[jss::error] = "malformedCurrency"; - } - else - { - uNodeIndex = keylet::line(*id1, *id2, uCurrency).key; - } - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::ticket)) + return uNodeIndex; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseAMM(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) { - expectedType = ltTICKET; - if (!context.params[jss::ticket].isObject()) - { - if (!uNodeIndex.parseHex( - context.params[jss::ticket].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::ticket].isMember(jss::account) || - !context.params[jss::ticket].isMember(jss::ticket_seq) || - !context.params[jss::ticket][jss::ticket_seq].isIntegral()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const id = parseBase58( - context.params[jss::ticket][jss::account].asString()); - if (!id) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = getTicketIndex( - *id, - context.params[jss::ticket][jss::ticket_seq].asUInt()); - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::nft_page)) + return uNodeIndex; + } + + if (!params.isMember(jss::asset) || !params.isMember(jss::asset2)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + try + { + auto const issue = issueFromJson(params[jss::asset]); + auto const issue2 = issueFromJson(params[jss::asset2]); + return keylet::amm(issue, issue2).key; + } + catch (std::runtime_error const&) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } +} + +std::optional +parseBridge(Json::Value const& params, Json::Value& jvResult) +{ + // return the keylet for the specified bridge or nullopt if the + // request is malformed + auto const maybeKeylet = [&]() -> std::optional { + try { - expectedType = ltNFTOKEN_PAGE; + if (!params.isMember(jss::bridge_account)) + return std::nullopt; - if (context.params[jss::nft_page].isString()) + auto const& jsBridgeAccount = params[jss::bridge_account]; + if (!jsBridgeAccount.isString()) { - if (!uNodeIndex.parseHex( - context.params[jss::nft_page].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + return std::nullopt; } - else + + auto const account = + parseBase58(jsBridgeAccount.asString()); + if (!account || account->isZero()) { - jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } + + // This may throw and is the reason for the `try` block. The + // try block has a larger scope so the `bridge` variable + // doesn't need to be an optional. + STXChainBridge const bridge(params[jss::bridge]); + STXChainBridge::ChainType const chainType = + STXChainBridge::srcChain(account == bridge.lockingChainDoor()); + + if (account != bridge.door(chainType)) + return std::nullopt; + + return keylet::bridge(bridge, chainType); } - else if (context.params.isMember(jss::amm)) + catch (...) { - expectedType = ltAMM; - if (!context.params[jss::amm].isObject()) - { - if (!uNodeIndex.parseHex(context.params[jss::amm].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::amm].isMember(jss::asset) || - !context.params[jss::amm].isMember(jss::asset2)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - try - { - auto const issue = - issueFromJson(context.params[jss::amm][jss::asset]); - auto const issue2 = - issueFromJson(context.params[jss::amm][jss::asset2]); - uNodeIndex = keylet::amm(issue, issue2).key; - } - catch (std::runtime_error const&) - { - jvResult[jss::error] = "malformedRequest"; - } - } + return std::nullopt; } - else if (context.params.isMember(jss::bridge)) + }(); + + if (maybeKeylet) + { + return maybeKeylet->key; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseXChainOwnedClaimID(Json::Value const& claim_id, Json::Value& jvResult) +{ + if (claim_id.isString()) + { + uint256 uNodeIndex; + // we accept a node id as specifier of a xchain claim id + if (!uNodeIndex.parseHex(claim_id.asString())) { - expectedType = ltBRIDGE; + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + return uNodeIndex; + } - // return the keylet for the specified bridge or nullopt if the - // request is malformed - auto const maybeKeylet = [&]() -> std::optional { - try - { - if (!context.params.isMember(jss::bridge_account)) - return std::nullopt; - - auto const& jsBridgeAccount = - context.params[jss::bridge_account]; - if (!jsBridgeAccount.isString()) - { - return std::nullopt; - } - auto const account = - parseBase58(jsBridgeAccount.asString()); - if (!account || account->isZero()) - { - return std::nullopt; - } - - // This may throw and is the reason for the `try` block. The - // try block has a larger scope so the `bridge` variable - // doesn't need to be an optional. - STXChainBridge const bridge(context.params[jss::bridge]); - STXChainBridge::ChainType const chainType = - STXChainBridge::srcChain( - account == bridge.lockingChainDoor()); - if (account != bridge.door(chainType)) - return std::nullopt; - - return keylet::bridge(bridge, chainType); - } - catch (...) - { - return std::nullopt; - } - }(); + if (!claim_id.isObject() || + !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) && + claim_id[sfIssuingChainDoor.getJsonName()].isString()) || + !(claim_id.isMember(sfLockingChainDoor.getJsonName()) && + claim_id[sfLockingChainDoor.getJsonName()].isString()) || + !claim_id.isMember(sfIssuingChainIssue.getJsonName()) || + !claim_id.isMember(sfLockingChainIssue.getJsonName()) || + !claim_id.isMember(jss::xchain_owned_claim_id)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - if (maybeKeylet) - { - uNodeIndex = maybeKeylet->key; - } - else - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } + // if not specified with a node id, a claim_id is specified by + // four strings defining the bridge (locking_chain_door, + // locking_chain_issue, issuing_chain_door, issuing_chain_issue) + // and the claim id sequence number. + auto const lockingChainDoor = parseBase58( + claim_id[sfLockingChainDoor.getJsonName()].asString()); + auto const issuingChainDoor = parseBase58( + claim_id[sfIssuingChainDoor.getJsonName()].asString()); + Issue lockingChainIssue, issuingChainIssue; + bool valid = lockingChainDoor && issuingChainDoor; + + if (valid) + { + try + { + lockingChainIssue = + issueFromJson(claim_id[sfLockingChainIssue.getJsonName()]); + issuingChainIssue = + issueFromJson(claim_id[sfIssuingChainIssue.getJsonName()]); } - else if (context.params.isMember(jss::xchain_owned_claim_id)) + catch (std::runtime_error const& ex) { - expectedType = ltXCHAIN_OWNED_CLAIM_ID; - auto& claim_id = context.params[jss::xchain_owned_claim_id]; - if (claim_id.isString()) - { - // we accept a node id as specifier of a xchain claim id - if (!uNodeIndex.parseHex(claim_id.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !claim_id.isObject() || - !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) && - claim_id[sfIssuingChainDoor.getJsonName()].isString()) || - !(claim_id.isMember(sfLockingChainDoor.getJsonName()) && - claim_id[sfLockingChainDoor.getJsonName()].isString()) || - !claim_id.isMember(sfIssuingChainIssue.getJsonName()) || - !claim_id.isMember(sfLockingChainIssue.getJsonName()) || - !claim_id.isMember(jss::xchain_owned_claim_id)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - // if not specified with a node id, a claim_id is specified by - // four strings defining the bridge (locking_chain_door, - // locking_chain_issue, issuing_chain_door, issuing_chain_issue) - // and the claim id sequence number. - auto lockingChainDoor = parseBase58( - claim_id[sfLockingChainDoor.getJsonName()].asString()); - auto issuingChainDoor = parseBase58( - claim_id[sfIssuingChainDoor.getJsonName()].asString()); - Issue lockingChainIssue, issuingChainIssue; - bool valid = lockingChainDoor && issuingChainDoor; - if (valid) - { - try - { - lockingChainIssue = issueFromJson( - claim_id[sfLockingChainIssue.getJsonName()]); - issuingChainIssue = issueFromJson( - claim_id[sfIssuingChainIssue.getJsonName()]); - } - catch (std::runtime_error const& ex) - { - valid = false; - jvResult[jss::error] = "malformedRequest"; - } - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + } - if (valid && claim_id[jss::xchain_owned_claim_id].isIntegral()) - { - auto seq = claim_id[jss::xchain_owned_claim_id].asUInt(); - - STXChainBridge bridge_spec( - *lockingChainDoor, - lockingChainIssue, - *issuingChainDoor, - issuingChainIssue); - Keylet keylet = keylet::xChainClaimID(bridge_spec, seq); - uNodeIndex = keylet.key; - } - } + if (valid && claim_id[jss::xchain_owned_claim_id].isIntegral()) + { + auto const seq = claim_id[jss::xchain_owned_claim_id].asUInt(); + + STXChainBridge bridge_spec( + *lockingChainDoor, + lockingChainIssue, + *issuingChainDoor, + issuingChainIssue); + Keylet keylet = keylet::xChainClaimID(bridge_spec, seq); + return keylet.key; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseXChainOwnedCreateAccountClaimID( + Json::Value const& claim_id, + Json::Value& jvResult) +{ + if (claim_id.isString()) + { + uint256 uNodeIndex; + // we accept a node id as specifier of a xchain create account + // claim_id + if (!uNodeIndex.parseHex(claim_id.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember( - jss::xchain_owned_create_account_claim_id)) + return uNodeIndex; + } + + if (!claim_id.isObject() || + !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) && + claim_id[sfIssuingChainDoor.getJsonName()].isString()) || + !(claim_id.isMember(sfLockingChainDoor.getJsonName()) && + claim_id[sfLockingChainDoor.getJsonName()].isString()) || + !claim_id.isMember(sfIssuingChainIssue.getJsonName()) || + !claim_id.isMember(sfLockingChainIssue.getJsonName()) || + !claim_id.isMember(jss::xchain_owned_create_account_claim_id)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + // if not specified with a node id, a create account claim_id is + // specified by four strings defining the bridge + // (locking_chain_door, locking_chain_issue, issuing_chain_door, + // issuing_chain_issue) and the create account claim id sequence + // number. + auto const lockingChainDoor = parseBase58( + claim_id[sfLockingChainDoor.getJsonName()].asString()); + auto const issuingChainDoor = parseBase58( + claim_id[sfIssuingChainDoor.getJsonName()].asString()); + Issue lockingChainIssue, issuingChainIssue; + bool valid = lockingChainDoor && issuingChainDoor; + if (valid) + { + try { - // see object definition in LedgerFormats.cpp - expectedType = ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID; - auto& claim_id = - context.params[jss::xchain_owned_create_account_claim_id]; - if (claim_id.isString()) - { - // we accept a node id as specifier of a xchain create account - // claim_id - if (!uNodeIndex.parseHex(claim_id.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !claim_id.isObject() || - !(claim_id.isMember(sfIssuingChainDoor.getJsonName()) && - claim_id[sfIssuingChainDoor.getJsonName()].isString()) || - !(claim_id.isMember(sfLockingChainDoor.getJsonName()) && - claim_id[sfLockingChainDoor.getJsonName()].isString()) || - !claim_id.isMember(sfIssuingChainIssue.getJsonName()) || - !claim_id.isMember(sfLockingChainIssue.getJsonName()) || - !claim_id.isMember(jss::xchain_owned_create_account_claim_id)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - // if not specified with a node id, a create account claim_id is - // specified by four strings defining the bridge - // (locking_chain_door, locking_chain_issue, issuing_chain_door, - // issuing_chain_issue) and the create account claim id sequence - // number. - auto lockingChainDoor = parseBase58( - claim_id[sfLockingChainDoor.getJsonName()].asString()); - auto issuingChainDoor = parseBase58( - claim_id[sfIssuingChainDoor.getJsonName()].asString()); - Issue lockingChainIssue, issuingChainIssue; - bool valid = lockingChainDoor && issuingChainDoor; - if (valid) - { - try - { - lockingChainIssue = issueFromJson( - claim_id[sfLockingChainIssue.getJsonName()]); - issuingChainIssue = issueFromJson( - claim_id[sfIssuingChainIssue.getJsonName()]); - } - catch (std::runtime_error const& ex) - { - valid = false; - jvResult[jss::error] = "malformedRequest"; - } - } + lockingChainIssue = + issueFromJson(claim_id[sfLockingChainIssue.getJsonName()]); + issuingChainIssue = + issueFromJson(claim_id[sfIssuingChainIssue.getJsonName()]); + } + catch (std::runtime_error const& ex) + { + valid = false; + jvResult[jss::error] = "malformedRequest"; + } + } - if (valid && - claim_id[jss::xchain_owned_create_account_claim_id] - .isIntegral()) - { - auto seq = - claim_id[jss::xchain_owned_create_account_claim_id] - .asUInt(); - - STXChainBridge bridge_spec( - *lockingChainDoor, - lockingChainIssue, - *issuingChainDoor, - issuingChainIssue); - Keylet keylet = - keylet::xChainCreateAccountClaimID(bridge_spec, seq); - uNodeIndex = keylet.key; - } - } + if (valid && + claim_id[jss::xchain_owned_create_account_claim_id].isIntegral()) + { + auto const seq = + claim_id[jss::xchain_owned_create_account_claim_id].asUInt(); + + STXChainBridge bridge_spec( + *lockingChainDoor, + lockingChainIssue, + *issuingChainDoor, + issuingChainIssue); + Keylet keylet = keylet::xChainCreateAccountClaimID(bridge_spec, seq); + return keylet.key; + } + + return std::nullopt; +} + +std::optional +parseDID(Json::Value const& params, Json::Value& jvResult) +{ + auto const account = parseBase58(params.asString()); + if (!account || account->isZero()) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + return keylet::did(*account).key; +} + +std::optional +parseOracle(Json::Value const& params, Json::Value& jvResult) +{ + if (!params.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(params.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::did)) + return uNodeIndex; + } + + if (!params.isMember(jss::oracle_document_id) || + !params.isMember(jss::account)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const& oracle = params; + auto const documentID = [&]() -> std::optional { + auto const id = oracle[jss::oracle_document_id]; + if (id.isUInt() || (id.isInt() && id.asInt() >= 0)) + return std::make_optional(id.asUInt()); + + if (id.isString()) { - expectedType = ltDID; - auto const account = - parseBase58(context.params[jss::did].asString()); - if (!account || account->isZero()) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = keylet::did(*account).key; + std::uint32_t v; + if (beast::lexicalCastChecked(v, id.asString())) + return std::make_optional(v); } - else if (context.params.isMember(jss::oracle)) + + return std::nullopt; + }(); + + auto const account = + parseBase58(oracle[jss::account].asString()); + if (!account || account->isZero()) + { + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; + } + + if (!documentID) + { + jvResult[jss::error] = "malformedDocumentID"; + return std::nullopt; + } + + return keylet::oracle(*account, *documentID).key; +} + +std::optional +parseCredential(Json::Value const& cred, Json::Value& jvResult) +{ + if (cred.isString()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(cred.asString())) { - expectedType = ltORACLE; - if (!context.params[jss::oracle].isObject()) - { - if (!uNodeIndex.parseHex( - context.params[jss::oracle].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !context.params[jss::oracle].isMember( - jss::oracle_document_id) || - !context.params[jss::oracle].isMember(jss::account)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - uNodeIndex = beast::zero; - auto const& oracle = context.params[jss::oracle]; - auto const documentID = [&]() -> std::optional { - auto const& id = oracle[jss::oracle_document_id]; - if (id.isUInt() || (id.isInt() && id.asInt() >= 0)) - return std::make_optional(id.asUInt()); - else if (id.isString()) - { - std::uint32_t v; - if (beast::lexicalCastChecked(v, id.asString())) - return std::make_optional(v); - } - return std::nullopt; - }(); - auto const account = - parseBase58(oracle[jss::account].asString()); - if (!account || account->isZero()) - jvResult[jss::error] = "malformedAddress"; - else if (!documentID) - jvResult[jss::error] = "malformedDocumentID"; - else - uNodeIndex = keylet::oracle(*account, *documentID).key; - } + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::credential)) + return uNodeIndex; + } + + if ((!cred.isMember(jss::subject) || !cred[jss::subject].isString()) || + (!cred.isMember(jss::issuer) || !cred[jss::issuer].isString()) || + (!cred.isMember(jss::credential_type) || + !cred[jss::credential_type].isString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + auto const subject = parseBase58(cred[jss::subject].asString()); + auto const issuer = parseBase58(cred[jss::issuer].asString()); + auto const credType = strUnHex(cred[jss::credential_type].asString()); + + if (!subject || subject->isZero() || !issuer || issuer->isZero() || + !credType || credType->empty()) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + return keylet::credential( + *subject, *issuer, Slice(credType->data(), credType->size())) + .key; +} + +std::optional +parseMPTokenIssuance( + Json::Value const& unparsedMPTIssuanceID, + Json::Value& jvResult) +{ + if (unparsedMPTIssuanceID.isString()) + { + uint192 mptIssuanceID; + if (!mptIssuanceID.parseHex(unparsedMPTIssuanceID.asString())) { - expectedType = ltCREDENTIAL; - auto const& cred = context.params[jss::credential]; + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } - if (cred.isString()) - { - if (!uNodeIndex.parseHex(cred.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - (!cred.isMember(jss::subject) || - !cred[jss::subject].isString()) || - (!cred.isMember(jss::issuer) || - !cred[jss::issuer].isString()) || - (!cred.isMember(jss::credential_type) || - !cred[jss::credential_type].isString())) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - auto const subject = - parseBase58(cred[jss::subject].asString()); - auto const issuer = - parseBase58(cred[jss::issuer].asString()); - auto const credType = - strUnHex(cred[jss::credential_type].asString()); - if (!subject || subject->isZero() || !issuer || - issuer->isZero() || !credType || credType->empty()) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - uNodeIndex = keylet::credential( - *subject, - *issuer, - Slice(credType->data(), credType->size())) - .key; - } - } + return keylet::mptIssuance(mptIssuanceID).key; + } + + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; +} + +std::optional +parseMPToken(Json::Value const& mptJson, Json::Value& jvResult) +{ + if (!mptJson.isObject()) + { + uint256 uNodeIndex; + if (!uNodeIndex.parseHex(mptJson.asString())) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; } - else if (context.params.isMember(jss::mpt_issuance)) + return uNodeIndex; + } + + if (!mptJson.isMember(jss::mpt_issuance_id) || + !mptJson.isMember(jss::account)) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } + + try + { + auto const mptIssuanceIdStr = mptJson[jss::mpt_issuance_id].asString(); + + uint192 mptIssuanceID; + if (!mptIssuanceID.parseHex(mptIssuanceIdStr)) + Throw("Cannot parse mpt_issuance_id"); + + auto const account = + parseBase58(mptJson[jss::account].asString()); + + if (!account || account->isZero()) { - expectedType = ltMPTOKEN_ISSUANCE; - auto const unparsedMPTIssuanceID = - context.params[jss::mpt_issuance]; - if (unparsedMPTIssuanceID.isString()) - { - uint192 mptIssuanceID; - if (!mptIssuanceID.parseHex(unparsedMPTIssuanceID.asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - else - uNodeIndex = keylet::mptIssuance(mptIssuanceID).key; - } - else - { - jvResult[jss::error] = "malformedRequest"; - } + jvResult[jss::error] = "malformedAddress"; + return std::nullopt; } - else if (context.params.isMember(jss::mptoken)) + + return keylet::mptoken(mptIssuanceID, *account).key; + } + catch (std::runtime_error const&) + { + jvResult[jss::error] = "malformedRequest"; + return std::nullopt; + } +} + +using FunctionType = + std::optional (*)(Json::Value const&, Json::Value&); + +struct LedgerEntry +{ + Json::StaticString fieldName; + FunctionType parseFunction; + LedgerEntryType expectedType; +}; + +// { +// ledger_hash : +// ledger_index : +// ... +// } +Json::Value +doLedgerEntry(RPC::JsonContext& context) +{ + std::shared_ptr lpLedger; + auto jvResult = RPC::lookupLedger(lpLedger, context); + + if (!lpLedger) + return jvResult; + + static auto ledgerEntryParsers = std::to_array({ + {jss::index, parseIndex, ltANY}, + {jss::account_root, parseAccountRoot, ltACCOUNT_ROOT}, + // TODO: add amendments + {jss::amm, parseAMM, ltAMM}, + {jss::bridge, parseBridge, ltBRIDGE}, + {jss::check, parseCheck, ltCHECK}, + {jss::credential, parseCredential, ltCREDENTIAL}, + {jss::deposit_preauth, parseDepositPreauth, ltDEPOSIT_PREAUTH}, + {jss::did, parseDID, ltDID}, + {jss::directory, parseDirectory, ltDIR_NODE}, + {jss::escrow, parseEscrow, ltESCROW}, + // TODO: add fee, hashes + {jss::mpt_issuance, parseMPTokenIssuance, ltMPTOKEN_ISSUANCE}, + {jss::mptoken, parseMPToken, ltMPTOKEN}, + // TODO: add NFT Offers + {jss::nft_page, parseNFTokenPage, ltNFTOKEN_PAGE}, + // TODO: add NegativeUNL + {jss::offer, parseOffer, ltOFFER}, + {jss::oracle, parseOracle, ltORACLE}, + {jss::payment_channel, parsePaymentChannel, ltPAYCHAN}, + {jss::ripple_state, parseRippleState, ltRIPPLE_STATE}, + // This is an alias, since the `ledger_data` filter uses jss::state + {jss::state, parseRippleState, ltRIPPLE_STATE}, + {jss::ticket, parseTicket, ltTICKET}, + {jss::xchain_owned_claim_id, + parseXChainOwnedClaimID, + ltXCHAIN_OWNED_CLAIM_ID}, + {jss::xchain_owned_create_account_claim_id, + parseXChainOwnedCreateAccountClaimID, + ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID}, + }); + + uint256 uNodeIndex; + LedgerEntryType expectedType = ltANY; + + try + { + bool found = false; + for (const auto& ledgerEntry : ledgerEntryParsers) { - expectedType = ltMPTOKEN; - auto const& mptJson = context.params[jss::mptoken]; - if (!mptJson.isObject()) + if (context.params.isMember(ledgerEntry.fieldName)) { - if (!uNodeIndex.parseHex(mptJson.asString())) + expectedType = ledgerEntry.expectedType; + // `Bridge` is the only type that involves two fields at the + // `ledger_entry` param level. + // So that parser needs to have the whole `params` field. + // All other parsers only need the one field name's info. + Json::Value const& params = ledgerEntry.fieldName == jss::bridge + ? context.params + : context.params[ledgerEntry.fieldName]; + uNodeIndex = ledgerEntry.parseFunction(params, jvResult) + .value_or(beast::zero); + if (jvResult.isMember(jss::error)) { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } - else if ( - !mptJson.isMember(jss::mpt_issuance_id) || - !mptJson.isMember(jss::account)) - { - jvResult[jss::error] = "malformedRequest"; - } - else - { - try - { - auto const mptIssuanceIdStr = - mptJson[jss::mpt_issuance_id].asString(); - - uint192 mptIssuanceID; - if (!mptIssuanceID.parseHex(mptIssuanceIdStr)) - Throw( - "Cannot parse mpt_issuance_id"); - - auto const account = parseBase58( - mptJson[jss::account].asString()); - - if (!account || account->isZero()) - jvResult[jss::error] = "malformedAddress"; - else - uNodeIndex = - keylet::mptoken(mptIssuanceID, *account).key; - } - catch (std::runtime_error const&) - { - jvResult[jss::error] = "malformedRequest"; + return jvResult; } + found = true; + break; } } - else + if (!found) { - if (context.params.isMember("params") && - context.params["params"].isArray() && - context.params["params"].size() == 1 && - context.params["params"][0u].isString()) - { - if (!uNodeIndex.parseHex( - context.params["params"][0u].asString())) - { - uNodeIndex = beast::zero; - jvResult[jss::error] = "malformedRequest"; - } - } + if (context.apiVersion < 2u) + jvResult[jss::error] = "unknownOption"; else - { - if (context.apiVersion < 2u) - jvResult[jss::error] = "unknownOption"; - else - jvResult[jss::error] = "invalidParams"; - } + jvResult[jss::error] = "invalidParams"; + return jvResult; } } catch (Json::error& e) { if (context.apiVersion > 1u) { - // For apiVersion 2 onwards, any parsing failures that throw - // this + // For apiVersion 2 onwards, any parsing failures that throw this // exception return an invalidParam error. - uNodeIndex = beast::zero; jvResult[jss::error] = "invalidParams"; + return jvResult; } else throw; } - if (uNodeIndex.isNonZero()) + if (uNodeIndex.isZero()) { - auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex)); - if (context.params.isMember(jss::binary)) - bNodeBinary = context.params[jss::binary].asBool(); + jvResult[jss::error] = "entryNotFound"; + return jvResult; + } - if (!sleNode) - { - // Not found. - jvResult[jss::error] = "entryNotFound"; - } - else if ( - (expectedType != ltANY) && (expectedType != sleNode->getType())) - { - jvResult[jss::error] = "unexpectedLedgerType"; - } - else if (bNodeBinary) - { - Serializer s; + auto const sleNode = lpLedger->read(keylet::unchecked(uNodeIndex)); - sleNode->add(s); + bool bNodeBinary = false; + if (context.params.isMember(jss::binary)) + bNodeBinary = context.params[jss::binary].asBool(); - jvResult[jss::node_binary] = strHex(s.peekData()); - jvResult[jss::index] = to_string(uNodeIndex); - } - else - { - jvResult[jss::node] = sleNode->getJson(JsonOptions::none); - jvResult[jss::index] = to_string(uNodeIndex); - } + if (!sleNode) + { + // Not found. + jvResult[jss::error] = "entryNotFound"; + return jvResult; + } + + if ((expectedType != ltANY) && (expectedType != sleNode->getType())) + { + jvResult[jss::error] = "unexpectedLedgerType"; + return jvResult; + } + + if (bNodeBinary) + { + Serializer s; + + sleNode->add(s); + + jvResult[jss::node_binary] = strHex(s.peekData()); + jvResult[jss::index] = to_string(uNodeIndex); + } + else + { + jvResult[jss::node] = sleNode->getJson(JsonOptions::none); + jvResult[jss::index] = to_string(uNodeIndex); } return jvResult; @@ -904,7 +981,7 @@ doLedgerEntryGrpc( return {response, errorStatus}; } - auto key = uint256::fromVoidChecked(request.key()); + auto const key = uint256::fromVoidChecked(request.key()); if (!key) { grpc::Status errorStatus{ diff --git a/src/xrpld/rpc/handlers/LedgerHandler.cpp b/src/xrpld/rpc/handlers/LedgerHandler.cpp index 2bf4fb09f94..b1a8a4b2252 100644 --- a/src/xrpld/rpc/handlers/LedgerHandler.cpp +++ b/src/xrpld/rpc/handlers/LedgerHandler.cpp @@ -135,7 +135,8 @@ doLedgerGrpc(RPC::GRPCContext& context) { for (auto& i : ledger->txs) { - assert(i.first); + XRPL_ASSERT( + i.first, "ripple::doLedgerGrpc : non-null transaction"); if (request.expand()) { auto txn = response.mutable_transactions_list() @@ -211,7 +212,9 @@ doLedgerGrpc(RPC::GRPCContext& context) obj->set_key(k.data(), k.size()); if (inDesired) { - assert(inDesired->size() > 0); + XRPL_ASSERT( + inDesired->size() > 0, + "ripple::doLedgerGrpc : non-empty desired"); obj->set_data(inDesired->data(), inDesired->size()); } if (inBase && inDesired) diff --git a/src/xrpld/rpc/handlers/PayChanClaim.cpp b/src/xrpld/rpc/handlers/PayChanClaim.cpp index 1fecd5f1449..f9c40ee776d 100644 --- a/src/xrpld/rpc/handlers/PayChanClaim.cpp +++ b/src/xrpld/rpc/handlers/PayChanClaim.cpp @@ -58,7 +58,9 @@ doChannelAuthorize(RPC::JsonContext& context) std::optional> const keyPair = RPC::keypairForSignature(params, result, context.apiVersion); - assert(keyPair || RPC::contains_error(result)); + XRPL_ASSERT( + keyPair || RPC::contains_error(result), + "ripple::doChannelAuthorize : valid keyPair or an error"); if (!keyPair || RPC::contains_error(result)) return result; diff --git a/src/xrpld/rpc/handlers/Tx.cpp b/src/xrpld/rpc/handlers/Tx.cpp index 98af3a809bf..b603e3945a2 100644 --- a/src/xrpld/rpc/handlers/Tx.cpp +++ b/src/xrpld/rpc/handlers/Tx.cpp @@ -251,7 +251,8 @@ populateJsonResponse( // populate binary metadata if (auto blob = std::get_if(&result.meta)) { - assert(args.binary); + XRPL_ASSERT( + args.binary, "ripple::populateJsonResponse : binary is set"); auto json_meta = (context.apiVersion > 1 ? jss::meta_blob : jss::meta); response[json_meta] = strHex(makeSlice(*blob)); diff --git a/src/xrpld/shamap/SHAMap.h b/src/xrpld/shamap/SHAMap.h index a47f1c1c2bc..c10f4eb1cb7 100644 --- a/src/xrpld/shamap/SHAMap.h +++ b/src/xrpld/shamap/SHAMap.h @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include @@ -599,7 +599,9 @@ SHAMap::setLedgerSeq(std::uint32_t lseq) inline void SHAMap::setImmutable() { - assert(state_ != SHAMapState::Invalid); + XRPL_ASSERT( + state_ != SHAMapState::Invalid, + "ripple::SHAMap::setImmutable : state is valid"); state_ = SHAMapState::Immutable; } @@ -680,7 +682,9 @@ class SHAMap::const_iterator inline SHAMap::const_iterator::const_iterator(SHAMap const* map) : map_(map) { - assert(map_ != nullptr); + XRPL_ASSERT( + map_, + "ripple::SHAMap::const_iterator::const_iterator : non-null input"); if (auto temp = map_->peekFirstItem(stack_)) item_ = temp->peekItem().get(); @@ -732,7 +736,10 @@ SHAMap::const_iterator::operator++(int) inline bool operator==(SHAMap::const_iterator const& x, SHAMap::const_iterator const& y) { - assert(x.map_ == y.map_); + XRPL_ASSERT( + x.map_ == y.map_, + "ripple::operator==(SHAMap::const_iterator, SHAMap::const_iterator) : " + "inputs map do match"); return x.item_ == y.item_; } diff --git a/src/xrpld/shamap/SHAMapItem.h b/src/xrpld/shamap/SHAMapItem.h index 1a1822456e9..2aba5d5d8eb 100644 --- a/src/xrpld/shamap/SHAMapItem.h +++ b/src/xrpld/shamap/SHAMapItem.h @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include namespace ripple { @@ -159,7 +159,9 @@ intrusive_ptr_release(SHAMapItem const* x) inline boost::intrusive_ptr make_shamapitem(uint256 const& tag, Slice data) { - assert(data.size() <= megabytes(16)); + XRPL_ASSERT( + data.size() <= megabytes(16), + "ripple::make_shamapitem : maximum input size"); std::uint8_t* raw = detail::slabber.allocate(data.size()); diff --git a/src/xrpld/shamap/detail/SHAMap.cpp b/src/xrpld/shamap/detail/SHAMap.cpp index d06ba2a153a..09a546be147 100644 --- a/src/xrpld/shamap/detail/SHAMap.cpp +++ b/src/xrpld/shamap/detail/SHAMap.cpp @@ -101,10 +101,12 @@ SHAMap::dirtyUp( // stack is a path of inner nodes up to, but not including, child // child can be an inner node or a leaf - assert( - (state_ != SHAMapState::Synching) && - (state_ != SHAMapState::Immutable)); - assert(child && (child->cowid() == cowid_)); + XRPL_ASSERT( + (state_ != SHAMapState::Synching) && (state_ != SHAMapState::Immutable), + "ripple::SHAMap::dirtyUp : valid state"); + XRPL_ASSERT( + child && (child->cowid() == cowid_), + "ripple::SHAMap::dirtyUp : valid child input"); while (!stack.empty()) { @@ -112,10 +114,10 @@ SHAMap::dirtyUp( std::dynamic_pointer_cast(stack.top().first); SHAMapNodeID nodeID = stack.top().second; stack.pop(); - assert(node != nullptr); + XRPL_ASSERT(node, "ripple::SHAMap::dirtyUp : non-null node"); int branch = selectBranch(nodeID, target); - assert(branch >= 0); + XRPL_ASSERT(branch >= 0, "ripple::SHAMap::dirtyUp : valid branch"); node = unshareNode(std::move(node), nodeID); node->setChild(branch, std::move(child)); @@ -127,7 +129,9 @@ SHAMap::dirtyUp( SHAMapLeafNode* SHAMap::walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack) const { - assert(stack == nullptr || stack->empty()); + XRPL_ASSERT( + stack == nullptr || stack->empty(), + "ripple::SHAMap::walkTowardsKey : empty stack input"); auto inNode = root_; SHAMapNodeID nodeID; @@ -162,7 +166,7 @@ SHAMap::findKey(uint256 const& id) const std::shared_ptr SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const { - assert(backed_); + XRPL_ASSERT(backed_, "ripple::SHAMap::fetchNodeFromDB : is backed"); auto obj = f_.db().fetchNodeObject(hash.as_uint256(), ledgerSeq_); return finishFetch(hash, obj); } @@ -172,7 +176,7 @@ SHAMap::finishFetch( SHAMapHash const& hash, std::shared_ptr const& object) const { - assert(backed_); + XRPL_ASSERT(backed_, "ripple::SHAMap::finishFetch : is backed"); try { @@ -360,9 +364,14 @@ SHAMap::descend( int branch, SHAMapSyncFilter* filter) const { - assert(parent->isInner()); - assert((branch >= 0) && (branch < branchFactor)); - assert(!parent->isEmptyBranch(branch)); + XRPL_ASSERT( + parent->isInner(), "ripple::SHAMap::descend : valid parent input"); + XRPL_ASSERT( + (branch >= 0) && (branch < branchFactor), + "ripple::SHAMap::descend : valid branch input"); + XRPL_ASSERT( + !parent->isEmptyBranch(branch), + "ripple::SHAMap::descend : parent branch is non-empty"); SHAMapTreeNode* child = parent->getChildPointer(branch); @@ -430,11 +439,15 @@ std::shared_ptr SHAMap::unshareNode(std::shared_ptr node, SHAMapNodeID const& nodeID) { // make sure the node is suitable for the intended operation (copy on write) - assert(node->cowid() <= cowid_); + XRPL_ASSERT( + node->cowid() <= cowid_, + "ripple::SHAMap::unshareNode : node valid for cowid"); if (node->cowid() != cowid_) { // have a CoW - assert(state_ != SHAMapState::Immutable); + XRPL_ASSERT( + state_ != SHAMapState::Immutable, + "ripple::SHAMap::unshareNode : not immutable"); node = std::static_pointer_cast(node->clone(cowid_)); if (nodeID.isRoot()) root_ = node; @@ -467,7 +480,9 @@ SHAMap::belowHelper( if (!inner->isEmptyBranch(i)) { node = descendThrow(inner, i); - assert(!stack.empty()); + XRPL_ASSERT( + !stack.empty(), + "ripple::SHAMap::belowHelper : non-empty stack"); if (node->isLeaf()) { auto n = std::static_pointer_cast(node); @@ -531,7 +546,7 @@ SHAMap::onlyBelow(SHAMapTreeNode* node) const if (!nextNode) { - assert(false); + UNREACHABLE("ripple::SHAMap::onlyBelow : no next node"); return no_item; } @@ -541,14 +556,17 @@ SHAMap::onlyBelow(SHAMapTreeNode* node) const // An inner node must have at least one leaf // below it, unless it's the root_ auto const leaf = static_cast(node); - assert(leaf->peekItem() || (leaf == root_.get())); + XRPL_ASSERT( + leaf->peekItem() || (leaf == root_.get()), + "ripple::SHAMap::onlyBelow : valid inner node"); return leaf->peekItem(); } SHAMapLeafNode const* SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const { - assert(stack.empty()); + XRPL_ASSERT( + stack.empty(), "ripple::SHAMap::peekFirstItem : empty stack input"); SHAMapLeafNode* node = firstBelow(root_, stack); if (!node) { @@ -562,13 +580,18 @@ SHAMap::peekFirstItem(SharedPtrNodeStack& stack) const SHAMapLeafNode const* SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const { - assert(!stack.empty()); - assert(stack.top().first->isLeaf()); + XRPL_ASSERT( + !stack.empty(), "ripple::SHAMap::peekNextItem : non-empty stack input"); + XRPL_ASSERT( + stack.top().first->isLeaf(), + "ripple::SHAMap::peekNextItem : stack starts with leaf"); stack.pop(); while (!stack.empty()) { auto [node, nodeID] = stack.top(); - assert(!node->isLeaf()); + XRPL_ASSERT( + !node->isLeaf(), + "ripple::SHAMap::peekNextItem : another node is not leaf"); auto inner = std::static_pointer_cast(node); for (auto i = selectBranch(nodeID, id) + 1; i < branchFactor; ++i) { @@ -578,7 +601,9 @@ SHAMap::peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const auto leaf = firstBelow(node, stack, i); if (!leaf) Throw(type_, id); - assert(leaf->isLeaf()); + XRPL_ASSERT( + leaf->isLeaf(), + "ripple::SHAMap::peekNextItem : leaf is valid"); return leaf; } } @@ -696,7 +721,9 @@ bool SHAMap::delItem(uint256 const& id) { // delete the item with this ID - assert(state_ != SHAMapState::Immutable); + XRPL_ASSERT( + state_ != SHAMapState::Immutable, + "ripple::SHAMap::delItem : not immutable"); SharedPtrNodeStack stack; walkTowardsKey(id, &stack); @@ -775,8 +802,12 @@ SHAMap::addGiveItem( SHAMapNodeType type, boost::intrusive_ptr item) { - assert(state_ != SHAMapState::Immutable); - assert(type != SHAMapNodeType::tnINNER); + XRPL_ASSERT( + state_ != SHAMapState::Immutable, + "ripple::SHAMap::addGiveItem : not immutable"); + XRPL_ASSERT( + type != SHAMapNodeType::tnINNER, + "ripple::SHAMap::addGiveItem : valid type input"); // add the specified item, does not update uint256 tag = item->key(); @@ -802,7 +833,9 @@ SHAMap::addGiveItem( // easy case, we end on an inner node auto inner = std::static_pointer_cast(node); int branch = selectBranch(nodeID, tag); - assert(inner->isEmptyBranch(branch)); + XRPL_ASSERT( + inner->isEmptyBranch(branch), + "ripple::SHAMap::addGiveItem : inner branch is empty"); inner->setChild(branch, makeTypedLeaf(type, std::move(item), cowid_)); } else @@ -811,7 +844,9 @@ SHAMap::addGiveItem( // items auto leaf = std::static_pointer_cast(node); auto otherItem = leaf->peekItem(); - assert(otherItem && (tag != otherItem->key())); + XRPL_ASSERT( + otherItem && (tag != otherItem->key()), + "ripple::SHAMap::addGiveItem : non-null item"); node = std::make_shared(node->cowid()); @@ -829,7 +864,8 @@ SHAMap::addGiveItem( } // we can add the two leaf nodes here - assert(node->isInner()); + XRPL_ASSERT( + node->isInner(), "ripple::SHAMap::addGiveItem : node is inner"); auto inner = static_cast(node.get()); inner->setChild(b1, makeTypedLeaf(type, std::move(item), cowid_)); @@ -868,7 +904,9 @@ SHAMap::updateGiveItem( // can't change the tag but can change the hash uint256 tag = item->key(); - assert(state_ != SHAMapState::Immutable); + XRPL_ASSERT( + state_ != SHAMapState::Immutable, + "ripple::SHAMap::updateGiveItem : not immutable"); SharedPtrNodeStack stack; walkTowardsKey(tag, &stack); @@ -882,7 +920,7 @@ SHAMap::updateGiveItem( if (!node || (node->peekItem()->key() != tag)) { - assert(false); + UNREACHABLE("ripple::SHAMap::updateGiveItem : invalid node"); return false; } @@ -927,7 +965,9 @@ SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter) if (newRoot) { root_ = newRoot; - assert(root_->getHash() == hash); + XRPL_ASSERT( + root_->getHash() == hash, + "ripple::SHAMap::fetchRoot : root hash do match"); return true; } @@ -949,8 +989,9 @@ SHAMap::fetchRoot(SHAMapHash const& hash, SHAMapSyncFilter* filter) std::shared_ptr SHAMap::writeNode(NodeObjectType t, std::shared_ptr node) const { - assert(node->cowid() == 0); - assert(backed_); + XRPL_ASSERT( + node->cowid() == 0, "ripple::SHAMap::writeNode : valid input node"); + XRPL_ASSERT(backed_, "ripple::SHAMap::writeNode : is backed"); canonicalize(node->getHash(), node); @@ -970,7 +1011,8 @@ SHAMap::preFlushNode(std::shared_ptr node) const { // A shared node should never need to be flushed // because that would imply someone modified it - assert(node->cowid() != 0); + XRPL_ASSERT( + node->cowid(), "ripple::SHAMap::preFlushNode : valid input node"); if (node->cowid() != cowid_) { @@ -998,7 +1040,8 @@ SHAMap::flushDirty(NodeObjectType t) int SHAMap::walkSubTree(bool doWrite, NodeObjectType t) { - assert(!doWrite || backed_); + XRPL_ASSERT( + !doWrite || backed_, "ripple::SHAMap::walkSubTree : valid input"); int flushed = 0; @@ -1073,7 +1116,10 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t) // flush this leaf ++flushed; - assert(node->cowid() == cowid_); + XRPL_ASSERT( + node->cowid() == cowid_, + "ripple::SHAMap::walkSubTree : node cowid do " + "match"); child->updateHash(); child->unshare(); @@ -1106,7 +1152,9 @@ SHAMap::walkSubTree(bool doWrite, NodeObjectType t) stack.pop(); // Hook this inner node to its parent - assert(parent->cowid() == cowid_); + XRPL_ASSERT( + parent->cowid() == cowid_, + "ripple::SHAMap::walkSubTree : parent cowid do match"); parent->shareChild(pos, node); // Continue with parent's next child, if any @@ -1150,7 +1198,9 @@ SHAMap::dump(bool hash) const auto child = inner->getChildPointer(i); if (child) { - assert(child->getHash() == inner->getChildHash(i)); + XRPL_ASSERT( + child->getHash() == inner->getChildHash(i), + "ripple::SHAMap::dump : child hash do match"); stack.push({child, nodeID.getChildNodeID(i)}); } } @@ -1167,7 +1217,9 @@ std::shared_ptr SHAMap::cacheLookup(SHAMapHash const& hash) const { auto ret = f_.getTreeNodeCache()->fetch(hash.as_uint256()); - assert(!ret || !ret->cowid()); + XRPL_ASSERT( + !ret || !ret->cowid(), + "ripple::SHAMap::cacheLookup : not found or zero cowid"); return ret; } @@ -1176,9 +1228,12 @@ SHAMap::canonicalize( SHAMapHash const& hash, std::shared_ptr& node) const { - assert(backed_); - assert(node->cowid() == 0); - assert(node->getHash() == hash); + XRPL_ASSERT(backed_, "ripple::SHAMap::canonicalize : is backed"); + XRPL_ASSERT( + node->cowid() == 0, "ripple::SHAMap::canonicalize : valid node input"); + XRPL_ASSERT( + node->getHash() == hash, + "ripple::SHAMap::canonicalize : node hash do match"); f_.getTreeNodeCache()->canonicalize_replace_client(hash.as_uint256(), node); } @@ -1188,8 +1243,9 @@ SHAMap::invariants() const { (void)getHash(); // update node hashes auto node = root_.get(); - assert(node != nullptr); - assert(!node->isLeaf()); + XRPL_ASSERT(node, "ripple::SHAMap::invariants : non-null root node"); + XRPL_ASSERT( + !node->isLeaf(), "ripple::SHAMap::invariants : root node is not leaf"); SharedPtrNodeStack stack; for (auto leaf = peekFirstItem(stack); leaf != nullptr; leaf = peekNextItem(leaf->peekItem()->key(), stack)) diff --git a/src/xrpld/shamap/detail/SHAMapDelta.cpp b/src/xrpld/shamap/detail/SHAMapDelta.cpp index 0dcb861a63f..baabd4ef139 100644 --- a/src/xrpld/shamap/detail/SHAMapDelta.cpp +++ b/src/xrpld/shamap/detail/SHAMapDelta.cpp @@ -128,7 +128,9 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const // many differences throws on corrupt tables or missing nodes CAUTION: // otherMap is not locked and must be immutable - assert(isValid() && otherMap.isValid()); + XRPL_ASSERT( + isValid() && otherMap.isValid(), + "ripple::SHAMap::compare : valid state and valid input"); if (getHash() == otherMap.getHash()) return true; @@ -145,7 +147,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const if (!ourNode || !otherNode) { - assert(false); + UNREACHABLE("ripple::SHAMap::compare : missing a node"); Throw(type_, uint256()); } @@ -226,7 +228,7 @@ SHAMap::compare(SHAMap const& otherMap, Delta& differences, int maxCount) const } } else - assert(false); + UNREACHABLE("ripple::SHAMap::compare : invalid node"); } return true; @@ -323,7 +325,9 @@ SHAMap::walkMapParallel( { std::shared_ptr node = std::move(nodeStack.top()); - assert(node); + XRPL_ASSERT( + node, + "ripple::SHAMap::walkMapParallel : non-null node"); nodeStack.pop(); for (int i = 0; i < 16; ++i) diff --git a/src/xrpld/shamap/detail/SHAMapInnerNode.cpp b/src/xrpld/shamap/detail/SHAMapInnerNode.cpp index 99155a6401f..b2fba1f9314 100644 --- a/src/xrpld/shamap/detail/SHAMapInnerNode.cpp +++ b/src/xrpld/shamap/detail/SHAMapInnerNode.cpp @@ -225,7 +225,8 @@ SHAMapInnerNode::updateHashDeep() void SHAMapInnerNode::serializeForWire(Serializer& s) const { - assert(!isEmpty()); + XRPL_ASSERT( + !isEmpty(), "ripple::SHAMapInnerNode::serializeForWire : is non-empty"); // If the node is sparse, then only send non-empty branches: if (getBranchCount() < 12) @@ -249,7 +250,9 @@ SHAMapInnerNode::serializeForWire(Serializer& s) const void SHAMapInnerNode::serializeWithPrefix(Serializer& s) const { - assert(!isEmpty()); + XRPL_ASSERT( + !isEmpty(), + "ripple::SHAMapInnerNode::serializeWithPrefix : is non-empty"); s.add32(HashPrefix::innerNode); iterChildren( @@ -274,9 +277,13 @@ SHAMapInnerNode::getString(const SHAMapNodeID& id) const void SHAMapInnerNode::setChild(int m, std::shared_ptr child) { - assert((m >= 0) && (m < branchFactor)); - assert(cowid_ != 0); - assert(child.get() != this); + XRPL_ASSERT( + (m >= 0) && (m < branchFactor), + "ripple::SHAMapInnerNode::setChild : valid branch input"); + XRPL_ASSERT(cowid_, "ripple::SHAMapInnerNode::setChild : nonzero cowid"); + XRPL_ASSERT( + child.get() != this, + "ripple::SHAMapInnerNode::setChild : valid child input"); auto const dstIsBranch = [&] { if (child) @@ -303,27 +310,40 @@ SHAMapInnerNode::setChild(int m, std::shared_ptr child) hash_.zero(); - assert(getBranchCount() <= hashesAndChildren_.capacity()); + XRPL_ASSERT( + getBranchCount() <= hashesAndChildren_.capacity(), + "ripple::SHAMapInnerNode::setChild : maximum branch count"); } // finished modifying, now make shareable void SHAMapInnerNode::shareChild(int m, std::shared_ptr const& child) { - assert((m >= 0) && (m < branchFactor)); - assert(cowid_ != 0); - assert(child); - assert(child.get() != this); - - assert(!isEmptyBranch(m)); + XRPL_ASSERT( + (m >= 0) && (m < branchFactor), + "ripple::SHAMapInnerNode::shareChild : valid branch input"); + XRPL_ASSERT(cowid_, "ripple::SHAMapInnerNode::shareChild : nonzero cowid"); + XRPL_ASSERT( + child, "ripple::SHAMapInnerNode::shareChild : non-null child input"); + XRPL_ASSERT( + child.get() != this, + "ripple::SHAMapInnerNode::shareChild : valid child input"); + + XRPL_ASSERT( + !isEmptyBranch(m), + "ripple::SHAMapInnerNode::shareChild : non-empty branch input"); hashesAndChildren_.getChildren()[*getChildIndex(m)] = child; } SHAMapTreeNode* SHAMapInnerNode::getChildPointer(int branch) { - assert(branch >= 0 && branch < branchFactor); - assert(!isEmptyBranch(branch)); + XRPL_ASSERT( + branch >= 0 && branch < branchFactor, + "ripple::SHAMapInnerNode::getChildPointer : valid branch input"); + XRPL_ASSERT( + !isEmptyBranch(branch), + "ripple::SHAMapInnerNode::getChildPointer : non-empty branch input"); auto const index = *getChildIndex(branch); @@ -335,8 +355,12 @@ SHAMapInnerNode::getChildPointer(int branch) std::shared_ptr SHAMapInnerNode::getChild(int branch) { - assert(branch >= 0 && branch < branchFactor); - assert(!isEmptyBranch(branch)); + XRPL_ASSERT( + branch >= 0 && branch < branchFactor, + "ripple::SHAMapInnerNode::getChild : valid branch input"); + XRPL_ASSERT( + !isEmptyBranch(branch), + "ripple::SHAMapInnerNode::getChild : non-empty branch input"); auto const index = *getChildIndex(branch); @@ -348,7 +372,9 @@ SHAMapInnerNode::getChild(int branch) SHAMapHash const& SHAMapInnerNode::getChildHash(int m) const { - assert((m >= 0) && (m < branchFactor)); + XRPL_ASSERT( + (m >= 0) && (m < branchFactor), + "ripple::SHAMapInnerNode::getChildHash : valid branch input"); if (auto const i = getChildIndex(m)) return hashesAndChildren_.getHashes()[*i]; @@ -360,12 +386,21 @@ SHAMapInnerNode::canonicalizeChild( int branch, std::shared_ptr node) { - assert(branch >= 0 && branch < branchFactor); - assert(node); - assert(!isEmptyBranch(branch)); + XRPL_ASSERT( + branch >= 0 && branch < branchFactor, + "ripple::SHAMapInnerNode::canonicalizeChild : valid branch input"); + XRPL_ASSERT( + node != nullptr, + "ripple::SHAMapInnerNode::canonicalizeChild : valid node input"); + XRPL_ASSERT( + !isEmptyBranch(branch), + "ripple::SHAMapInnerNode::canonicalizeChild : non-empty branch input"); auto const childIndex = *getChildIndex(branch); auto [_, hashes, children] = hashesAndChildren_.getHashesAndChildren(); - assert(node->getHash() == hashes[childIndex]); + XRPL_ASSERT( + node->getHash() == hashes[childIndex], + "ripple::SHAMapInnerNode::canonicalizeChild : node and branch inputs " + "hash do match"); packed_spinlock sl(lock_, childIndex); std::lock_guard lock(sl); @@ -395,7 +430,9 @@ SHAMapInnerNode::invariants(bool is_root) const auto const branchCount = getBranchCount(); for (int i = 0; i < branchCount; ++i) { - assert(hashes[i].isNonZero()); + XRPL_ASSERT( + hashes[i].isNonZero(), + "ripple::SHAMapInnerNode::invariants : nonzero hash in branch"); if (children[i] != nullptr) children[i]->invariants(); ++count; @@ -407,24 +444,35 @@ SHAMapInnerNode::invariants(bool is_root) const { if (hashes[i].isNonZero()) { - assert((isBranch_ & (1 << i)) != 0); + XRPL_ASSERT( + (isBranch_ & (1 << i)), + "ripple::SHAMapInnerNode::invariants : valid branch when " + "nonzero hash"); if (children[i] != nullptr) children[i]->invariants(); ++count; } else { - assert((isBranch_ & (1 << i)) == 0); + XRPL_ASSERT( + (isBranch_ & (1 << i)) == 0, + "ripple::SHAMapInnerNode::invariants : valid branch when " + "zero hash"); } } } if (!is_root) { - assert(hash_.isNonZero()); - assert(count >= 1); + XRPL_ASSERT( + hash_.isNonZero(), + "ripple::SHAMapInnerNode::invariants : nonzero hash"); + XRPL_ASSERT( + count >= 1, "ripple::SHAMapInnerNode::invariants : minimum count"); } - assert((count == 0) ? hash_.isZero() : hash_.isNonZero()); + XRPL_ASSERT( + (count == 0) ? hash_.isZero() : hash_.isNonZero(), + "ripple::SHAMapInnerNode::invariants : hash and count do match"); } } // namespace ripple diff --git a/src/xrpld/shamap/detail/SHAMapLeafNode.cpp b/src/xrpld/shamap/detail/SHAMapLeafNode.cpp index 972919a9bda..72ec177fb39 100644 --- a/src/xrpld/shamap/detail/SHAMapLeafNode.cpp +++ b/src/xrpld/shamap/detail/SHAMapLeafNode.cpp @@ -28,7 +28,10 @@ SHAMapLeafNode::SHAMapLeafNode( std::uint32_t cowid) : SHAMapTreeNode(cowid), item_(std::move(item)) { - assert(item_->size() >= 12); + XRPL_ASSERT( + item_->size() >= 12, + "ripple::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" + "SHAMapItem const>, std::uint32_t) : minimum input size"); } SHAMapLeafNode::SHAMapLeafNode( @@ -37,7 +40,11 @@ SHAMapLeafNode::SHAMapLeafNode( SHAMapHash const& hash) : SHAMapTreeNode(cowid, hash), item_(std::move(item)) { - assert(item_->size() >= 12); + XRPL_ASSERT( + item_->size() >= 12, + "ripple::SHAMapLeafNode::SHAMapLeafNode(boost::intrusive_ptr<" + "SHAMapItem const>, std::uint32_t, SHAMapHash const&) : minimum input " + "size"); } boost::intrusive_ptr const& @@ -49,7 +56,7 @@ SHAMapLeafNode::peekItem() const bool SHAMapLeafNode::setItem(boost::intrusive_ptr item) { - assert(cowid_ != 0); + XRPL_ASSERT(cowid_, "ripple::SHAMapLeafNode::setItem : nonzero cowid"); item_ = std::move(item); auto const oldHash = hash_; @@ -87,8 +94,9 @@ SHAMapLeafNode::getString(const SHAMapNodeID& id) const void SHAMapLeafNode::invariants(bool) const { - assert(hash_.isNonZero()); - assert(item_ != nullptr); + XRPL_ASSERT( + hash_.isNonZero(), "ripple::SHAMapLeafNode::invariants : nonzero hash"); + XRPL_ASSERT(item_, "ripple::SHAMapLeafNode::invariants : non-null item"); } } // namespace ripple diff --git a/src/xrpld/shamap/detail/SHAMapNodeID.cpp b/src/xrpld/shamap/detail/SHAMapNodeID.cpp index 5cbd095e7a9..7f093dbe46e 100644 --- a/src/xrpld/shamap/detail/SHAMapNodeID.cpp +++ b/src/xrpld/shamap/detail/SHAMapNodeID.cpp @@ -20,9 +20,9 @@ #include #include #include +#include #include #include -#include namespace ripple { @@ -57,8 +57,12 @@ depthMask(unsigned int depth) SHAMapNodeID::SHAMapNodeID(unsigned int depth, uint256 const& hash) : id_(hash), depth_(depth) { - assert(depth <= SHAMap::leafDepth); - assert(id_ == (id_ & depthMask(depth))); + XRPL_ASSERT( + depth <= SHAMap::leafDepth, + "ripple::SHAMapNodeID::SHAMapNodeID : maximum depth input"); + XRPL_ASSERT( + id_ == (id_ & depthMask(depth)), + "ripple::SHAMapNodeID::SHAMapNodeID : hash and depth inputs do match"); } std::string @@ -73,7 +77,9 @@ SHAMapNodeID::getRawString() const SHAMapNodeID SHAMapNodeID::getChildNodeID(unsigned int m) const { - assert(m < SHAMap::branchFactor); + XRPL_ASSERT( + m < SHAMap::branchFactor, + "ripple::SHAMapNodeID::getChildNodeID : valid branch input"); // A SHAMap has exactly 65 levels, so nodes must not exceed that // depth; if they do, this breaks the invariant of never allowing @@ -83,7 +89,9 @@ SHAMapNodeID::getChildNodeID(unsigned int m) const // We throw (but never assert) if the node is at level 64, since // entries at that depth are leaf nodes and have no children and even // constructing a child node from them would break the above invariant. - assert(depth_ <= SHAMap::leafDepth); + XRPL_ASSERT( + depth_ <= SHAMap::leafDepth, + "ripple::SHAMapNodeID::getChildNodeID : maximum leaf depth"); if (depth_ >= SHAMap::leafDepth) Throw( @@ -128,14 +136,17 @@ selectBranch(SHAMapNodeID const& id, uint256 const& hash) else branch >>= 4; - assert(branch < SHAMap::branchFactor); + XRPL_ASSERT( + branch < SHAMap::branchFactor, "ripple::selectBranch : maximum result"); return branch; } SHAMapNodeID SHAMapNodeID::createID(int depth, uint256 const& key) { - assert((depth >= 0) && (depth < 65)); + XRPL_ASSERT( + (depth >= 0) && (depth < 65), + "ripple::SHAMapNodeID::createID : valid branch input"); return SHAMapNodeID(depth, key & depthMask(depth)); } diff --git a/src/xrpld/shamap/detail/SHAMapSync.cpp b/src/xrpld/shamap/detail/SHAMapSync.cpp index 7235e526560..4f938257511 100644 --- a/src/xrpld/shamap/detail/SHAMapSync.cpp +++ b/src/xrpld/shamap/detail/SHAMapSync.cpp @@ -314,8 +314,10 @@ SHAMap::gmn_ProcessDeferredReads(MissingNodes& mn) std::vector> SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) { - assert(root_->getHash().isNonZero()); - assert(max > 0); + XRPL_ASSERT( + root_->getHash().isNonZero(), + "ripple::SHAMap::getMissingNodes : nonzero root hash"); + XRPL_ASSERT(max > 0, "ripple::SHAMap::getMissingNodes : valid max input"); MissingNodes mn( max, @@ -374,7 +376,9 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) // This is a node we are continuing to process fullBelow = fullBelow && was; // was and still is } - assert(node); + XRPL_ASSERT( + node, + "ripple::SHAMap::getMissingNodes : first non-null node"); } } @@ -405,7 +409,9 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter* filter) // Resume at the top of the stack pos = mn.stack_.top(); mn.stack_.pop(); - assert(node != nullptr); + XRPL_ASSERT( + node, + "ripple::SHAMap::getMissingNodes : second non-null node"); } } @@ -532,11 +538,13 @@ SHAMap::addRootNode( if (root_->getHash().isNonZero()) { JLOG(journal_.trace()) << "got root node, already have one"; - assert(root_->getHash() == hash); + XRPL_ASSERT( + root_->getHash() == hash, + "ripple::SHAMap::addRootNode : valid hash input"); return SHAMapAddNode::duplicate(); } - assert(cowid_ >= 1); + XRPL_ASSERT(cowid_ >= 1, "ripple::SHAMap::addRootNode : valid cowid"); auto node = SHAMapTreeNode::makeFromWire(rootNode); if (!node || node->getHash() != hash) return SHAMapAddNode::invalid(); @@ -570,7 +578,8 @@ SHAMap::addKnownNode( Slice const& rawNode, SHAMapSyncFilter* filter) { - assert(!node.isRoot()); + XRPL_ASSERT( + !node.isRoot(), "ripple::SHAMap::addKnownNode : valid node input"); if (!isSynching()) { @@ -587,7 +596,7 @@ SHAMap::addKnownNode( (iNodeID.getDepth() < node.getDepth())) { int branch = selectBranch(iNodeID, node.getNodeID()); - assert(branch >= 0); + XRPL_ASSERT(branch >= 0, "ripple::SHAMap::addKnownNode : valid branch"); auto inner = static_cast(iNode); if (inner->isEmptyBranch(branch)) { diff --git a/src/xrpld/shamap/detail/TaggedPointer.ipp b/src/xrpld/shamap/detail/TaggedPointer.ipp index 487b88e3461..0e67947a8ed 100644 --- a/src/xrpld/shamap/detail/TaggedPointer.ipp +++ b/src/xrpld/shamap/detail/TaggedPointer.ipp @@ -79,14 +79,18 @@ constexpr auto chunksPerBlock = [[nodiscard]] inline std::uint8_t numAllocatedChildren(std::uint8_t n) { - assert(n <= SHAMapInnerNode::branchFactor); + XRPL_ASSERT( + n <= SHAMapInnerNode::branchFactor, + "ripple::numAllocatedChildren : valid input"); return *std::lower_bound(boundaries.begin(), boundaries.end(), n); } [[nodiscard]] inline std::size_t boundariesIndex(std::uint8_t numChildren) { - assert(numChildren <= SHAMapInnerNode::branchFactor); + XRPL_ASSERT( + numChildren <= SHAMapInnerNode::branchFactor, + "ripple::boundariesIndex : valid input"); return std::distance( boundaries.begin(), std::lower_bound(boundaries.begin(), boundaries.end(), numChildren)); @@ -156,7 +160,9 @@ allocateArrays(std::uint8_t numChildren) inline void deallocateArrays(std::uint8_t boundaryIndex, void* p) { - assert(isFromArrayFuns[boundaryIndex](p)); + XRPL_ASSERT( + isFromArrayFuns[boundaryIndex](p), + "ripple::deallocateArrays : valid inputs"); freeArrayFuns[boundaryIndex](p); } @@ -270,10 +276,15 @@ TaggedPointer::getChildIndex(std::uint16_t isBranch, int i) const inline TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t numChildren) { auto [tag, p] = allocateArrays(numChildren); - assert(tag < boundaries.size()); - assert( + XRPL_ASSERT( + tag < boundaries.size(), + "ripple::TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t) : " + "maximum tag"); + XRPL_ASSERT( (reinterpret_cast(p) & ptrMask) == - reinterpret_cast(p)); + reinterpret_cast(p), + "ripple::TaggedPointer::TaggedPointer(RawAllocateTag, std::uint8_t) : " + "valid pointer"); tp_ = reinterpret_cast(p) + tag; } @@ -283,7 +294,10 @@ inline TaggedPointer::TaggedPointer( std::uint16_t dstBranches, std::uint8_t toAllocate) { - assert(toAllocate >= popcnt16(dstBranches)); + XRPL_ASSERT( + toAllocate >= popcnt16(dstBranches), + "ripple::TaggedPointer::TaggedPointer(TaggedPointer&& ...) : minimum " + "toAllocate input"); if (other.capacity() == numAllocatedChildren(toAllocate)) { @@ -428,7 +442,10 @@ inline TaggedPointer::TaggedPointer( } } // If sparse, may need to run additional constructors - assert(!dstIsDense || dstIndex == dstNumAllocated); + XRPL_ASSERT( + !dstIsDense || dstIndex == dstNumAllocated, + "ripple::TaggedPointer::TaggedPointer(TaggedPointer&& ...) : " + "non-sparse or valid sparse"); for (int i = dstIndex; i < dstNumAllocated; ++i) { new (&dstHashes[i]) SHAMapHash{};