Compare commits

...

26 Commits

Author SHA1 Message Date
Pratik Mankawde
19dca11cf9 Merge branch 'develop' into pratik/Move-runtime-sanitizer-options-to-file 2026-03-12 14:10:30 +00:00
Ayaz Salikhov
e460ea0840 ci: Move Type of Change from PR template to CONTRIBUTING (#6522)
Now that prefixes in PR titles are being validated as part of CI, the "Type of Change" section in the PR template is no longer needed. The prefixes and descriptions in the `CONTRIBUTING.md` file have been updated to reflect the currently supported list.
2026-03-12 06:39:40 +01:00
yinyiqian1
46d5c67a8d fix: Mark SAV and Lending transactions as NotDelegable (#6489)
New transactions should be marked as `NotDelegable`, until the interactions with other transactions have been fully tested and validated.
2026-03-11 21:27:35 +00:00
Mayukha Vadari
ce9ccf844a fix: Remove unneeded import, fix log (#6532)
This change:
* Removes an unneeded import in `DeleteAccount.cpp`.
* Fixes a typo in a log statement in `SetAccount.cpp`.
2026-03-11 19:36:03 +00:00
Pratik Mankawde
a127ef0615 Merge branch 'develop' into pratik/Move-runtime-sanitizer-options-to-file 2026-03-11 18:34:36 +00:00
Sergey Kuznetsov
c791cae1ec test: Fix flaky subscribe tests (#6510)
Subscribe tests have a problem that there is no way to synchronize application running in background threads and test threads. Threads are communicating via websocket messages. When the code is compiled in debug mode with code coverage enabled it executes quite slow, so receiving websocket messages by the client in subscribe tests may time out.

This change does 2 things to fix the problem:
* Increases timeout for receiving a websocket message.
* Decreases the number of tests running in parallel.

While testing the fix for subscribe test another flaky test in ledger replay was found, which has also been addressed.
2026-03-11 18:06:12 +00:00
Pratik Mankawde
a1bf44a675 added some suppressions to let the CI pass. These are cleared in other PRs
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-03-11 14:45:02 +00:00
Pratik Mankawde
47724a4836 Merge branch 'develop' into pratik/Move-runtime-sanitizer-options-to-file 2026-03-11 14:37:17 +00:00
Alex Kremer
7b3724b7a3 fix: Add missed clang-tidy bugprone-inc-dec-conditions check (#6526) 2026-03-11 14:04:26 +00:00
Ayaz Salikhov
bee2d112c6 ci: Fix how clang-tidy is run when .clang-tidy is changed (#6521) 2026-03-11 14:18:18 +01:00
Bart
01c977bbfe ci: Fix rules used to determine when to upload Conan recipes (#6524)
The refs as previously used pointed to the source branch, not the target branch. However, determining the target branch is different depending on the GitHub event. The pull request logic was incorrect and needed to be fixed, and the logic inside the workflow could be simplified. Both modifications have been made in this commit.
2026-03-11 13:43:58 +01:00
Bart
3baf5454f2 ci: Only upload artifacts in the XRPLF/rippled repository (#6523)
This change will only attempt to upload artifacts for CI runs performed in the XRPLF/rippled repository.
2026-03-11 11:48:40 +01:00
Michael Legleux
24a5cbaa93 chore: Build voidstar on amd64 only (#6481)
* chore: Build voidstar on amd64 only

* fatal error if configuring voidstar on  non x86
2026-03-10 23:59:43 +00:00
Michael Legleux
eb7c8c6c7a chore: Use CMake components for install (#6485)
* chore: Use components for install

* rm CMake export targets

* reformat
2026-03-10 23:38:43 +00:00
Alex Kremer
f27d8f3890 chore: Enable clang-tidy bugprone-inc-dec-in-conditions check (#6455) 2026-03-10 20:12:15 +00:00
Alex Kremer
8345cd77df chore: Enable clang-tidy bugprone-unused-raii check (#6505) 2026-03-10 19:48:56 +00:00
Alex Kremer
c38aabdaee chore: Enable clang-tidy bugprone-unhandled-self-assignment check (#6504) 2026-03-10 17:42:49 +00:00
Pratik Mankawde
38de875259 Merge branch 'develop' into pratik/Move-runtime-sanitizer-options-to-file 2026-03-10 15:47:21 +00:00
Pratik Mankawde
48fb31b409 Merge branch 'develop' into pratik/Move-runtime-sanitizer-options-to-file 2026-03-09 11:23:01 +00:00
Pratik Mankawde
9df00098bd Added ErrorCodes.h to supp
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-02-24 14:16:47 +00:00
Pratik Mankawde
68c3a0e65e Merge branch 'pratik/Move-runtime-sanitizer-options-to-file' of github.com:XRPLF/rippled into pratik/Move-runtime-sanitizer-options-to-file 2026-02-23 15:19:20 +00:00
Pratik Mankawde
637628cca5 remove default options
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-02-23 15:19:14 +00:00
Pratik Mankawde
a8df346478 Merge branch 'develop' into pratik/Move-runtime-sanitizer-options-to-file 2026-02-23 13:24:29 +00:00
Pratik Mankawde
ec365fb986 added symbolize=true
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-02-23 13:24:01 +00:00
Pratik Mankawde
4478ddaff4 added more options
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-02-23 13:23:15 +00:00
Pratik Mankawde
ef83091ba8 Move sanitizer runtime options out to files
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com>
2026-02-16 15:39:32 +00:00
38 changed files with 278 additions and 399 deletions

View File

@@ -14,6 +14,7 @@ Checks: "-*,
bugprone-fold-init-type,
bugprone-forward-declaration-namespace,
bugprone-inaccurate-erase,
bugprone-inc-dec-in-conditions,
bugprone-incorrect-enable-if,
bugprone-incorrect-roundings,
bugprone-infinite-loop,
@@ -64,8 +65,10 @@ Checks: "-*,
bugprone-undefined-memory-manipulation,
bugprone-undelegated-constructor,
bugprone-unhandled-exception-at-new,
bugprone-unhandled-self-assignment,
bugprone-unique-ptr-array-mismatch,
bugprone-unsafe-functions,
bugprone-unused-raii,
bugprone-unused-local-non-trivial-variable,
bugprone-virtual-near-miss,
cppcoreguidelines-no-suspend-with-lock,
@@ -95,13 +98,11 @@ Checks: "-*,
# checks that have some issues that need to be resolved:
#
# bugprone-crtp-constructor-accessibility,
# bugprone-inc-dec-in-conditions,
# bugprone-move-forwarding-reference,
# bugprone-switch-missing-default-case,
# bugprone-unused-raii,
# bugprone-unused-return-value,
# bugprone-use-after-move,
# bugprone-unhandled-self-assignment,
# bugprone-unused-raii,
#
# cppcoreguidelines-misleading-capture-default-by-value,
# cppcoreguidelines-init-variables,

View File

@@ -29,22 +29,6 @@ If a refactor, how is this better than the previous implementation?
If there is a spec or design document for this feature, please link it here.
-->
### Type of Change
<!--
Please check [x] relevant options, delete irrelevant ones.
-->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Refactor (non-breaking change that only restructures code)
- [ ] Performance (increase or change in throughput and/or latency)
- [ ] Tests (you added tests for code that already exists, or your new feature included in this PR)
- [ ] Documentation update
- [ ] Chore (no impact to binary, e.g. `.gitignore`, formatting, dropping support for older tooling)
- [ ] Release
### API Impact
<!--

View File

@@ -55,7 +55,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
# fee to 500.
# - Bookworm using GCC 15: Debug on linux/amd64, enable code
# coverage (which will be done below).
# - Bookworm using Clang 16: Debug on linux/arm64, enable voidstar.
# - Bookworm using Clang 16: Debug on linux/amd64, enable voidstar.
# - Bookworm using Clang 17: Release on linux/amd64, set the
# reference fee to 1000.
# - Bookworm using Clang 20: Debug on linux/amd64.
@@ -78,7 +78,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-16"
and build_type == "Debug"
and architecture["platform"] == "linux/arm64"
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-Dvoidstar=ON {cmake_args}"
skip = False

View File

@@ -141,9 +141,8 @@ jobs:
needs:
- should-run
- build-test
# Only run when committing to a PR that targets a release branch in the
# XRPLF repository.
if: ${{ github.repository_owner == 'XRPLF' && needs.should-run.outputs.go == 'true' && startsWith(github.ref, 'refs/heads/release') }}
# Only run when committing to a PR that targets a release branch.
if: ${{ github.repository == 'XRPLF/rippled' && needs.should-run.outputs.go == 'true' && github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release') }}
uses: ./.github/workflows/reusable-upload-recipe.yml
secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}

View File

@@ -17,8 +17,7 @@ defaults:
jobs:
upload-recipe:
# Only run when a tag is pushed to the XRPLF repository.
if: ${{ github.repository_owner == 'XRPLF' }}
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: ./.github/workflows/reusable-upload-recipe.yml
secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}

View File

@@ -92,8 +92,8 @@ jobs:
upload-recipe:
needs: build-test
# Only run when pushing to the develop branch in the XRPLF repository.
if: ${{ github.repository_owner == 'XRPLF' && github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
# Only run when pushing to the develop branch.
if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
uses: ./.github/workflows/reusable-upload-recipe.yml
secrets:
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}

View File

@@ -176,7 +176,7 @@ jobs:
fi
- name: Upload the binary (Linux)
if: ${{ github.repository_owner == 'XRPLF' && runner.os == 'Linux' }}
if: ${{ github.repository == 'XRPLF/rippled' && runner.os == 'Linux' }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: xrpld-${{ inputs.config_name }}
@@ -205,10 +205,10 @@ jobs:
- name: Set sanitizer options
if: ${{ !inputs.build_only && env.SANITIZERS_ENABLED == 'true' }}
run: |
echo "ASAN_OPTIONS=print_stacktrace=1:detect_container_overflow=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" >> ${GITHUB_ENV}
echo "TSAN_OPTIONS=second_deadlock_stack=1:halt_on_error=0:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV}
echo "UBSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV}
echo "LSAN_OPTIONS=suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV}
echo "ASAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-asan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/asan.supp" >> ${GITHUB_ENV}
echo "TSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-tsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/tsan.supp" >> ${GITHUB_ENV}
echo "UBSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/ubsan.supp" >> ${GITHUB_ENV}
echo "LSAN_OPTIONS=include=${GITHUB_WORKSPACE}/sanitizers/suppressions/runtime-lsan-options.txt:suppressions=${GITHUB_WORKSPACE}/sanitizers/suppressions/lsan.supp" >> ${GITHUB_ENV}
- name: Run the separate tests
if: ${{ !inputs.build_only }}
@@ -230,6 +230,8 @@ jobs:
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
run: |
set -o pipefail
# Coverage builds are slower due to instrumentation; use fewer parallel jobs to avoid flakiness
[ "$COVERAGE_ENABLED" = "true" ] && BUILD_NPROC=$(( BUILD_NPROC - 2 ))
./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log
- name: Show test failure summary
@@ -266,7 +268,7 @@ jobs:
--target coverage
- name: Upload coverage report
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
disable_search: true

View File

@@ -51,5 +51,5 @@ jobs:
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_cpp_changed == 'true' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
uses: ./.github/workflows/reusable-clang-tidy-files.yml
with:
files: ${{ (needs.determine-files.outputs.clang_tidy_config_changed == 'true' && '') || (inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '') }}
files: ${{ needs.determine-files.outputs.clang_tidy_config_changed == 'true' && '' || (inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '') }}
create_issue_on_failure: ${{ inputs.create_issue_on_failure }}

View File

@@ -69,22 +69,28 @@ jobs:
conan export . --version=${{ steps.version.outputs.version }}
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.version.outputs.version }}
# When this workflow is triggered by a push event, it will always be when merging into the
# 'develop' branch, see on-trigger.yml.
- name: Upload Conan recipe (develop)
if: ${{ github.ref == 'refs/heads/develop' }}
if: ${{ github.event_name == 'push' }}
env:
REMOTE_NAME: ${{ inputs.remote_name }}
run: |
conan export . --version=develop
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/develop
# When this workflow is triggered by a pull request event, it will always be when merging into
# one of the 'release' branches, see on-pr.yml.
- name: Upload Conan recipe (rc)
if: ${{ startsWith(github.ref, 'refs/heads/release') }}
if: ${{ github.event_name == 'pull_request' }}
env:
REMOTE_NAME: ${{ inputs.remote_name }}
run: |
conan export . --version=rc
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/rc
# When this workflow is triggered by a tag event, it will always be when tagging a final
# release, see on-tag.yml.
- name: Upload Conan recipe (release)
if: ${{ github.event_name == 'tag' }}
env:

View File

@@ -103,11 +103,11 @@ jobs:
sanitizers: ${{ matrix.sanitizers }}
- name: Log into Conan remote
if: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.CONAN_REMOTE_USERNAME }}" --password "${{ secrets.CONAN_REMOTE_PASSWORD }}"
- name: Upload Conan packages
if: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
env:
FORCE_OPTION: ${{ github.event.inputs.force_upload == 'true' && '--force' || '' }}
run: conan upload "*" --remote="${CONAN_REMOTE_NAME}" --confirm ${FORCE_OPTION}

View File

@@ -131,7 +131,6 @@ if(coverage)
include(XrplCov)
endif()
set(PROJECT_EXPORT_SET XrplExports)
include(XrplCore)
include(XrplInstall)
include(XrplValidatorKeys)

View File

@@ -127,26 +127,6 @@ tl;dr
> 6. Wrap the body at 72 characters.
> 7. Use the body to explain what and why vs. how.
In addition to those guidelines, please add one of the following
prefixes to the subject line if appropriate.
- `fix:` - The primary purpose is to fix an existing bug.
- `perf:` - The primary purpose is performance improvements.
- `refactor:` - The changes refactor code without affecting
functionality.
- `test:` - The changes _only_ affect unit tests.
- `docs:` - The changes _only_ affect documentation. This can
include code comments in addition to `.md` files like this one.
- `build:` - The changes _only_ affect the build process,
including CMake and/or Conan settings.
- `chore:` - Other tasks that don't affect the binary, but don't fit
any of the other cases. e.g. formatting, git settings, updating
Github Actions jobs.
Whenever possible, when updating commits after the PR is open, please
add the PR number to the end of the subject line. e.g. `test: Add
unit tests for Feature X (#1234)`.
## Pull requests
In general, pull requests use `develop` as the base branch.
@@ -180,6 +160,23 @@ credibility of the existing approvals is insufficient.
Pull requests must be merged by [squash-and-merge][squash]
to preserve a linear history for the `develop` branch.
### Type of Change
In addition to those guidelines, please start your PR title with one of the following:
- `build:` - The changes _only_ affect the build process, including CMake and/or Conan settings.
- `feat`: New feature (change which adds functionality).
- `fix:` - The primary purpose is to fix an existing bug.
- `docs:` - The changes _only_ affect documentation.
- `test:` - The changes _only_ affect unit tests.
- `ci`: Continuous Integration (changes to our CI configuration files and scripts).
- `style`: Code style (formatting).
- `refactor:` - The changes refactor code without affecting functionality.
- `perf:` - The primary purpose is performance improvements.
- `chore:` - Other tasks that don't affect the binary, but don't fit any of the other cases. e.g. `git` settings, `clang-tidy`, removing dead code, dropping support for older tooling.
First letter after the type prefix should be capitalized, and the type prefix should be followed by a colon and a space. e.g. `feat: Add support for Borrowing Protocol`.
### "Ready to merge"
A pull request should only have the "Ready to merge" label added when it

View File

@@ -1,60 +0,0 @@
include(CMakeFindDependencyMacro)
# need to represent system dependencies of the lib here
#[=========================================================[
Boost
#]=========================================================]
if(static OR APPLE OR MSVC)
set(Boost_USE_STATIC_LIBS ON)
endif()
set(Boost_USE_MULTITHREADED ON)
if(static OR MSVC)
set(Boost_USE_STATIC_RUNTIME ON)
else()
set(Boost_USE_STATIC_RUNTIME OFF)
endif()
find_dependency(
Boost
COMPONENTS
chrono
container
context
coroutine
date_time
filesystem
program_options
regex
system
thread
)
#[=========================================================[
OpenSSL
#]=========================================================]
if(NOT DEFINED OPENSSL_ROOT_DIR)
if(DEFINED ENV{OPENSSL_ROOT})
set(OPENSSL_ROOT_DIR $ENV{OPENSSL_ROOT})
elseif(APPLE)
find_program(homebrew brew)
if(homebrew)
execute_process(
COMMAND ${homebrew} --prefix openssl
OUTPUT_VARIABLE OPENSSL_ROOT_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
endif()
file(TO_CMAKE_PATH "${OPENSSL_ROOT_DIR}" OPENSSL_ROOT_DIR)
endif()
if(static OR APPLE OR MSVC)
set(OPENSSL_USE_STATIC_LIBS ON)
endif()
set(OPENSSL_MSVC_STATIC_RT ON)
find_dependency(OpenSSL REQUIRED)
find_dependency(ZLIB)
find_dependency(date)
if(TARGET ZLIB::ZLIB)
set_target_properties(
OpenSSL::Crypto
PROPERTIES INTERFACE_LINK_LIBRARIES ZLIB::ZLIB
)
endif()

View File

@@ -2,100 +2,38 @@
install stuff
#]===================================================================]
include(create_symbolic_link)
include(GNUInstallDirs)
# If no suffix is defined for executables (e.g. Windows uses .exe but Linux
# and macOS use none), then explicitly set it to the empty string.
if(NOT DEFINED suffix)
set(suffix "")
if(is_root_project AND TARGET xrpld)
install(
TARGETS xrpld
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT runtime
)
install(
FILES "${CMAKE_CURRENT_SOURCE_DIR}/cfg/xrpld-example.cfg"
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/xrpld"
RENAME xrpld.cfg
COMPONENT runtime
)
install(
FILES "${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt"
DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/xrpld"
RENAME validators.txt
COMPONENT runtime
)
endif()
install(
TARGETS
common
opts
xrpl_boost
xrpl_libs
xrpl_syslibs
xrpl.imports.main
xrpl.libpb
xrpl.libxrpl
xrpl.libxrpl.basics
xrpl.libxrpl.beast
xrpl.libxrpl.conditions
xrpl.libxrpl.core
xrpl.libxrpl.crypto
xrpl.libxrpl.git
xrpl.libxrpl.json
xrpl.libxrpl.rdb
xrpl.libxrpl.ledger
xrpl.libxrpl.net
xrpl.libxrpl.nodestore
xrpl.libxrpl.protocol
xrpl.libxrpl.resource
xrpl.libxrpl.server
xrpl.libxrpl.shamap
xrpl.libxrpl.tx
antithesis-sdk-cpp
EXPORT XrplExports
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
TARGETS xrpl.libpb xrpl.libxrpl
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT development
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT development
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT development
)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/xrpl"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
install(
EXPORT XrplExports
FILE XrplTargets.cmake
NAMESPACE Xrpl::
DESTINATION lib/cmake/xrpl
)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
XrplConfigVersion.cmake
VERSION ${xrpld_version}
COMPATIBILITY SameMajorVersion
)
if(is_root_project AND TARGET xrpld)
install(TARGETS xrpld RUNTIME DESTINATION bin)
set_target_properties(xrpld PROPERTIES INSTALL_RPATH_USE_LINK_PATH ON)
# sample configs should not overwrite existing files
# install if-not-exists workaround as suggested by
# https://cmake.org/Bug/view.php?id=12646
install(
CODE
"
macro (copy_if_not_exists SRC DEST NEWNAME)
if (NOT EXISTS \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\")
file (INSTALL FILE_PERMISSIONS OWNER_READ OWNER_WRITE DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${DEST}\" FILES \"\${SRC}\" RENAME \"\${NEWNAME}\")
else ()
message (\"-- Skipping : \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/\${DEST}/\${NEWNAME}\")
endif ()
endmacro()
copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/xrpld-example.cfg\" etc xrpld.cfg)
copy_if_not_exists(\"${CMAKE_CURRENT_SOURCE_DIR}/cfg/validators-example.txt\" etc validators.txt)
"
)
install(
CODE
"
set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\")
include(create_symbolic_link)
create_symbolic_link(xrpld${suffix} \
\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/rippled${suffix})
"
)
endif()
install(
FILES
${CMAKE_CURRENT_SOURCE_DIR}/cmake/XrplConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/XrplConfigVersion.cmake
DESTINATION lib/cmake/xrpl
COMPONENT development
)

View File

@@ -50,6 +50,13 @@ if(MSVC AND CMAKE_GENERATOR_PLATFORM STREQUAL "Win32")
message(FATAL_ERROR "Visual Studio 32-bit build is not supported.")
endif()
if(voidstar AND NOT is_amd64)
message(
FATAL_ERROR
"The voidstar library only supported on amd64/x86_64. Detected archictecture was: ${CMAKE_SYSTEM_PROCESSOR}"
)
endif()
if(APPLE AND NOT HOMEBREW)
find_program(HOMEBREW brew)
endif()

View File

@@ -89,8 +89,8 @@ cmake --build . --parallel 4
**IMPORTANT**: ASAN with Boost produces many false positives. Use these options:
```bash
export ASAN_OPTIONS="print_stacktrace=1:detect_container_overflow=0:suppressions=path/to/asan.supp:halt_on_error=0:log_path=asan.log"
export LSAN_OPTIONS="suppressions=path/to/lsan.supp:halt_on_error=0:log_path=lsan.log"
export ASAN_OPTIONS="include=sanitizers/suppressions/runtime-asan-options.txt:suppressions=sanitizers/suppressions/asan.supp"
export LSAN_OPTIONS="include=sanitizers/suppressions/runtime-lsan-options.txt:suppressions=sanitizers/suppressions/lsan.supp"
# Run tests
./xrpld --unittest --unittest-jobs=5
@@ -108,7 +108,7 @@ export LSAN_OPTIONS="suppressions=path/to/lsan.supp:halt_on_error=0:log_path=lsa
### ThreadSanitizer (TSan)
```bash
export TSAN_OPTIONS="suppressions=path/to/tsan.supp halt_on_error=0 log_path=tsan.log"
export TSAN_OPTIONS="include=sanitizers/suppressions/runtime-tsan-options.txt:suppressions=sanitizers/suppressions/tsan.supp"
# Run tests
./xrpld --unittest --unittest-jobs=5
@@ -129,7 +129,7 @@ More details [here](https://github.com/google/sanitizers/wiki/AddressSanitizerLe
### UndefinedBehaviorSanitizer (UBSan)
```bash
export UBSAN_OPTIONS="suppressions=path/to/ubsan.supp:print_stacktrace=1:halt_on_error=0:log_path=ubsan.log"
export UBSAN_OPTIONS="include=sanitizers/suppressions/runtime-ubsan-options.txt:suppressions=sanitizers/suppressions/ubsan.supp"
# Run tests
./xrpld --unittest --unittest-jobs=5

View File

@@ -830,7 +830,7 @@ TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
# include <xrpl/tx/transactors/vault/VaultCreate.h>
#endif
TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
Delegation::delegable,
Delegation::notDelegable,
featureSingleAssetVault,
createPseudoAcct | createMPTIssuance | mustModifyVault,
({
@@ -848,7 +848,7 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
# include <xrpl/tx/transactors/vault/VaultSet.h>
#endif
TRANSACTION(ttVAULT_SET, 66, VaultSet,
Delegation::delegable,
Delegation::notDelegable,
featureSingleAssetVault,
mustModifyVault,
({
@@ -863,7 +863,7 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet,
# include <xrpl/tx/transactors/vault/VaultDelete.h>
#endif
TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
Delegation::delegable,
Delegation::notDelegable,
featureSingleAssetVault,
mustDeleteAcct | destroyMPTIssuance | mustModifyVault,
({
@@ -875,7 +875,7 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
# include <xrpl/tx/transactors/vault/VaultDeposit.h>
#endif
TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
Delegation::delegable,
Delegation::notDelegable,
featureSingleAssetVault,
mayAuthorizeMPT | mustModifyVault,
({
@@ -888,7 +888,7 @@ TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
# include <xrpl/tx/transactors/vault/VaultWithdraw.h>
#endif
TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
Delegation::delegable,
Delegation::notDelegable,
featureSingleAssetVault,
mayDeleteMPT | mayAuthorizeMPT | mustModifyVault,
({
@@ -903,7 +903,7 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
# include <xrpl/tx/transactors/vault/VaultClawback.h>
#endif
TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
Delegation::delegable,
Delegation::notDelegable,
featureSingleAssetVault,
mayDeleteMPT | mustModifyVault,
({
@@ -932,7 +932,7 @@ TRANSACTION(ttBATCH, 71, Batch,
# include <xrpl/tx/transactors/lending/LoanBrokerSet.h>
#endif
TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
createPseudoAcct | mayAuthorizeMPT, ({
{sfVaultID, soeREQUIRED},
@@ -949,7 +949,7 @@ TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
# include <xrpl/tx/transactors/lending/LoanBrokerDelete.h>
#endif
TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
mustDeleteAcct | mayAuthorizeMPT, ({
{sfLoanBrokerID, soeREQUIRED},
@@ -960,7 +960,7 @@ TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
# include <xrpl/tx/transactors/lending/LoanBrokerCoverDeposit.h>
#endif
TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
noPriv, ({
{sfLoanBrokerID, soeREQUIRED},
@@ -972,7 +972,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
# include <xrpl/tx/transactors/lending/LoanBrokerCoverWithdraw.h>
#endif
TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
mayAuthorizeMPT, ({
{sfLoanBrokerID, soeREQUIRED},
@@ -987,7 +987,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
# include <xrpl/tx/transactors/lending/LoanBrokerCoverClawback.h>
#endif
TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
noPriv, ({
{sfLoanBrokerID, soeOPTIONAL},
@@ -999,7 +999,7 @@ TRANSACTION(ttLOAN_BROKER_COVER_CLAWBACK, 78, LoanBrokerCoverClawback,
# include <xrpl/tx/transactors/lending/LoanSet.h>
#endif
TRANSACTION(ttLOAN_SET, 80, LoanSet,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
mayAuthorizeMPT | mustModifyVault, ({
{sfLoanBrokerID, soeREQUIRED},
@@ -1026,7 +1026,7 @@ TRANSACTION(ttLOAN_SET, 80, LoanSet,
# include <xrpl/tx/transactors/lending/LoanDelete.h>
#endif
TRANSACTION(ttLOAN_DELETE, 81, LoanDelete,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
noPriv, ({
{sfLoanID, soeREQUIRED},
@@ -1037,7 +1037,7 @@ TRANSACTION(ttLOAN_DELETE, 81, LoanDelete,
# include <xrpl/tx/transactors/lending/LoanManage.h>
#endif
TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
// All of the LoanManage options will modify the vault, but the
// transaction can succeed without options, essentially making it
@@ -1051,7 +1051,7 @@ TRANSACTION(ttLOAN_MANAGE, 82, LoanManage,
# include <xrpl/tx/transactors/lending/LoanPay.h>
#endif
TRANSACTION(ttLOAN_PAY, 84, LoanPay,
Delegation::delegable,
Delegation::notDelegable,
featureLendingProtocol,
mayAuthorizeMPT | mustModifyVault, ({
{sfLoanID, soeREQUIRED},

View File

@@ -20,6 +20,34 @@ interceptor_name:xrpl/net/HTTPClient.h
interceptor_name:xrpl/net/HTTPClientSSLContext.h
interceptor_name:xrpl/net/RegisterSSLCerts.h
# The issue is a well-known interaction between ASan's use-after-scope detection and aggressive inlining. All the Json::StaticString overloads in ErrorCodes.h follow this pattern:
# inline Json::Value
# invalid_field_error(Json::StaticString name)
# {
# return invalid_field_error(std::string(name)); // temporary passed by const ref
# }
# When Clang inlines the entire call chain (invalid_field_error(StaticString) → invalid_field_error(const string&) → invalid_field_message(const string&)),
# the compiler inserts ASan scope-poisoning markers for the temporary std::string. Because there's no actual function call boundary after inlining,
# ASan can poison the temporary before the inlined callee finishes reading through the const string&.
#
# Per the C++ standard the temporary's lifetime extends through the full-expression, so the original code is technically valid.
# But ASan's scope tracking doesn't model this correctly after inlining, causing it to flag a use-after-scope and (on the coroutine stack) crash the Simulate test.
#
# The fix is to use a named local variable instead of a temporary. This gives the std::string an unambiguous scope that ASan tracks correctly:
# inline Json::Value
# invalid_field_error(Json::StaticString name)
# {
# std::string s(name);
# return invalid_field_error(s);
# }
# The same pattern should be fixed in all the StaticString overloads in that file
# -- missing_field_error, object_field_error, invalid_field_message, expected_field_message, and expected_field_error (lines 237-306).
# They all do the same return func(std::string(name)) with a temporary.
# In this PR we just suppress the error for the whole file.
# Then in another PR we will mark the functions with `__attribute__((no_sanitize("address")))`, to keep the original code but disable the false positive.
interceptor_name:xrpl/protocol/ErrorCodes.h
# Suppress false positive stack-buffer errors in thread stack allocation
# Related to ASan's __asan_handle_no_return warnings (github.com/google/sanitizers/issues/189)
# These occur during multi-threaded test initialization on macOS

View File

@@ -0,0 +1,8 @@
detect_container_overflow=false
detect_stack_use_after_return=false
debug=true
halt_on_error=false
print_stats=true
print_cmdline=true
use_sigaltstack=0
print_stacktrace=1

View File

@@ -0,0 +1 @@
halt_on_error=false

View File

@@ -0,0 +1,3 @@
halt_on_error=false
verbosity=1
second_deadlock_stack=1

View File

@@ -0,0 +1 @@
halt_on_error=false

View File

@@ -27,3 +27,11 @@ src:core/JobQueue.cpp
src:libxrpl/beast/utility/beast_Journal.cpp
src:test/beast/beast_PropertyStream_test.cpp
src:src/test/app/Invariants_test.cpp
# ASan false positive: stack-use-after-scope in ErrorCodes.h inline functions.
# When Clang inlines the StaticString overloads (e.g. invalid_field_error(StaticString)),
# ASan scope-poisons the temporary std::string before the inlined callee finishes reading
# through the const ref. This corrupts the coroutine stack and crashes the Simulate test.
# See asan.supp comments for full explanation and planned fix.
[address]
src:*ErrorCodes.h

View File

@@ -182,6 +182,17 @@ signed-integer-overflow:src/test/beast/LexicalCast_test.cpp
# External library suppressions
unsigned-integer-overflow:nudb/detail/xxhash.hpp
# Loan_test.cpp intentional underflow in test arithmetic
unsigned-integer-overflow:src/test/app/Loan_test.cpp
undefined:src/test/app/Loan_test.cpp
# Source tree restructured paths (libxrpl/tx/transactors/)
# These duplicate the xrpld/app/tx/detail entries above for the new layout
unsigned-integer-overflow:src/libxrpl/tx/transactors/oracle/SetOracle.cpp
undefined:src/libxrpl/tx/transactors/oracle/SetOracle.cpp
unsigned-integer-overflow:src/libxrpl/tx/transactors/nft/NFTokenMint.cpp
undefined:src/libxrpl/tx/transactors/nft/NFTokenMint.cpp
# Protobuf intentional overflows in hash functions
# Protobuf uses intentional unsigned overflow for hash computation (stringpiece.h:393)
unsigned-integer-overflow:google/protobuf/stubs/stringpiece.h

View File

@@ -168,7 +168,7 @@ decode(void* dest, char const* src, std::size_t len)
break;
++in;
c4[i] = v;
if (++i == 4)
if (++i; i == 4)
{
c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);

View File

@@ -729,21 +729,18 @@ Reader::decodeUnicodeCodePoint(Token& token, Location& current, Location end, un
unsigned int surrogatePair;
if (*(current++) == '\\' && *(current++) == 'u')
{
if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair))
{
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
}
else
return false;
}
else
if (*current != '\\' || *(current + 1) != 'u')
return addError(
"expecting another \\u token to begin the second half of a "
"unicode surrogate pair",
"expecting another \\u token to begin the second half of a unicode surrogate pair",
token,
current);
current += 2; // skip two characters checked above
if (!decodeUnicodeEscapeSequence(token, current, end, surrogatePair))
return false;
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
}
return true;

View File

@@ -319,7 +319,7 @@ StyledWriter::writeValue(Value const& value)
document_ += " : ";
writeValue(childValue);
if (++it == members.end())
if (++it; it == members.end())
break;
document_ += ",";

View File

@@ -74,8 +74,10 @@ BookDirs::const_iterator::operator++()
XRPL_ASSERT(index_ != zero, "xrpl::BookDirs::const_iterator::operator++ : nonzero index");
if (!cdirNext(*view_, cur_key_, sle_, entry_, index_))
{
if (index_ != 0 ||
(cur_key_ = view_->succ(++cur_key_, next_quality_).value_or(zero)) == zero)
if (index_ == 0)
cur_key_ = view_->succ(++cur_key_, next_quality_).value_or(zero);
if (index_ != 0 || cur_key_ == zero)
{
cur_key_ = key_;
entry_ = 0;
@@ -84,9 +86,7 @@ BookDirs::const_iterator::operator++()
else if (!cdirFirst(*view_, cur_key_, sle_, entry_, index_))
{
// LCOV_EXCL_START
UNREACHABLE(
"xrpl::BookDirs::const_iterator::operator++ : directory is "
"empty");
UNREACHABLE("xrpl::BookDirs::const_iterator::operator++ : directory is empty");
// LCOV_EXCL_STOP
}
}

View File

@@ -23,6 +23,9 @@ STBase::STBase(SField const& n) : fName(&n)
STBase&
STBase::operator=(STBase const& t)
{
if (this == &t)
return *this;
if (!fName->isUseful())
fName = t.fName;
return *this;

View File

@@ -39,6 +39,9 @@ Consumer::~Consumer()
Consumer&
Consumer::operator=(Consumer const& other)
{
if (this == &other)
return *this;
// remove old ref
if (m_logic && m_entry)
m_logic->release(*m_entry);

View File

@@ -1,5 +1,4 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/mulDiv.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/CredentialHelpers.h>
#include <xrpl/ledger/View.h>

View File

@@ -491,7 +491,7 @@ SetAccount::doApply()
if (messageKey.empty())
{
JLOG(j_.debug()) << "set message key";
JLOG(j_.debug()) << "clear message key";
sle->makeFieldAbsent(sfMessageKey);
}
else

View File

@@ -1614,13 +1614,7 @@ class Delegate_test : public beast::unit_test::suite
{"CredentialDelete", featureCredentials},
{"NFTokenModify", featureDynamicNFT},
{"PermissionedDomainSet", featurePermissionedDomains},
{"PermissionedDomainDelete", featurePermissionedDomains},
{"VaultCreate", featureSingleAssetVault},
{"VaultSet", featureSingleAssetVault},
{"VaultDelete", featureSingleAssetVault},
{"VaultDeposit", featureSingleAssetVault},
{"VaultWithdraw", featureSingleAssetVault},
{"VaultClawback", featureSingleAssetVault}};
{"PermissionedDomainDelete", featurePermissionedDomains}};
// Can not delegate tx if any required feature disabled.
{
@@ -1660,6 +1654,56 @@ class Delegate_test : public beast::unit_test::suite
}
}
void
testTxDelegableCount()
{
testcase("Delegable Transactions Completeness");
std::size_t delegableCount = 0;
#pragma push_macro("TRANSACTION")
#undef TRANSACTION
#define TRANSACTION(tag, value, name, delegable, ...) \
if (delegable == xrpl::delegable) \
{ \
delegableCount++; \
}
#include <xrpl/protocol/detail/transactions.macro>
#undef TRANSACTION
#pragma pop_macro("TRANSACTION")
// ====================================================================
// IMPORTANT NOTICE:
//
// If this test fails, it indicates that the 'Delegation::delegable' status
// in transactions.macro has been changed. Delegation allows accounts to act
// on behalf of others, significantly increasing the security surface.
//
//
// To ENSURE any added transaction is safe and compatible with delegation:
//
// 1. Verify that the transaction is intended to be delegable.
// 2. Every standard test case for that transaction MUST be
// duplicated and verified for a Delegated context.
// 3. Ensure that Fee, Reserve, and Signing are correctly handled.
//
// DO NOT modify expectedDelegableCount unless all scenarios, including
// edge cases, have been fully tested and verified.
// ====================================================================
std::size_t const expectedDelegableCount = 75;
BEAST_EXPECTS(
delegableCount == expectedDelegableCount,
"\n[SECURITY] New delegable transaction detected!"
"\n Expected: " +
std::to_string(expectedDelegableCount) +
"\n Actual: " + std::to_string(delegableCount) +
"\n Action: Verify security requirements to interact with Delegation feature");
}
void
run() override
{
@@ -1684,6 +1728,7 @@ class Delegate_test : public beast::unit_test::suite
testMultiSignQuorumNotMet();
testPermissionValue(all);
testTxRequireFeatures(all);
testTxDelegableCount();
}
};
BEAST_DEFINE_TESTSUITE(Delegate, app, xrpl);

View File

@@ -1128,9 +1128,27 @@ struct LedgerReplayer_test : public beast::unit_test::suite
BEAST_EXPECT(net.client.waitAndCheckStatus(
finalHash, totalReplay, TaskStatus::Completed, TaskStatus::Completed, deltaStatuses));
// sweep
net.client.replayer.sweep();
BEAST_EXPECT(net.client.countsAsExpected(0, 0, 0));
// sweep() cleans up skipLists_ and deltas_ by removing entries whose
// weak_ptr can no longer be locked. Those weak_ptrs expire only when the
// last shared_ptr holder releases the sub-task. The sole owner is the
// LedgerReplayTask, but a JobQueue worker thread may still hold a
// temporary shared_ptr to a sub-task (from wptr.lock()) while executing
// the timer job that drove the task to completion. If sweep() runs before
// that thread unwinds, the weak_ptr is still lockable and the map entry
// is not removed. We retry until the worker thread finishes.
auto waitForSweep = [&net]() {
for (auto numAttempts = 0; numAttempts < 20; ++numAttempts)
{
net.client.replayer.sweep();
if (net.client.countsAsExpected(0, 0, 0))
{
return true;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return false;
};
BEAST_EXPECT(waitForSweep());
}
void

View File

@@ -4500,131 +4500,6 @@ class Vault_test : public beast::unit_test::suite
}
}
void
testDelegate()
{
using namespace test::jtx;
Env env(*this, testable_amendments());
Account alice{"alice"};
Account bob{"bob"};
Account carol{"carol"};
struct CaseArgs
{
PrettyAsset asset = xrpIssue();
};
auto const xrpBalance = [this](
Env const& env, Account const& account) -> std::optional<long> {
auto sle = env.le(keylet::account(account.id()));
if (BEAST_EXPECT(sle != nullptr))
return sle->getFieldAmount(sfBalance).xrp().drops();
return std::nullopt;
};
auto testCase = [&, this](auto test, CaseArgs args = {}) {
Env env{*this, testable_amendments() | featureSingleAssetVault};
Vault vault{env};
// use different initial amount to distinguish the source balance
env.fund(XRP(10000), alice);
env.fund(XRP(20000), bob);
env.fund(XRP(30000), carol);
env.close();
env(delegate::set(
carol,
alice,
{"Payment",
"VaultCreate",
"VaultSet",
"VaultDelete",
"VaultDeposit",
"VaultWithdraw",
"VaultClawback"}));
test(env, vault, args.asset);
};
testCase([&, this](Env& env, Vault& vault, PrettyAsset const& asset) {
testcase("delegated vault creation");
auto startBalance = xrpBalance(env, carol);
if (!BEAST_EXPECT(startBalance.has_value()))
return;
auto [tx, keylet] = vault.create({.owner = carol, .asset = asset});
env(tx, delegate::as(alice));
env.close();
BEAST_EXPECT(xrpBalance(env, carol) == *startBalance);
});
testCase([&, this](Env& env, Vault& vault, PrettyAsset const& asset) {
testcase("delegated deposit and withdrawal");
auto [tx, keylet] = vault.create({.owner = carol, .asset = asset});
env(tx);
env.close();
auto const amount = 1513;
auto const baseFee = env.current()->fees().base;
auto startBalance = xrpBalance(env, carol);
if (!BEAST_EXPECT(startBalance.has_value()))
return;
tx = vault.deposit({.depositor = carol, .id = keylet.key, .amount = asset(amount)});
env(tx, delegate::as(alice));
env.close();
BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount);
tx =
vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(amount - 1)});
env(tx, delegate::as(alice));
env.close();
BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - 1);
tx = vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(1)});
env(tx);
env.close();
BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - baseFee);
});
testCase([&, this](Env& env, Vault& vault, PrettyAsset const& asset) {
testcase("delegated withdrawal same as base fee and deletion");
auto [tx, keylet] = vault.create({.owner = carol, .asset = asset});
env(tx);
env.close();
auto const amount = 25537;
auto const baseFee = env.current()->fees().base;
auto startBalance = xrpBalance(env, carol);
if (!BEAST_EXPECT(startBalance.has_value()))
return;
tx = vault.deposit({.depositor = carol, .id = keylet.key, .amount = asset(amount)});
env(tx);
env.close();
BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount - baseFee);
tx = vault.withdraw({.depositor = carol, .id = keylet.key, .amount = asset(baseFee)});
env(tx, delegate::as(alice));
env.close();
BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - amount);
tx = vault.withdraw(
{.depositor = carol, .id = keylet.key, .amount = asset(amount - baseFee)});
env(tx, delegate::as(alice));
env.close();
BEAST_EXPECT(xrpBalance(env, carol) == *startBalance - baseFee);
tx = vault.del({.owner = carol, .id = keylet.key});
env(tx, delegate::as(alice));
env.close();
});
}
void
testVaultClawbackBurnShares()
{
@@ -5374,7 +5249,6 @@ public:
testFailedPseudoAccount();
testScaleIOU();
testRPC();
testDelegate();
testVaultClawbackBurnShares();
testVaultClawbackAssets();
testAssetsMaximum();

View File

@@ -39,9 +39,9 @@ public:
a = std::move(b);
Account c(std::move(a));
}
Account("alice");
Account("alice", KeyType::secp256k1);
Account("alice", KeyType::ed25519);
Account("alice"); // NOLINT(bugprone-unused-raii)
Account("alice", KeyType::secp256k1); // NOLINT(bugprone-unused-raii)
Account("alice", KeyType::ed25519); // NOLINT(bugprone-unused-raii)
auto const gw = Account("gw");
[](AccountID) {}(gw);
auto const USD = gw["USD"];
@@ -56,11 +56,11 @@ public:
{
using namespace jtx;
PrettyAmount(0);
PrettyAmount(1);
PrettyAmount(0u);
PrettyAmount(1u);
PrettyAmount(-1);
PrettyAmount(0); // NOLINT(bugprone-unused-raii)
PrettyAmount(1); // NOLINT(bugprone-unused-raii)
PrettyAmount(0u); // NOLINT(bugprone-unused-raii)
PrettyAmount(1u); // NOLINT(bugprone-unused-raii)
PrettyAmount(-1); // NOLINT(bugprone-unused-raii)
static_assert(!std::is_trivially_constructible<PrettyAmount, char>::value, "");
static_assert(!std::is_trivially_constructible<PrettyAmount, unsigned char>::value, "");
static_assert(!std::is_trivially_constructible<PrettyAmount, short>::value, "");

View File

@@ -802,13 +802,17 @@ public:
* return {true, true} if received numReplies replies and also
* received a tx with the account_history_tx_first == true
*/
auto getTxHash = [](WSClient& wsc, IdxHashVec& v, int numReplies) -> std::pair<bool, bool> {
auto getTxHash = [](WSClient& wsc,
IdxHashVec& v,
int numReplies,
std::chrono::milliseconds timeout =
std::chrono::milliseconds{5000}) -> std::pair<bool, bool> {
bool first_flag = false;
for (int i = 0; i < numReplies; ++i)
{
std::uint32_t idx{0};
auto reply = wsc.getMsg(100ms);
auto reply = wsc.getMsg(timeout);
if (reply)
{
auto r = *reply;
@@ -982,7 +986,7 @@ public:
BEAST_EXPECT(goodSubRPC(jv));
sendPayments(env, env.master, alice, 1, 1);
r = getTxHash(*wscTxHistory, vec, 1);
r = getTxHash(*wscTxHistory, vec, 1, 10ms);
BEAST_EXPECT(!r.first);
}
{
@@ -1001,7 +1005,7 @@ public:
return;
IdxHashVec genesisFullHistoryVec;
BEAST_EXPECT(env.syncClose());
if (!BEAST_EXPECT(!getTxHash(*wscTxHistory, genesisFullHistoryVec, 1).first))
if (!BEAST_EXPECT(!getTxHash(*wscTxHistory, genesisFullHistoryVec, 1, 10ms).first))
return;
/*
@@ -1161,7 +1165,7 @@ public:
{
// take out existing txns from the stream
IdxHashVec tempVec;
getTxHash(*ws, tempVec, 100);
getTxHash(*ws, tempVec, 100, 1000ms);
}
auto count = mixedPayments();
@@ -1195,7 +1199,7 @@ public:
{
// take out existing txns from the stream
IdxHashVec tempVec;
getTxHash(*wscLong, tempVec, 100);
getTxHash(*wscLong, tempVec, 100, 1000ms);
}
// repeat the payments many rounds

View File

@@ -98,8 +98,12 @@ LedgerReplayer::createDeltas(std::shared_ptr<LedgerReplayTask> task)
{
auto skipListItem =
std::find(parameter.skipList_.begin(), parameter.skipList_.end(), parameter.startHash_);
if (skipListItem == parameter.skipList_.end() ||
++skipListItem == parameter.skipList_.end())
auto const wasLast = skipListItem == parameter.skipList_.end();
if (not wasLast)
++skipListItem;
auto const isLast = skipListItem == parameter.skipList_.end();
if (wasLast || isLast)
{
JLOG(j_.error()) << "Task parameter error when creating deltas "
<< parameter.finishHash_;