Compare commits

..

41 Commits

Author SHA1 Message Date
JCW
62dbd3d1d3 Cleanup 2025-06-02 18:39:02 +01:00
JCW
4565e97af9 Cleanup 2025-06-02 18:29:41 +01:00
JCW
2169abc438 Cleanup 2025-06-02 17:04:47 +01:00
JCW
404ea567ef Cleanup 2025-06-02 17:04:20 +01:00
JCW
f59a3c81c1 Cleanup 2025-06-02 16:57:07 +01:00
JCW
c65b13c730 Cleanup 2025-06-02 16:56:33 +01:00
JCW
3e13bd036e Cleanup 2025-06-02 16:43:00 +01:00
JCW
0b29ff0bf7 Cleanup 2025-06-02 13:17:13 +01:00
JCW
af284bf23f Buffer data 2025-06-02 10:07:44 +01:00
JCW
47a73e6b0f Buffer data 2025-06-02 09:37:04 +01:00
JCW
c3a7ae3730 Fix build error 2025-05-30 13:40:50 +01:00
JCW
ac5ff24323 Temporarily disbable some unit tests. To renable and investigate in the future 2025-05-30 13:28:13 +01:00
JCW
4ec90d7c73 Disable profiling 2025-05-30 11:56:17 +01:00
JCW
0a21224c98 optimise 2025-05-30 11:27:03 +01:00
JCW
881f5d9d71 Disable performance counters 2025-05-30 10:58:48 +01:00
JCW
780816a2ec Fix build errors 2025-05-30 10:31:35 +01:00
JCW
5e49158258 Fix build errors 2025-05-30 10:09:31 +01:00
JCW
b82ec378c9 Fix build errors 2025-05-30 10:09:10 +01:00
JCW
09bcaaa035 salt based bit shift hash 2025-05-30 10:04:33 +01:00
JCW
775e8e4af7 Test 2025-05-28 16:39:01 +01:00
JCW
0dc0bc42ba Test 2025-05-28 15:42:28 +01:00
JCW
41d9d9528c Add cpu counter 2025-05-28 15:07:24 +01:00
JCW
4483921eeb Add cpu counter 2025-05-28 12:34:02 +01:00
JCW
28c37ba244 Add cpu counter 2025-05-28 12:32:43 +01:00
JCW
e2a83c9205 Add cpu counter 2025-05-28 12:31:49 +01:00
JCW
6379bf1953 Add cpu counter 2025-05-28 12:30:33 +01:00
JCW
3e71229185 Add cpu counter 2025-05-28 11:45:53 +01:00
JCW
d2ee6f0c9d Add cpu counter 2025-05-28 11:21:54 +01:00
JCW
13410f2a76 Add cpu counter 2025-05-28 11:19:45 +01:00
JCW
e11e805c34 update 2025-05-22 09:47:16 +01:00
JCW
09abafd8d6 update 2025-05-22 08:52:49 +01:00
JCW
0f9f3a0834 update 2025-05-22 08:34:43 +01:00
JCW
f62e9c0ba5 Modify profiler 2025-05-21 17:39:19 +01:00
JCW
0590c13de3 Modify profiler 2025-05-21 17:38:13 +01:00
JCW
95b9a77126 Update profiler 2025-05-21 16:54:39 +01:00
JCW
f85432aee4 Add profiler 2025-05-21 16:14:00 +01:00
Michael Legleux
a6f97ed7b3 Set version to 2.5.0-b1 2025-05-21 16:14:00 +01:00
Valentin Balaschenko
092c37f52e Fix: Resolve slow test on macOS pipeline (#5392)
Using std::barrier performs extremely poorly (~1 hour vs ~1 minute to run the test suite) in certain macOS environments.
To unblock our macOS CI pipeline, std::barrier has been replaced with a custom mutex-based barrier (Barrier) that significantly improves performance without compromising correctness.
2025-05-21 16:14:00 +01:00
brettmollin
a3651b417c fix: Update validators-example.txt fix xrplf example URL (#5384) 2025-05-21 16:14:00 +01:00
Jingchen
00697a49fe fix: Ensure that coverage file generation is atomic. (#5426)
Running unit tests in parallel and multiple threads can write into one file can corrupt output files, and then gcovr won't be able to parse the corrupted file. This change adds -fprofile-update=atomic as instructed by https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68080.
2025-05-21 16:14:00 +01:00
Bronek Kozicki
6d730f9ffb Add codecov badge, raised .codecov.yml thresholds 2025-05-12 14:24:21 +01:00
528 changed files with 15939 additions and 44899 deletions

2
.github/CODEOWNERS vendored
View File

@@ -2,7 +2,7 @@
* *
# Require the rpc-reviewers team to review changes to the rpc code. # Require the rpc-reviewers team to review changes to the rpc code.
include/xrpl/protocol/ @xrplf/rpc-reviewers include/libxrpl/protocol/ @xrplf/rpc-reviewers
src/libxrpl/protocol/ @xrplf/rpc-reviewers src/libxrpl/protocol/ @xrplf/rpc-reviewers
src/xrpld/rpc/ @xrplf/rpc-reviewers src/xrpld/rpc/ @xrplf/rpc-reviewers
src/xrpld/app/misc/ @xrplf/rpc-reviewers src/xrpld/app/misc/ @xrplf/rpc-reviewers

View File

@@ -6,29 +6,36 @@ inputs:
runs: runs:
using: composite using: composite
steps: steps:
- name: unlock Conan
shell: bash
run: conan remove --locks
- name: export custom recipes - name: export custom recipes
shell: bash shell: bash
run: | run: |
conan export --version 1.1.10 external/snappy conan config set general.revisions_enabled=1
conan export --version 4.0.3 external/soci conan export external/snappy snappy/1.1.10@
conan export external/rocksdb rocksdb/9.7.3@
conan export external/soci soci/4.0.3@
conan export external/nudb nudb/2.0.8@
- name: add Ripple Conan remote - name: add Ripple Conan remote
if: env.CONAN_URL != ''
shell: bash shell: bash
run: | run: |
if conan remote list | grep -q "ripple"; then conan remote list
conan remote remove ripple conan remote remove ripple || true
echo "Removed conan remote ripple" # Do not quote the URL. An empty string will be accepted (with
fi # a non-fatal warning), but a missing argument will not.
conan remote add --index 0 ripple "${CONAN_URL}" conan remote add ripple ${{ env.CONAN_URL }} --insert 0
echo "Added conan remote ripple at ${CONAN_URL}"
- name: try to authenticate to Ripple Conan remote - name: try to authenticate to Ripple Conan remote
if: env.CONAN_LOGIN_USERNAME_RIPPLE != '' && env.CONAN_PASSWORD_RIPPLE != ''
id: remote id: remote
shell: bash shell: bash
run: | run: |
echo "Authenticating to ripple remote..." # `conan user` implicitly uses the environment variables
conan remote auth ripple --force # CONAN_LOGIN_USERNAME_<REMOTE> and CONAN_PASSWORD_<REMOTE>.
conan remote list-users # https://docs.conan.io/1/reference/commands/misc/user.html#using-environment-variables
# https://docs.conan.io/1/reference/env_vars.html#conan-login-username-conan-login-username-remote-name
# https://docs.conan.io/1/reference/env_vars.html#conan-password-conan-password-remote-name
echo outcome=$(conan user --remote ripple --password >&2 \
&& echo success || echo failure) | tee ${GITHUB_OUTPUT}
- name: list missing binaries - name: list missing binaries
id: binaries id: binaries
shell: bash shell: bash
@@ -44,7 +51,7 @@ runs:
conan install \ conan install \
--output-folder . \ --output-folder . \
--build missing \ --build missing \
--options:host "&:tests=True" \ --options tests=True \
--options:host "&:xrpld=True" \ --options xrpld=True \
--settings:all build_type=${{ inputs.configuration }} \ --settings build_type=${{ inputs.configuration }} \
.. ..

View File

@@ -9,25 +9,24 @@ jobs:
check: check:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }} if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
container: ghcr.io/xrplf/ci/tools-rippled-clang-format env:
CLANG_VERSION: 18
steps: steps:
# For jobs running in containers, $GITHUB_WORKSPACE and ${{ github.workspace }} might not be the
# same directory. The actions/checkout step is *supposed* to checkout into $GITHUB_WORKSPACE and
# then add it to safe.directory (see instructions at https://github.com/actions/checkout)
# but that's apparently not happening for some container images. We can't be sure what is actually
# happening, so let's pre-emptively add both directories to safe.directory. There's a
# Github issue opened in 2022 and not resolved in 2025 https://github.com/actions/runner/issues/2058 ¯\_(ツ)_/¯
- run: |
git config --global --add safe.directory $GITHUB_WORKSPACE
git config --global --add safe.directory ${{ github.workspace }}
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Format first-party sources - name: Install clang-format
run: | run: |
clang-format --version codename=$( lsb_release --codename --short )
find include src tests -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format -i {} + sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null <<EOF
deb http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
deb-src http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-${CLANG_VERSION} main
EOF
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add
sudo apt-get update
sudo apt-get install clang-format-${CLANG_VERSION}
- name: Format first-party sources
run: find include src tests -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
- name: Check for differences - name: Check for differences
id: assert id: assert
shell: bash
run: | run: |
set -o pipefail set -o pipefail
git diff --exit-code | tee "clang-format.patch" git diff --exit-code | tee "clang-format.patch"
@@ -59,6 +58,6 @@ jobs:
in your repo, commit, and push. in your repo, commit, and push.
run: | run: |
echo "${PREAMBLE}" echo "${PREAMBLE}"
clang-format --version clang-format-${CLANG_VERSION} --version
echo "${SUGGESTION}" echo "${SUGGESTION}"
exit 1 exit 1

View File

@@ -10,7 +10,7 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
documentation: job:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write

View File

@@ -1,6 +1,6 @@
name: Check libXRPL compatibility with Clio name: Check libXRPL compatibility with Clio
env: env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/dev CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }} CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }}
CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }} CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }}
on: on:

View File

@@ -15,18 +15,6 @@ on:
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
# This part of Conan configuration is specific to this workflow only; we do not want
# to pollute conan/profiles directory with settings which might not work for others
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/dev
CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }}
CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }}
CONAN_GLOBAL_CONF: |
core.download:parallel={{os.cpu_count()}}
core.upload:parallel={{os.cpu_count()}}
tools.build:jobs={{ (os.cpu_count() * 4/5) | int }}
tools.build:verbosity=verbose
tools.compilation:verbosity=verbose
jobs: jobs:
@@ -40,22 +28,23 @@ jobs:
- Ninja - Ninja
configuration: configuration:
- Release - Release
runs-on: [self-hosted, macOS, mac-runner-m1] runs-on: [self-hosted, macOS]
env: env:
# The `build` action requires these variables. # The `build` action requires these variables.
build_dir: .build build_dir: .build
NUM_PROCESSORS: 12 NUM_PROCESSORS: 12
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: install Conan - name: install Conan
run: | run: |
brew install conan brew install conan@1
echo '/opt/homebrew/opt/conan@1/bin' >> $GITHUB_PATH
- name: install Ninja - name: install Ninja
if: matrix.generator == 'Ninja' if: matrix.generator == 'Ninja'
run: brew install ninja run: brew install ninja
- name: install python - name: install python
run: | run: |
if which python > /dev/null 2>&1; then if which python > /dev/null 2>&1; then
echo "Python executable exists" echo "Python executable exists"
else else
@@ -87,26 +76,14 @@ jobs:
clang --version clang --version
- name: configure Conan - name: configure Conan
run : | run : |
echo "${CONAN_GLOBAL_CONF}" >> $(conan config home)/global.conf conan profile new default --detect || true
conan config install conan/profiles/ -tf $(conan config home)/profiles/ conan profile update settings.compiler.cppstd=20 default
conan profile show
- name: export custom recipes
shell: bash
run: |
conan export --version 1.1.10 external/snappy
conan export --version 4.0.3 external/soci
- name: add Ripple Conan remote
if: env.CONAN_URL != ''
shell: bash
run: |
if conan remote list | grep -q "ripple"; then
conan remote remove ripple
echo "Removed conan remote ripple"
fi
conan remote add --index 0 ripple "${CONAN_URL}"
echo "Added conan remote ripple at ${CONAN_URL}"
- name: build dependencies - name: build dependencies
uses: ./.github/actions/dependencies uses: ./.github/actions/dependencies
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }}
CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }}
with: with:
configuration: ${{ matrix.configuration }} configuration: ${{ matrix.configuration }}
- name: build - name: build
@@ -119,7 +96,4 @@ jobs:
run: | run: |
n=$(nproc) n=$(nproc)
echo "Using $n test jobs" echo "Using $n test jobs"
${build_dir}/rippled --unittest --unittest-jobs $n
cd ${build_dir}
./rippled --unittest --unittest-jobs $n
ctest -j $n --output-on-failure

View File

@@ -16,19 +16,6 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
# This part of Conan configuration is specific to this workflow only; we do not want
# to pollute conan/profiles directory with settings which might not work for others
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/dev
CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }}
CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }}
CONAN_GLOBAL_CONF: |
core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }}
tools.build:jobs={{ (os.cpu_count() * 4/5) | int }}
tools.build:verbosity=verbose
tools.compilation:verbosity=verbose
# This workflow has multiple job matrixes. # This workflow has multiple job matrixes.
# They can be considered phases because most of the matrices ("test", # They can be considered phases because most of the matrices ("test",
# "coverage", "conan", ) depend on the first ("dependencies"). # "coverage", "conan", ) depend on the first ("dependencies").
@@ -67,45 +54,59 @@ jobs:
- Release - Release
include: include:
- compiler: gcc - compiler: gcc
compiler_version: 12 profile:
distro: ubuntu version: 11
codename: jammy cc: /usr/bin/gcc
cxx: /usr/bin/g++
- compiler: clang - compiler: clang
compiler_version: 16 profile:
distro: debian version: 14
codename: bookworm cc: /usr/bin/clang-14
cxx: /usr/bin/clang++-14
runs-on: [self-hosted, heavy] runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/${{ matrix.distro }}-${{ matrix.codename }}:${{ matrix.compiler }}-${{ matrix.compiler_version }} container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
env: env:
build_dir: .build build_dir: .build
steps: steps:
- name: upgrade conan
run: |
pip install --upgrade "conan<2"
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: check environment - name: check environment
run: | run: |
echo ${PATH} | tr ':' '\n' echo ${PATH} | tr ':' '\n'
lsb_release -a || true lsb_release -a || true
${{ matrix.compiler }}-${{ matrix.compiler_version }} --version ${{ matrix.profile.cc }} --version
conan --version conan --version
cmake --version cmake --version
env | sort env | sort
- name: configure Conan - name: configure Conan
run: | run: |
echo "${CONAN_GLOBAL_CONF}" >> $(conan config home)/global.conf conan profile new default --detect
conan config install conan/profiles/ -tf $(conan config home)/profiles/ conan profile update settings.compiler.cppstd=20 default
conan profile show conan profile update settings.compiler=${{ matrix.compiler }} default
conan profile update settings.compiler.version=${{ matrix.profile.version }} default
conan profile update settings.compiler.libcxx=libstdc++11 default
conan profile update env.CC=${{ matrix.profile.cc }} default
conan profile update env.CXX=${{ matrix.profile.cxx }} default
conan profile update conf.tools.build:compiler_executables='{"c": "${{ matrix.profile.cc }}", "cpp": "${{ matrix.profile.cxx }}"}' default
- name: archive profile - name: archive profile
# Create this archive before dependencies are added to the local cache. # Create this archive before dependencies are added to the local cache.
run: tar -czf conan.tar.gz -C ${CONAN_HOME} . run: tar -czf conan.tar -C ~/.conan .
- name: build dependencies - name: build dependencies
uses: ./.github/actions/dependencies uses: ./.github/actions/dependencies
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }}
CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }}
with: with:
configuration: ${{ matrix.configuration }} configuration: ${{ matrix.configuration }}
- name: upload archive - name: upload archive
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 uses: actions/upload-artifact@v4
with: with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
path: conan.tar.gz path: conan.tar
if-no-files-found: error if-no-files-found: error
test: test:
@@ -120,32 +121,26 @@ jobs:
configuration: configuration:
- Debug - Debug
- Release - Release
include:
- compiler: gcc
compiler_version: 12
distro: ubuntu
codename: jammy
- compiler: clang
compiler_version: 16
distro: debian
codename: bookworm
cmake-args: cmake-args:
- -
- "-Dunity=ON" - "-Dunity=ON"
needs: dependencies needs: dependencies
runs-on: [self-hosted, heavy] runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/${{ matrix.distro }}-${{ matrix.codename }}:${{ matrix.compiler }}-${{ matrix.compiler_version }} container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
env: env:
build_dir: .build build_dir: .build
steps: steps:
- name: upgrade conan
run: |
pip install --upgrade "conan<2"
- name: download cache - name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 uses: actions/download-artifact@v4
with: with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
- name: extract cache - name: extract cache
run: | run: |
mkdir -p ${CONAN_HOME} mkdir -p ~/.conan
tar -xzf conan.tar.gz -C ${CONAN_HOME} tar -xzf conan.tar -C ~/.conan
- name: check environment - name: check environment
run: | run: |
env | sort env | sort
@@ -153,9 +148,11 @@ jobs:
conan --version conan --version
cmake --version cmake --version
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: dependencies - name: dependencies
uses: ./.github/actions/dependencies uses: ./.github/actions/dependencies
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
with: with:
configuration: ${{ matrix.configuration }} configuration: ${{ matrix.configuration }}
- name: build - name: build
@@ -164,21 +161,9 @@ jobs:
generator: Ninja generator: Ninja
configuration: ${{ matrix.configuration }} configuration: ${{ matrix.configuration }}
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}" cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
- name: check linking
run: |
cd ${build_dir}
ldd ./rippled
if [ "$(ldd ./rippled | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then
echo 'The binary is statically linked.'
else
echo 'The binary is dynamically linked.'
exit 1
fi
- name: test - name: test
run: | run: |
cd ${build_dir} ${build_dir}/rippled --unittest --unittest-jobs $(nproc)
./rippled --unittest --unittest-jobs $(nproc)
ctest -j $(nproc) --output-on-failure
reference-fee-test: reference-fee-test:
strategy: strategy:
@@ -195,18 +180,21 @@ jobs:
- "-DUNIT_TEST_REFERENCE_FEE=1000" - "-DUNIT_TEST_REFERENCE_FEE=1000"
needs: dependencies needs: dependencies
runs-on: [self-hosted, heavy] runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12 container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
env: env:
build_dir: .build build_dir: .build
steps: steps:
- name: upgrade conan
run: |
pip install --upgrade "conan<2"
- name: download cache - name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 uses: actions/download-artifact@v4
with: with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
- name: extract cache - name: extract cache
run: | run: |
mkdir -p ${CONAN_HOME} mkdir -p ~/.conan
tar -xzf conan.tar.gz -C ${CONAN_HOME} tar -xzf conan.tar -C ~/.conan
- name: check environment - name: check environment
run: | run: |
env | sort env | sort
@@ -214,9 +202,11 @@ jobs:
conan --version conan --version
cmake --version cmake --version
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: dependencies - name: dependencies
uses: ./.github/actions/dependencies uses: ./.github/actions/dependencies
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
with: with:
configuration: ${{ matrix.configuration }} configuration: ${{ matrix.configuration }}
- name: build - name: build
@@ -227,9 +217,7 @@ jobs:
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}" cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
- name: test - name: test
run: | run: |
cd ${build_dir} ${build_dir}/rippled --unittest --unittest-jobs $(nproc)
./rippled --unittest --unittest-jobs $(nproc)
ctest -j $(nproc) --output-on-failure
coverage: coverage:
strategy: strategy:
@@ -243,18 +231,23 @@ jobs:
- Debug - Debug
needs: dependencies needs: dependencies
runs-on: [self-hosted, heavy] runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12 container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
env: env:
build_dir: .build build_dir: .build
steps: steps:
- name: upgrade conan
run: |
pip install --upgrade "conan<2"
- name: download cache - name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 uses: actions/download-artifact@v4
with: with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }} name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
- name: extract cache - name: extract cache
run: | run: |
mkdir -p ${CONAN_HOME} mkdir -p ~/.conan
tar -xzf conan.tar.gz -C ${CONAN_HOME} tar -xzf conan.tar -C ~/.conan
- name: install gcovr
run: pip install "gcovr>=7,<9"
- name: check environment - name: check environment
run: | run: |
echo ${PATH} | tr ':' '\n' echo ${PATH} | tr ':' '\n'
@@ -262,11 +255,13 @@ jobs:
cmake --version cmake --version
gcovr --version gcovr --version
env | sort env | sort
ls ${CONAN_HOME} ls ~/.conan
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: dependencies - name: dependencies
uses: ./.github/actions/dependencies uses: ./.github/actions/dependencies
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
with: with:
configuration: ${{ matrix.configuration }} configuration: ${{ matrix.configuration }}
- name: build - name: build
@@ -288,7 +283,7 @@ jobs:
run: | run: |
mv "${build_dir}/coverage.xml" ./ mv "${build_dir}/coverage.xml" ./
- name: archive coverage report - name: archive coverage report
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 uses: actions/upload-artifact@v4
with: with:
name: coverage.xml name: coverage.xml
path: coverage.xml path: coverage.xml
@@ -310,23 +305,22 @@ jobs:
conan: conan:
needs: dependencies needs: dependencies
runs-on: [self-hosted, heavy] runs-on: [self-hosted, heavy]
container: container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
image: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
env: env:
build_dir: .build build_dir: .build
platform: linux
compiler: gcc
compiler_version: 12
configuration: Release configuration: Release
steps: steps:
- name: upgrade conan
run: |
pip install --upgrade "conan<2"
- name: download cache - name: download cache
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 uses: actions/download-artifact@v4
with: with:
name: ${{ env.platform }}-${{ env.compiler }}-${{ env.configuration }} name: linux-gcc-${{ env.configuration }}
- name: extract cache - name: extract cache
run: | run: |
mkdir -p ${CONAN_HOME} mkdir -p ~/.conan
tar -xzf conan.tar.gz -C ${CONAN_HOME} tar -xzf conan.tar -C ~/.conan
- name: check environment - name: check environment
run: | run: |
env | sort env | sort
@@ -334,66 +328,95 @@ jobs:
conan --version conan --version
cmake --version cmake --version
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: dependencies - name: dependencies
uses: ./.github/actions/dependencies uses: ./.github/actions/dependencies
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
with: with:
configuration: ${{ env.configuration }} configuration: ${{ env.configuration }}
- name: export - name: export
run: | run: |
conan export . --version head version=$(conan inspect --raw version .)
reference="xrpl/${version}@local/test"
conan remove -f ${reference} || true
conan export . local/test
echo "reference=${reference}" >> "${GITHUB_ENV}"
- name: build - name: build
run: | run: |
cd tests/conan cd tests/conan
mkdir ${build_dir} && cd ${build_dir} mkdir ${build_dir}
conan install .. \ cd ${build_dir}
--settings:all build_type=${configuration} \ conan install .. --output-folder . \
--output-folder . \ --require-override ${reference} --build missing
--build missing
cmake .. \ cmake .. \
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=./build/${configuration}/generators/conan_toolchain.cmake \ -DCMAKE_TOOLCHAIN_FILE:FILEPATH=./build/${configuration}/generators/conan_toolchain.cmake \
-DCMAKE_BUILD_TYPE=${configuration} -DCMAKE_BUILD_TYPE=${configuration}
cmake --build . cmake --build .
./example | grep '^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+' ./example | grep '^[[:digit:]]\+\.[[:digit:]]\+\.[[:digit:]]\+'
# NOTE we are not using dependencies built above because it lags with
# compiler versions. Instrumentation requires clang version 16 or
# later
instrumentation-build: instrumentation-build:
needs: dependencies if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/debian-bookworm:clang-16
env: env:
build_dir: .build CLANG_RELEASE: 16
strategy:
fail-fast: false
runs-on: [self-hosted, heavy]
container: debian:bookworm
steps: steps:
- name: download cache - name: install prerequisites
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 env:
with: DEBIAN_FRONTEND: noninteractive
name: linux-clang-Debug
- name: extract cache
run: | run: |
mkdir -p ${CONAN_HOME} apt-get update
tar -xzf conan.tar.gz -C ${CONAN_HOME} apt-get install --yes --no-install-recommends \
clang-${CLANG_RELEASE} clang++-${CLANG_RELEASE} \
- name: check environment python3-pip python-is-python3 make cmake git wget
run: | apt-get clean
echo ${PATH} | tr ':' '\n' update-alternatives --install \
conan --version /usr/bin/clang clang /usr/bin/clang-${CLANG_RELEASE} 100 \
cmake --version --slave /usr/bin/clang++ clang++ /usr/bin/clang++-${CLANG_RELEASE}
env | sort update-alternatives --auto clang
ls ${CONAN_HOME} pip install --no-cache --break-system-packages "conan<2"
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: dependencies
uses: ./.github/actions/dependencies
with:
configuration: Debug
- name: prepare environment - name: prepare environment
run: | run: |
mkdir -p ${build_dir} mkdir ${GITHUB_WORKSPACE}/.build
echo "SOURCE_DIR=$(pwd)" >> $GITHUB_ENV echo "SOURCE_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV
echo "BUILD_DIR=$(pwd)/${build_dir}" >> $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 - name: build with instrumentation
run: | run: |
@@ -418,4 +441,3 @@ jobs:
run: | run: |
cd ${BUILD_DIR} cd ${BUILD_DIR}
./rippled -u --unittest-jobs $(( $(nproc)/4 )) ./rippled -u --unittest-jobs $(( $(nproc)/4 ))
ctest -j $(nproc) --output-on-failure

View File

@@ -18,18 +18,6 @@ on:
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
# This part of Conan configuration is specific to this workflow only; we do not want
# to pollute conan/profiles directory with settings which might not work for others
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/dev
CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }}
CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }}
CONAN_GLOBAL_CONF: |
core.download:parallel={{os.cpu_count()}}
core.upload:parallel={{os.cpu_count()}}
tools.build:jobs=24
tools.build:verbosity=verbose
tools.compilation:verbosity=verbose
jobs: jobs:
@@ -54,11 +42,11 @@ jobs:
build_dir: .build build_dir: .build
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: choose Python - name: choose Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 uses: actions/setup-python@v5
with: with:
python-version: 3.13 python-version: 3.9
- name: learn Python cache directory - name: learn Python cache directory
id: pip-cache id: pip-cache
shell: bash shell: bash
@@ -66,12 +54,12 @@ jobs:
python -m pip install --upgrade pip python -m pip install --upgrade pip
echo "dir=$(pip cache dir)" | tee ${GITHUB_OUTPUT} echo "dir=$(pip cache dir)" | tee ${GITHUB_OUTPUT}
- name: restore Python cache directory - name: restore Python cache directory
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 uses: actions/cache@v4
with: with:
path: ${{ steps.pip-cache.outputs.dir }} path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-${{ hashFiles('.github/workflows/windows.yml') }} key: ${{ runner.os }}-${{ hashFiles('.github/workflows/windows.yml') }}
- name: install Conan - name: install Conan
run: pip install wheel conan run: pip install wheel 'conan<2'
- name: check environment - name: check environment
run: | run: |
dir env: dir env:
@@ -82,26 +70,17 @@ jobs:
- name: configure Conan - name: configure Conan
shell: bash shell: bash
run: | run: |
echo "${CONAN_GLOBAL_CONF}" >> $(conan config home)/global.conf conan profile new default --detect
conan config install conan/profiles/ -tf $(conan config home)/profiles/ conan profile update settings.compiler.cppstd=20 default
conan profile show conan profile update \
- name: export custom recipes settings.compiler.runtime=MT${{ matrix.configuration.runtime }} \
shell: bash default
run: |
conan export --version 1.1.10 external/snappy
conan export --version 4.0.3 external/soci
- name: add Ripple Conan remote
if: env.CONAN_URL != ''
shell: bash
run: |
if conan remote list | grep -q "ripple"; then
conan remote remove ripple
echo "Removed conan remote ripple"
fi
conan remote add --index 0 ripple "${CONAN_URL}"
echo "Added conan remote ripple at ${CONAN_URL}"
- name: build dependencies - name: build dependencies
uses: ./.github/actions/dependencies uses: ./.github/actions/dependencies
env:
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
CONAN_LOGIN_USERNAME_RIPPLE: ${{ secrets.CONAN_USERNAME }}
CONAN_PASSWORD_RIPPLE: ${{ secrets.CONAN_TOKEN }}
with: with:
configuration: ${{ matrix.configuration.type }} configuration: ${{ matrix.configuration.type }}
- name: build - name: build
@@ -116,6 +95,5 @@ jobs:
shell: bash shell: bash
if: ${{ matrix.configuration.tests }} if: ${{ matrix.configuration.tests }}
run: | run: |
cd ${build_dir}/${{ matrix.configuration.type }} ${build_dir}/${{ matrix.configuration.type }}/rippled --unittest \
./rippled --unittest --unittest-jobs $(nproc) --unittest-jobs $(nproc)
ctest -j $(nproc) --output-on-failure

View File

@@ -1,6 +1,6 @@
# .pre-commit-config.yaml # .pre-commit-config.yaml
repos: repos:
- repo: https://github.com/pre-commit/mirrors-clang-format - repo: https://github.com/pre-commit/mirrors-clang-format
rev: v18.1.8 rev: v18.1.3
hooks: hooks:
- id: clang-format - id: clang-format

View File

@@ -167,18 +167,43 @@ It does not explicitly link the C++ standard library,
which allows you to statically link it with GCC, if you want. which allows you to statically link it with GCC, if you want.
``` ```
# Conan 1.x
conan export external/snappy snappy/1.1.10@
# Conan 2.x # Conan 2.x
conan export --version 1.1.10 external/snappy conan export --version 1.1.10 external/snappy
``` ```
Export our [Conan recipe for RocksDB](./external/rocksdb).
It does not override paths to dependencies when building with Visual Studio.
```
# Conan 1.x
conan export external/rocksdb rocksdb/9.7.3@
# Conan 2.x
conan export --version 9.7.3 external/rocksdb
```
Export our [Conan recipe for SOCI](./external/soci). Export our [Conan recipe for SOCI](./external/soci).
It patches their CMake to correctly import its dependencies. It patches their CMake to correctly import its dependencies.
``` ```
# Conan 1.x
conan export external/soci soci/4.0.3@
# Conan 2.x # Conan 2.x
conan export --version 4.0.3 external/soci conan export --version 4.0.3 external/soci
``` ```
Export our [Conan recipe for NuDB](./external/nudb).
It fixes some source files to add missing `#include`s.
```
# Conan 1.x
conan export external/nudb nudb/2.0.8@
# Conan 2.x
conan export --version 2.0.8 external/nudb
```
### Build and Test ### Build and Test
1. Create a build directory and move into it. 1. Create a build directory and move into it.
@@ -263,7 +288,7 @@ It patches their CMake to correctly import its dependencies.
Single-config generators: Single-config generators:
``` ```
cmake --build . -j $(nproc) cmake --build .
``` ```
Multi-config generators: Multi-config generators:

View File

@@ -132,7 +132,6 @@ test.shamap > xrpl.protocol
test.toplevel > test.csf test.toplevel > test.csf
test.toplevel > xrpl.json test.toplevel > xrpl.json
test.unit_test > xrpl.basics test.unit_test > xrpl.basics
tests.libxrpl > xrpl.basics
xrpl.json > xrpl.basics xrpl.json > xrpl.basics
xrpl.protocol > xrpl.basics xrpl.protocol > xrpl.basics
xrpl.protocol > xrpl.json xrpl.protocol > xrpl.json

View File

@@ -90,11 +90,6 @@ set_target_properties(OpenSSL::SSL PROPERTIES
INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2 INTERFACE_COMPILE_DEFINITIONS OPENSSL_NO_SSL2
) )
set(SECP256K1_INSTALL TRUE) set(SECP256K1_INSTALL TRUE)
set(SECP256K1_BUILD_BENCHMARK FALSE)
set(SECP256K1_BUILD_TESTS FALSE)
set(SECP256K1_BUILD_EXHAUSTIVE_TESTS FALSE)
set(SECP256K1_BUILD_CTIME_TESTS FALSE)
set(SECP256K1_BUILD_EXAMPLES FALSE)
add_subdirectory(external/secp256k1) add_subdirectory(external/secp256k1)
add_library(secp256k1::secp256k1 ALIAS secp256k1) add_library(secp256k1::secp256k1 ALIAS secp256k1)
add_subdirectory(external/ed25519-donna) add_subdirectory(external/ed25519-donna)
@@ -149,8 +144,3 @@ set(PROJECT_EXPORT_SET RippleExports)
include(RippledCore) include(RippledCore)
include(RippledInstall) include(RippledInstall)
include(RippledValidatorKeys) include(RippledValidatorKeys)
if(tests)
include(CTest)
add_subdirectory(src/tests/libxrpl)
endif()

4817
RELEASENOTES.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -83,7 +83,7 @@ To report a qualifying bug, please send a detailed report to:
|Long Key ID | `0xCD49A0AFC57929BE` | |Long Key ID | `0xCD49A0AFC57929BE` |
|Fingerprint | `24E6 3B02 37E0 FA9C 5E96 8974 CD49 A0AF C579 29BE` | |Fingerprint | `24E6 3B02 37E0 FA9C 5E96 8974 CD49 A0AF C579 29BE` |
The full PGP key for this address, which is also available on several key servers (e.g. on [keyserver.ubuntu.com](https://keyserver.ubuntu.com)), is: The full PGP key for this address, which is also available on several key servers (e.g. on [keys.gnupg.net](https://keys.gnupg.net)), is:
``` ```
-----BEGIN PGP PUBLIC KEY BLOCK----- -----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFUwGHYBEAC0wpGpBPkd8W1UdQjg9+cEFzeIEJRaoZoeuJD8mofwI5Ejnjdt mQINBFUwGHYBEAC0wpGpBPkd8W1UdQjg9+cEFzeIEJRaoZoeuJD8mofwI5Ejnjdt

View File

@@ -53,9 +53,9 @@ set(download_script "${CMAKE_BINARY_DIR}/docs/download-cppreference.cmake")
file(WRITE file(WRITE
"${download_script}" "${download_script}"
"file(DOWNLOAD \ "file(DOWNLOAD \
https://github.com/PeterFeicht/cppreference-doc/releases/download/v20250209/html-book-20250209.zip \ http://upload.cppreference.com/mwiki/images/b/b2/html_book_20190607.zip \
${CMAKE_BINARY_DIR}/docs/cppreference.zip \ ${CMAKE_BINARY_DIR}/docs/cppreference.zip \
EXPECTED_HASH MD5=bda585f72fbca4b817b29a3d5746567b \ EXPECTED_HASH MD5=82b3a612d7d35a83e3cb1195a63689ab \
)\n \ )\n \
execute_process( \ execute_process( \
COMMAND \"${CMAKE_COMMAND}\" -E tar -xf cppreference.zip \ COMMAND \"${CMAKE_COMMAND}\" -E tar -xf cppreference.zip \

View File

@@ -2,6 +2,16 @@
convenience variables and sanity checks convenience variables and sanity checks
#]===================================================================] #]===================================================================]
include(ProcessorCount)
if (NOT ep_procs)
ProcessorCount(ep_procs)
if (ep_procs GREATER 1)
# never use more than half of cores for EP builds
math (EXPR ep_procs "${ep_procs} / 2")
message (STATUS "Using ${ep_procs} cores for ExternalProject builds.")
endif ()
endif ()
get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) get_property(is_multiconfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
set (CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) set (CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE)

View File

@@ -18,7 +18,7 @@ if(tests)
endif() endif()
endif() endif()
option(unity "Creates a build using UNITY support in cmake." OFF) option(unity "Creates a build using UNITY support in cmake. This is the default" ON)
if(unity) if(unity)
if(NOT is_ci) if(NOT is_ci)
set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "") set(CMAKE_UNITY_BUILD_BATCH_SIZE 15 CACHE STRING "")

View File

@@ -2,6 +2,7 @@ find_package(Boost 1.82 REQUIRED
COMPONENTS COMPONENTS
chrono chrono
container container
context
coroutine coroutine
date_time date_time
filesystem filesystem
@@ -23,7 +24,7 @@ endif()
target_link_libraries(ripple_boost target_link_libraries(ripple_boost
INTERFACE INTERFACE
Boost::headers Boost::boost
Boost::chrono Boost::chrono
Boost::container Boost::container
Boost::coroutine Boost::coroutine

View File

@@ -1,41 +0,0 @@
include(isolate_headers)
function(xrpl_add_test name)
set(target ${PROJECT_NAME}.test.${name})
file(GLOB_RECURSE sources CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp"
)
add_executable(${target} EXCLUDE_FROM_ALL ${ARGN} ${sources})
isolate_headers(
${target}
"${CMAKE_SOURCE_DIR}"
"${CMAKE_SOURCE_DIR}/tests/${name}"
PRIVATE
)
# Make sure the test isn't optimized away in unity builds
set_target_properties(${target} PROPERTIES
UNITY_BUILD_MODE GROUP
UNITY_BUILD_BATCH_SIZE 0) # Adjust as needed
add_test(NAME ${target} COMMAND ${target})
set_tests_properties(
${target} PROPERTIES
FIXTURES_REQUIRED ${target}_fixture
)
add_test(
NAME ${target}.build
COMMAND
${CMAKE_COMMAND}
--build ${CMAKE_BINARY_DIR}
--config $<CONFIG>
--target ${target}
)
set_tests_properties(${target}.build PROPERTIES
FIXTURES_SETUP ${target}_fixture
)
endfunction()

View File

@@ -1,37 +0,0 @@
{% set os = detect_api.detect_os() %}
{% set arch = detect_api.detect_arch() %}
{% set compiler, version, compiler_exe = detect_api.detect_default_compiler() %}
{% set compiler_version = version %}
{% if os == "Linux" %}
{% set compiler_version = detect_api.default_compiler_version(compiler, version) %}
{% endif %}
[settings]
os={{ os }}
arch={{ arch }}
build_type=Debug
compiler={{compiler}}
compiler.version={{ compiler_version }}
compiler.cppstd=20
{% if os == "Windows" %}
compiler.runtime=static
{% else %}
compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}}
{% endif %}
[conf]
{% if compiler == "clang" and compiler_version >= 19 %}
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %}
{% if compiler == "apple-clang" and compiler_version >= 17 %}
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %}
{% if compiler == "clang" and compiler_version == 16 %}
tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS']
{% endif %}
{% if compiler == "gcc" and compiler_version < 13 %}
tools.build:cxxflags=['-Wno-restrict']
{% endif %}
[tool_requires]
!cmake/*: cmake/[>=3 <4]

View File

@@ -1,4 +1,4 @@
from conan import ConanFile, __version__ as conan_version from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
import re import re
@@ -24,20 +24,18 @@ class Xrpl(ConanFile):
} }
requires = [ requires = [
'date/3.0.3',
'grpc/1.50.1', 'grpc/1.50.1',
'libarchive/3.8.1', 'libarchive/3.7.6',
'nudb/2.0.9', 'nudb/2.0.8',
'openssl/1.1.1w', 'openssl/1.1.1v',
'soci/4.0.3', 'soci/4.0.3',
'xxhash/0.8.2',
'zlib/1.3.1', 'zlib/1.3.1',
] ]
test_requires = [
'doctest/2.4.11',
]
tool_requires = [ tool_requires = [
'protobuf/3.21.12', 'protobuf/3.21.9',
] ]
default_options = { default_options = {
@@ -89,31 +87,26 @@ class Xrpl(ConanFile):
} }
def set_version(self): def set_version(self):
if self.version is None: path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp'
path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp' regex = r'versionString\s?=\s?\"(.*)\"'
regex = r'versionString\s?=\s?\"(.*)\"' with open(path, 'r') as file:
with open(path, encoding='utf-8') as file: matches = (re.search(regex, line) for line in file)
matches = (re.search(regex, line) for line in file) match = next(m for m in matches if m)
match = next(m for m in matches if m) self.version = match.group(1)
self.version = match.group(1)
def configure(self): def configure(self):
if self.settings.compiler == 'apple-clang': if self.settings.compiler == 'apple-clang':
self.options['boost'].visibility = 'global' self.options['boost'].visibility = 'global'
def requirements(self): def requirements(self):
# Conan 2 requires transitive headers to be specified self.requires('boost/1.83.0', force=True)
transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {}
self.requires('boost/1.83.0', force=True, **transitive_headers_opt)
self.requires('date/3.0.4', **transitive_headers_opt)
self.requires('lz4/1.10.0', force=True) self.requires('lz4/1.10.0', force=True)
self.requires('protobuf/3.21.12', force=True) self.requires('protobuf/3.21.9', force=True)
self.requires('sqlite3/3.49.1', force=True) self.requires('sqlite3/3.47.0', force=True)
if self.options.jemalloc: if self.options.jemalloc:
self.requires('jemalloc/5.3.0') self.requires('jemalloc/5.3.0')
if self.options.rocksdb: if self.options.rocksdb:
self.requires('rocksdb/10.0.1') self.requires('rocksdb/9.7.3')
self.requires('xxhash/0.8.3', **transitive_headers_opt)
exports_sources = ( exports_sources = (
'CMakeLists.txt', 'CMakeLists.txt',
@@ -168,17 +161,7 @@ class Xrpl(ConanFile):
# `include/`, not `include/ripple/proto/`. # `include/`, not `include/ripple/proto/`.
libxrpl.includedirs = ['include', 'include/ripple/proto'] libxrpl.includedirs = ['include', 'include/ripple/proto']
libxrpl.requires = [ libxrpl.requires = [
'boost::headers', 'boost::boost',
'boost::chrono',
'boost::container',
'boost::coroutine',
'boost::date_time',
'boost::filesystem',
'boost::json',
'boost::program_options',
'boost::regex',
'boost::system',
'boost::thread',
'date::date', 'date::date',
'grpc::grpc++', 'grpc::grpc++',
'libarchive::libarchive', 'libarchive::libarchive',

View File

@@ -23,7 +23,7 @@ direction.
``` ```
apt update apt update
apt install --yes curl git libssl-dev pipx python3.10-dev python3-pip make g++-11 libprotobuf-dev protobuf-compiler apt install --yes curl git libssl-dev python3.10-dev python3-pip make g++-11 libprotobuf-dev protobuf-compiler
curl --location --remote-name \ curl --location --remote-name \
"https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1.tar.gz" "https://github.com/Kitware/CMake/releases/download/v3.25.1/cmake-3.25.1.tar.gz"
@@ -35,8 +35,7 @@ make --jobs $(nproc)
make install make install
cd .. cd ..
pipx install 'conan<2' pip3 install 'conan<2'
pipx ensurepath
``` ```
[1]: https://github.com/thejohnfreeman/rippled-docker/blob/master/ubuntu-22.04/install.sh [1]: https://github.com/thejohnfreeman/rippled-docker/blob/master/ubuntu-22.04/install.sh

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.25)
# Note, version set explicitly by rippled project # Note, version set explicitly by rippled project
project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX) project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)

10
external/nudb/conandata.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
sources:
"2.0.8":
url: "https://github.com/CPPAlliance/NuDB/archive/2.0.8.tar.gz"
sha256: "9b71903d8ba111cd893ab064b9a8b6ac4124ed8bd6b4f67250205bc43c7f13a8"
patches:
"2.0.8":
- patch_file: "patches/2.0.8-0001-add-include-stdexcept-for-msvc.patch"
patch_description: "Fix build for MSVC by including stdexcept"
patch_type: "portability"
patch_source: "https://github.com/cppalliance/NuDB/pull/100/files"

72
external/nudb/conanfile.py vendored Normal file
View File

@@ -0,0 +1,72 @@
import os
from conan import ConanFile
from conan.tools.build import check_min_cppstd
from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get
from conan.tools.layout import basic_layout
required_conan_version = ">=1.52.0"
class NudbConan(ConanFile):
name = "nudb"
description = "A fast key/value insert-only database for SSD drives in C++11"
license = "BSL-1.0"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/CPPAlliance/NuDB"
topics = ("header-only", "KVS", "insert-only")
package_type = "header-library"
settings = "os", "arch", "compiler", "build_type"
no_copy_source = True
@property
def _min_cppstd(self):
return 11
def export_sources(self):
export_conandata_patches(self)
def layout(self):
basic_layout(self, src_folder="src")
def requirements(self):
self.requires("boost/1.83.0")
def package_id(self):
self.info.clear()
def validate(self):
if self.settings.compiler.cppstd:
check_min_cppstd(self, self._min_cppstd)
def source(self):
get(self, **self.conan_data["sources"][self.version], strip_root=True)
def build(self):
apply_conandata_patches(self)
def package(self):
copy(self, "LICENSE*",
dst=os.path.join(self.package_folder, "licenses"),
src=self.source_folder)
copy(self, "*",
dst=os.path.join(self.package_folder, "include"),
src=os.path.join(self.source_folder, "include"))
def package_info(self):
self.cpp_info.bindirs = []
self.cpp_info.libdirs = []
self.cpp_info.set_property("cmake_target_name", "NuDB")
self.cpp_info.set_property("cmake_target_aliases", ["NuDB::nudb"])
self.cpp_info.set_property("cmake_find_mode", "both")
self.cpp_info.components["core"].set_property("cmake_target_name", "nudb")
self.cpp_info.components["core"].names["cmake_find_package"] = "nudb"
self.cpp_info.components["core"].names["cmake_find_package_multi"] = "nudb"
self.cpp_info.components["core"].requires = ["boost::thread", "boost::system"]
# TODO: to remove in conan v2 once cmake_find_package_* generators removed
self.cpp_info.names["cmake_find_package"] = "NuDB"
self.cpp_info.names["cmake_find_package_multi"] = "NuDB"

View File

@@ -0,0 +1,24 @@
diff --git a/include/nudb/detail/stream.hpp b/include/nudb/detail/stream.hpp
index 6c07bf1..e0ce8ed 100644
--- a/include/nudb/detail/stream.hpp
+++ b/include/nudb/detail/stream.hpp
@@ -14,6 +14,7 @@
#include <cstdint>
#include <cstring>
#include <memory>
+#include <stdexcept>
namespace nudb {
namespace detail {
diff --git a/include/nudb/impl/context.ipp b/include/nudb/impl/context.ipp
index beb7058..ffde0b3 100644
--- a/include/nudb/impl/context.ipp
+++ b/include/nudb/impl/context.ipp
@@ -9,6 +9,7 @@
#define NUDB_IMPL_CONTEXT_IPP
#include <nudb/detail/store_base.hpp>
+#include <stdexcept>
namespace nudb {

12
external/rocksdb/conandata.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
sources:
"9.7.3":
url: "https://github.com/facebook/rocksdb/archive/refs/tags/v9.7.3.tar.gz"
sha256: "acfabb989cbfb5b5c4d23214819b059638193ec33dad2d88373c46448d16d38b"
patches:
"9.7.3":
- patch_file: "patches/9.x.x-0001-exclude-thirdparty.patch"
patch_description: "Do not include thirdparty.inc"
patch_type: "portability"
- patch_file: "patches/9.7.3-0001-memory-leak.patch"
patch_description: "Fix a leak of obsolete blob files left open until DB::Close()"
patch_type: "portability"

235
external/rocksdb/conanfile.py vendored Normal file
View File

@@ -0,0 +1,235 @@
import os
import glob
import shutil
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.build import check_min_cppstd
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.files import apply_conandata_patches, collect_libs, copy, export_conandata_patches, get, rm, rmdir
from conan.tools.microsoft import check_min_vs, is_msvc, is_msvc_static_runtime
from conan.tools.scm import Version
required_conan_version = ">=1.53.0"
class RocksDBConan(ConanFile):
name = "rocksdb"
description = "A library that provides an embeddable, persistent key-value store for fast storage"
license = ("GPL-2.0-only", "Apache-2.0")
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://github.com/facebook/rocksdb"
topics = ("database", "leveldb", "facebook", "key-value")
package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"lite": [True, False],
"with_gflags": [True, False],
"with_snappy": [True, False],
"with_lz4": [True, False],
"with_zlib": [True, False],
"with_zstd": [True, False],
"with_tbb": [True, False],
"with_jemalloc": [True, False],
"enable_sse": [False, "sse42", "avx2"],
"use_rtti": [True, False],
}
default_options = {
"shared": False,
"fPIC": True,
"lite": False,
"with_snappy": False,
"with_lz4": False,
"with_zlib": False,
"with_zstd": False,
"with_gflags": False,
"with_tbb": False,
"with_jemalloc": False,
"enable_sse": False,
"use_rtti": False,
}
@property
def _min_cppstd(self):
return "11" if Version(self.version) < "8.8.1" else "17"
@property
def _compilers_minimum_version(self):
return {} if self._min_cppstd == "11" else {
"apple-clang": "10",
"clang": "7",
"gcc": "7",
"msvc": "191",
"Visual Studio": "15",
}
def export_sources(self):
export_conandata_patches(self)
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
if self.settings.arch != "x86_64":
del self.options.with_tbb
if self.settings.build_type == "Debug":
self.options.use_rtti = True # Rtti are used in asserts for debug mode...
def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
def layout(self):
cmake_layout(self, src_folder="src")
def requirements(self):
if self.options.with_gflags:
self.requires("gflags/2.2.2")
if self.options.with_snappy:
self.requires("snappy/1.1.10")
if self.options.with_lz4:
self.requires("lz4/1.10.0")
if self.options.with_zlib:
self.requires("zlib/[>=1.2.11 <2]")
if self.options.with_zstd:
self.requires("zstd/1.5.6")
if self.options.get_safe("with_tbb"):
self.requires("onetbb/2021.12.0")
if self.options.with_jemalloc:
self.requires("jemalloc/5.3.0")
def validate(self):
if self.settings.compiler.get_safe("cppstd"):
check_min_cppstd(self, self._min_cppstd)
minimum_version = self._compilers_minimum_version.get(str(self.settings.compiler), False)
if minimum_version and Version(self.settings.compiler.version) < minimum_version:
raise ConanInvalidConfiguration(
f"{self.ref} requires C++{self._min_cppstd}, which your compiler does not support."
)
if self.settings.arch not in ["x86_64", "ppc64le", "ppc64", "mips64", "armv8"]:
raise ConanInvalidConfiguration("Rocksdb requires 64 bits")
check_min_vs(self, "191")
if self.version == "6.20.3" and \
self.settings.os == "Linux" and \
self.settings.compiler == "gcc" and \
Version(self.settings.compiler.version) < "5":
raise ConanInvalidConfiguration("Rocksdb 6.20.3 is not compilable with gcc <5.") # See https://github.com/facebook/rocksdb/issues/3522
def source(self):
get(self, **self.conan_data["sources"][self.version], strip_root=True)
def generate(self):
tc = CMakeToolchain(self)
tc.variables["FAIL_ON_WARNINGS"] = False
tc.variables["WITH_TESTS"] = False
tc.variables["WITH_TOOLS"] = False
tc.variables["WITH_CORE_TOOLS"] = False
tc.variables["WITH_BENCHMARK_TOOLS"] = False
tc.variables["WITH_FOLLY_DISTRIBUTED_MUTEX"] = False
if is_msvc(self):
tc.variables["WITH_MD_LIBRARY"] = not is_msvc_static_runtime(self)
tc.variables["ROCKSDB_INSTALL_ON_WINDOWS"] = self.settings.os == "Windows"
tc.variables["ROCKSDB_LITE"] = self.options.lite
tc.variables["WITH_GFLAGS"] = self.options.with_gflags
tc.variables["WITH_SNAPPY"] = self.options.with_snappy
tc.variables["WITH_LZ4"] = self.options.with_lz4
tc.variables["WITH_ZLIB"] = self.options.with_zlib
tc.variables["WITH_ZSTD"] = self.options.with_zstd
tc.variables["WITH_TBB"] = self.options.get_safe("with_tbb", False)
tc.variables["WITH_JEMALLOC"] = self.options.with_jemalloc
tc.variables["ROCKSDB_BUILD_SHARED"] = self.options.shared
tc.variables["ROCKSDB_LIBRARY_EXPORTS"] = self.settings.os == "Windows" and self.options.shared
tc.variables["ROCKSDB_DLL" ] = self.settings.os == "Windows" and self.options.shared
tc.variables["USE_RTTI"] = self.options.use_rtti
if not bool(self.options.enable_sse):
tc.variables["PORTABLE"] = True
tc.variables["FORCE_SSE42"] = False
elif self.options.enable_sse == "sse42":
tc.variables["PORTABLE"] = True
tc.variables["FORCE_SSE42"] = True
elif self.options.enable_sse == "avx2":
tc.variables["PORTABLE"] = False
tc.variables["FORCE_SSE42"] = False
# not available yet in CCI
tc.variables["WITH_NUMA"] = False
tc.generate()
deps = CMakeDeps(self)
if self.options.with_jemalloc:
deps.set_property("jemalloc", "cmake_file_name", "JeMalloc")
deps.set_property("jemalloc", "cmake_target_name", "JeMalloc::JeMalloc")
if self.options.with_zstd:
deps.set_property("zstd", "cmake_target_name", "zstd::zstd")
deps.generate()
def build(self):
apply_conandata_patches(self)
cmake = CMake(self)
cmake.configure()
cmake.build()
def _remove_static_libraries(self):
rm(self, "rocksdb.lib", os.path.join(self.package_folder, "lib"))
for lib in glob.glob(os.path.join(self.package_folder, "lib", "*.a")):
if not lib.endswith(".dll.a"):
os.remove(lib)
def _remove_cpp_headers(self):
for path in glob.glob(os.path.join(self.package_folder, "include", "rocksdb", "*")):
if path != os.path.join(self.package_folder, "include", "rocksdb", "c.h"):
if os.path.isfile(path):
os.remove(path)
else:
shutil.rmtree(path)
def package(self):
copy(self, "COPYING", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
copy(self, "LICENSE*", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
cmake = CMake(self)
cmake.install()
if self.options.shared:
self._remove_static_libraries()
self._remove_cpp_headers() # Force stable ABI for shared libraries
rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
def package_info(self):
cmake_target = "rocksdb-shared" if self.options.shared else "rocksdb"
self.cpp_info.set_property("cmake_file_name", "RocksDB")
self.cpp_info.set_property("cmake_target_name", f"RocksDB::{cmake_target}")
# TODO: back to global scope in conan v2 once cmake_find_package* generators removed
self.cpp_info.components["librocksdb"].libs = collect_libs(self)
if self.settings.os == "Windows":
self.cpp_info.components["librocksdb"].system_libs = ["shlwapi", "rpcrt4"]
if self.options.shared:
self.cpp_info.components["librocksdb"].defines = ["ROCKSDB_DLL"]
elif self.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.components["librocksdb"].system_libs = ["pthread", "m"]
if self.options.lite:
self.cpp_info.components["librocksdb"].defines.append("ROCKSDB_LITE")
# TODO: to remove in conan v2 once cmake_find_package* generators removed
self.cpp_info.names["cmake_find_package"] = "RocksDB"
self.cpp_info.names["cmake_find_package_multi"] = "RocksDB"
self.cpp_info.components["librocksdb"].names["cmake_find_package"] = cmake_target
self.cpp_info.components["librocksdb"].names["cmake_find_package_multi"] = cmake_target
self.cpp_info.components["librocksdb"].set_property("cmake_target_name", f"RocksDB::{cmake_target}")
if self.options.with_gflags:
self.cpp_info.components["librocksdb"].requires.append("gflags::gflags")
if self.options.with_snappy:
self.cpp_info.components["librocksdb"].requires.append("snappy::snappy")
if self.options.with_lz4:
self.cpp_info.components["librocksdb"].requires.append("lz4::lz4")
if self.options.with_zlib:
self.cpp_info.components["librocksdb"].requires.append("zlib::zlib")
if self.options.with_zstd:
self.cpp_info.components["librocksdb"].requires.append("zstd::zstd")
if self.options.get_safe("with_tbb"):
self.cpp_info.components["librocksdb"].requires.append("onetbb::onetbb")
if self.options.with_jemalloc:
self.cpp_info.components["librocksdb"].requires.append("jemalloc::jemalloc")

View File

@@ -0,0 +1,319 @@
diff --git a/HISTORY.md b/HISTORY.md
index 36d472229..05ad1a202 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,6 +1,10 @@
# Rocksdb Change Log
> NOTE: Entries for next release do not go here. Follow instructions in `unreleased_history/README.txt`
+## 9.7.4 (10/31/2024)
+### Bug Fixes
+* Fix a leak of obsolete blob files left open until DB::Close(). This bug was introduced in version 9.4.0.
+
## 9.7.3 (10/16/2024)
### Behavior Changes
* OPTIONS file to be loaded by remote worker is now preserved so that it does not get purged by the primary host. A similar technique as how we are preserving new SST files from getting purged is used for this. min_options_file_numbers_ is tracked like pending_outputs_ is tracked.
diff --git a/db/blob/blob_file_cache.cc b/db/blob/blob_file_cache.cc
index 5f340aadf..1b9faa238 100644
--- a/db/blob/blob_file_cache.cc
+++ b/db/blob/blob_file_cache.cc
@@ -42,6 +42,7 @@ Status BlobFileCache::GetBlobFileReader(
assert(blob_file_reader);
assert(blob_file_reader->IsEmpty());
+ // NOTE: sharing same Cache with table_cache
const Slice key = GetSliceForKey(&blob_file_number);
assert(cache_);
@@ -98,4 +99,13 @@ Status BlobFileCache::GetBlobFileReader(
return Status::OK();
}
+void BlobFileCache::Evict(uint64_t blob_file_number) {
+ // NOTE: sharing same Cache with table_cache
+ const Slice key = GetSliceForKey(&blob_file_number);
+
+ assert(cache_);
+
+ cache_.get()->Erase(key);
+}
+
} // namespace ROCKSDB_NAMESPACE
diff --git a/db/blob/blob_file_cache.h b/db/blob/blob_file_cache.h
index 740e67ada..6858d012b 100644
--- a/db/blob/blob_file_cache.h
+++ b/db/blob/blob_file_cache.h
@@ -36,6 +36,15 @@ class BlobFileCache {
uint64_t blob_file_number,
CacheHandleGuard<BlobFileReader>* blob_file_reader);
+ // Called when a blob file is obsolete to ensure it is removed from the cache
+ // to avoid effectively leaking the open file and assicated memory
+ void Evict(uint64_t blob_file_number);
+
+ // Used to identify cache entries for blob files (not normally useful)
+ static const Cache::CacheItemHelper* GetHelper() {
+ return CacheInterface::GetBasicHelper();
+ }
+
private:
using CacheInterface =
BasicTypedCacheInterface<BlobFileReader, CacheEntryRole::kMisc>;
diff --git a/db/column_family.h b/db/column_family.h
index e4b7adde8..86637736a 100644
--- a/db/column_family.h
+++ b/db/column_family.h
@@ -401,6 +401,7 @@ class ColumnFamilyData {
SequenceNumber earliest_seq);
TableCache* table_cache() const { return table_cache_.get(); }
+ BlobFileCache* blob_file_cache() const { return blob_file_cache_.get(); }
BlobSource* blob_source() const { return blob_source_.get(); }
// See documentation in compaction_picker.h
diff --git a/db/db_impl/db_impl.cc b/db/db_impl/db_impl.cc
index 261593423..06573ac2e 100644
--- a/db/db_impl/db_impl.cc
+++ b/db/db_impl/db_impl.cc
@@ -659,8 +659,9 @@ Status DBImpl::CloseHelper() {
// We need to release them before the block cache is destroyed. The block
// cache may be destroyed inside versions_.reset(), when column family data
// list is destroyed, so leaving handles in table cache after
- // versions_.reset() may cause issues.
- // Here we clean all unreferenced handles in table cache.
+ // versions_.reset() may cause issues. Here we clean all unreferenced handles
+ // in table cache, and (for certain builds/conditions) assert that no obsolete
+ // files are hanging around unreferenced (leak) in the table/blob file cache.
// Now we assume all user queries have finished, so only version set itself
// can possibly hold the blocks from block cache. After releasing unreferenced
// handles here, only handles held by version set left and inside
@@ -668,6 +669,9 @@ Status DBImpl::CloseHelper() {
// time a handle is released, we erase it from the cache too. By doing that,
// we can guarantee that after versions_.reset(), table cache is empty
// so the cache can be safely destroyed.
+#ifndef NDEBUG
+ TEST_VerifyNoObsoleteFilesCached(/*db_mutex_already_held=*/true);
+#endif // !NDEBUG
table_cache_->EraseUnRefEntries();
for (auto& txn_entry : recovered_transactions_) {
@@ -3227,6 +3231,8 @@ Status DBImpl::MultiGetImpl(
s = Status::Aborted();
break;
}
+ // This could be a long-running operation
+ ROCKSDB_THREAD_YIELD_HOOK();
}
// Post processing (decrement reference counts and record statistics)
diff --git a/db/db_impl/db_impl.h b/db/db_impl/db_impl.h
index 5e4fa310b..ccc0abfa7 100644
--- a/db/db_impl/db_impl.h
+++ b/db/db_impl/db_impl.h
@@ -1241,9 +1241,14 @@ class DBImpl : public DB {
static Status TEST_ValidateOptions(const DBOptions& db_options) {
return ValidateOptions(db_options);
}
-
#endif // NDEBUG
+ // In certain configurations, verify that the table/blob file cache only
+ // contains entries for live files, to check for effective leaks of open
+ // files. This can only be called when purging of obsolete files has
+ // "settled," such as during parts of DB Close().
+ void TEST_VerifyNoObsoleteFilesCached(bool db_mutex_already_held) const;
+
// persist stats to column family "_persistent_stats"
void PersistStats();
diff --git a/db/db_impl/db_impl_debug.cc b/db/db_impl/db_impl_debug.cc
index 790a50d7a..67f5b4aaf 100644
--- a/db/db_impl/db_impl_debug.cc
+++ b/db/db_impl/db_impl_debug.cc
@@ -9,6 +9,7 @@
#ifndef NDEBUG
+#include "db/blob/blob_file_cache.h"
#include "db/column_family.h"
#include "db/db_impl/db_impl.h"
#include "db/error_handler.h"
@@ -328,5 +329,49 @@ size_t DBImpl::TEST_EstimateInMemoryStatsHistorySize() const {
InstrumentedMutexLock l(&const_cast<DBImpl*>(this)->stats_history_mutex_);
return EstimateInMemoryStatsHistorySize();
}
+
+void DBImpl::TEST_VerifyNoObsoleteFilesCached(
+ bool db_mutex_already_held) const {
+ // This check is somewhat expensive and obscure to make a part of every
+ // unit test in every build variety. Thus, we only enable it for ASAN builds.
+ if (!kMustFreeHeapAllocations) {
+ return;
+ }
+
+ std::optional<InstrumentedMutexLock> l;
+ if (db_mutex_already_held) {
+ mutex_.AssertHeld();
+ } else {
+ l.emplace(&mutex_);
+ }
+
+ std::vector<uint64_t> live_files;
+ for (auto cfd : *versions_->GetColumnFamilySet()) {
+ if (cfd->IsDropped()) {
+ continue;
+ }
+ // Sneakily add both SST and blob files to the same list
+ cfd->current()->AddLiveFiles(&live_files, &live_files);
+ }
+ std::sort(live_files.begin(), live_files.end());
+
+ auto fn = [&live_files](const Slice& key, Cache::ObjectPtr, size_t,
+ const Cache::CacheItemHelper* helper) {
+ if (helper != BlobFileCache::GetHelper()) {
+ // Skip non-blob files for now
+ // FIXME: diagnose and fix the leaks of obsolete SST files revealed in
+ // unit tests.
+ return;
+ }
+ // See TableCache and BlobFileCache
+ assert(key.size() == sizeof(uint64_t));
+ uint64_t file_number;
+ GetUnaligned(reinterpret_cast<const uint64_t*>(key.data()), &file_number);
+ // Assert file is in sorted live_files
+ assert(
+ std::binary_search(live_files.begin(), live_files.end(), file_number));
+ };
+ table_cache_->ApplyToAllEntries(fn, {});
+}
} // namespace ROCKSDB_NAMESPACE
#endif // NDEBUG
diff --git a/db/db_iter.cc b/db/db_iter.cc
index e02586377..bf4749eb9 100644
--- a/db/db_iter.cc
+++ b/db/db_iter.cc
@@ -540,6 +540,8 @@ bool DBIter::FindNextUserEntryInternal(bool skipping_saved_key,
} else {
iter_.Next();
}
+ // This could be a long-running operation due to tombstones, etc.
+ ROCKSDB_THREAD_YIELD_HOOK();
} while (iter_.Valid());
valid_ = false;
diff --git a/db/table_cache.cc b/db/table_cache.cc
index 71fc29c32..8a5be75e8 100644
--- a/db/table_cache.cc
+++ b/db/table_cache.cc
@@ -164,6 +164,7 @@ Status TableCache::GetTableReader(
}
Cache::Handle* TableCache::Lookup(Cache* cache, uint64_t file_number) {
+ // NOTE: sharing same Cache with BlobFileCache
Slice key = GetSliceForFileNumber(&file_number);
return cache->Lookup(key);
}
@@ -179,6 +180,7 @@ Status TableCache::FindTable(
size_t max_file_size_for_l0_meta_pin, Temperature file_temperature) {
PERF_TIMER_GUARD_WITH_CLOCK(find_table_nanos, ioptions_.clock);
uint64_t number = file_meta.fd.GetNumber();
+ // NOTE: sharing same Cache with BlobFileCache
Slice key = GetSliceForFileNumber(&number);
*handle = cache_.Lookup(key);
TEST_SYNC_POINT_CALLBACK("TableCache::FindTable:0",
diff --git a/db/version_builder.cc b/db/version_builder.cc
index ed8ab8214..c98f53f42 100644
--- a/db/version_builder.cc
+++ b/db/version_builder.cc
@@ -24,6 +24,7 @@
#include <vector>
#include "cache/cache_reservation_manager.h"
+#include "db/blob/blob_file_cache.h"
#include "db/blob/blob_file_meta.h"
#include "db/dbformat.h"
#include "db/internal_stats.h"
@@ -744,12 +745,9 @@ class VersionBuilder::Rep {
return Status::Corruption("VersionBuilder", oss.str());
}
- // Note: we use C++11 for now but in C++14, this could be done in a more
- // elegant way using generalized lambda capture.
- VersionSet* const vs = version_set_;
- const ImmutableCFOptions* const ioptions = ioptions_;
-
- auto deleter = [vs, ioptions](SharedBlobFileMetaData* shared_meta) {
+ auto deleter = [vs = version_set_, ioptions = ioptions_,
+ bc = cfd_ ? cfd_->blob_file_cache()
+ : nullptr](SharedBlobFileMetaData* shared_meta) {
if (vs) {
assert(ioptions);
assert(!ioptions->cf_paths.empty());
@@ -758,6 +756,9 @@ class VersionBuilder::Rep {
vs->AddObsoleteBlobFile(shared_meta->GetBlobFileNumber(),
ioptions->cf_paths.front().path);
}
+ if (bc) {
+ bc->Evict(shared_meta->GetBlobFileNumber());
+ }
delete shared_meta;
};
@@ -766,7 +767,7 @@ class VersionBuilder::Rep {
blob_file_number, blob_file_addition.GetTotalBlobCount(),
blob_file_addition.GetTotalBlobBytes(),
blob_file_addition.GetChecksumMethod(),
- blob_file_addition.GetChecksumValue(), deleter);
+ blob_file_addition.GetChecksumValue(), std::move(deleter));
mutable_blob_file_metas_.emplace(
blob_file_number, MutableBlobFileMetaData(std::move(shared_meta)));
diff --git a/db/version_set.h b/db/version_set.h
index 9336782b1..024f869e7 100644
--- a/db/version_set.h
+++ b/db/version_set.h
@@ -1514,7 +1514,6 @@ class VersionSet {
void GetLiveFilesMetaData(std::vector<LiveFileMetaData>* metadata);
void AddObsoleteBlobFile(uint64_t blob_file_number, std::string path) {
- // TODO: Erase file from BlobFileCache?
obsolete_blob_files_.emplace_back(blob_file_number, std::move(path));
}
diff --git a/include/rocksdb/version.h b/include/rocksdb/version.h
index 2a19796b8..0afa2cab1 100644
--- a/include/rocksdb/version.h
+++ b/include/rocksdb/version.h
@@ -13,7 +13,7 @@
// minor or major version number planned for release.
#define ROCKSDB_MAJOR 9
#define ROCKSDB_MINOR 7
-#define ROCKSDB_PATCH 3
+#define ROCKSDB_PATCH 4
// Do not use these. We made the mistake of declaring macros starting with
// double underscore. Now we have to live with our choice. We'll deprecate these
diff --git a/port/port.h b/port/port.h
index 13aa56d47..141716e5b 100644
--- a/port/port.h
+++ b/port/port.h
@@ -19,3 +19,19 @@
#elif defined(OS_WIN)
#include "port/win/port_win.h"
#endif
+
+#ifdef OS_LINUX
+// A temporary hook into long-running RocksDB threads to support modifying their
+// priority etc. This should become a public API hook once the requirements
+// are better understood.
+extern "C" void RocksDbThreadYield() __attribute__((__weak__));
+#define ROCKSDB_THREAD_YIELD_HOOK() \
+ { \
+ if (RocksDbThreadYield) { \
+ RocksDbThreadYield(); \
+ } \
+ }
+#else
+#define ROCKSDB_THREAD_YIELD_HOOK() \
+ {}
+#endif

View File

@@ -0,0 +1,30 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93b884d..b715cb6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -106,14 +106,9 @@ endif()
include(CMakeDependentOption)
if(MSVC)
- option(WITH_GFLAGS "build with GFlags" OFF)
option(WITH_XPRESS "build with windows built in compression" OFF)
- option(ROCKSDB_SKIP_THIRDPARTY "skip thirdparty.inc" OFF)
-
- if(NOT ROCKSDB_SKIP_THIRDPARTY)
- include(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty.inc)
- endif()
-else()
+endif()
+if(TRUE)
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD" AND NOT CMAKE_SYSTEM_NAME MATCHES "kFreeBSD")
# FreeBSD has jemalloc as default malloc
# but it does not have all the jemalloc files in include/...
@@ -126,7 +121,7 @@ else()
endif()
endif()
- if(MINGW)
+ if(MSVC OR MINGW)
option(WITH_GFLAGS "build with GFlags" OFF)
else()
option(WITH_GFLAGS "build with GFlags" ON)

View File

@@ -25,7 +25,6 @@
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <memory>
namespace ripple { namespace ripple {

View File

@@ -22,18 +22,8 @@
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <boost/outcome.hpp> #include <boost/outcome.hpp>
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#include <stdexcept> #include <stdexcept>
namespace ripple { namespace ripple {

View File

@@ -29,6 +29,7 @@
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#include <optional> #include <optional>
#include <sstream>
#include <string> #include <string>
namespace ripple { namespace ripple {

View File

@@ -20,6 +20,7 @@
#ifndef RIPPLE_ALGORITHM_H_INCLUDED #ifndef RIPPLE_ALGORITHM_H_INCLUDED
#define RIPPLE_ALGORITHM_H_INCLUDED #define RIPPLE_ALGORITHM_H_INCLUDED
#include <iterator>
#include <utility> #include <utility>
namespace ripple { namespace ripple {

View File

@@ -632,13 +632,6 @@ to_string(base_uint<Bits, Tag> const& a)
return strHex(a.cbegin(), a.cend()); return strHex(a.cbegin(), a.cend());
} }
template <std::size_t Bits, class Tag>
inline std::string
to_short_string(base_uint<Bits, Tag> const& a)
{
return to_string(a).substr(0, 8) + "...";
}
template <std::size_t Bits, class Tag> template <std::size_t Bits, class Tag>
inline std::ostream& inline std::ostream&
operator<<(std::ostream& out, base_uint<Bits, Tag> const& u) operator<<(std::ostream& out, base_uint<Bits, Tag> const& u)

View File

@@ -24,8 +24,12 @@
#include <xrpl/beast/hash/xxhasher.h> #include <xrpl/beast/hash/xxhasher.h>
#include <cstdint> #include <cstdint>
#include <functional>
#include <mutex> #include <mutex>
#include <random> #include <random>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility> #include <utility>
namespace ripple { namespace ripple {

View File

@@ -23,6 +23,7 @@
#include <cstdint> #include <cstdint>
#include <limits> #include <limits>
#include <optional> #include <optional>
#include <utility>
namespace ripple { namespace ripple {
auto constexpr muldiv_max = std::numeric_limits<std::uint64_t>::max(); auto constexpr muldiv_max = std::numeric_limits<std::uint64_t>::max();

View File

@@ -24,8 +24,10 @@
#include <boost/operators.hpp> #include <boost/operators.hpp>
#include <functional>
#include <iostream> #include <iostream>
#include <type_traits> #include <type_traits>
#include <utility>
namespace ripple { namespace ripple {

View File

@@ -20,6 +20,9 @@
#ifndef BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED #ifndef BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED
#define BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED #define BEAST_CHRONO_ABSTRACT_CLOCK_H_INCLUDED
#include <chrono>
#include <string>
namespace beast { namespace beast {
/** Abstract interface to a clock. /** Abstract interface to a clock.

View File

@@ -23,8 +23,6 @@
#include <xrpl/beast/clock/abstract_clock.h> #include <xrpl/beast/clock/abstract_clock.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <chrono>
namespace beast { namespace beast {
/** Manual clock implementation. /** Manual clock implementation.

View File

@@ -22,7 +22,6 @@
#include <xrpl/beast/container/aged_container.h> #include <xrpl/beast/container/aged_container.h>
#include <chrono>
#include <type_traits> #include <type_traits>
namespace beast { namespace beast {

View File

@@ -20,6 +20,8 @@
#ifndef BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED #ifndef BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED
#define BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED #define BEAST_CONTAINER_DETAIL_AGED_ASSOCIATIVE_CONTAINER_H_INCLUDED
#include <type_traits>
namespace beast { namespace beast {
namespace detail { namespace detail {

View File

@@ -33,6 +33,7 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <initializer_list> #include <initializer_list>
#include <iterator>
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>

View File

@@ -0,0 +1,120 @@
#ifndef RIPPLE_BASICS_FUNCTIONPROFILER_H_INCLUDED
#define RIPPLE_BASICS_FUNCTIONPROFILER_H_INCLUDED
#include <chrono>
#include <csignal>
#include <mutex>
#include <source_location>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <numeric> // std::accumulate
#define PROFILING 1
#if PROFILING && (defined(__x86_64__) || defined(_M_X64))
#include <x86intrin.h>
#else
#define __rdtsc() 0
#endif
namespace beast {
template <typename T>
double compute_stddev(const std::vector<T>& samples) {
if (samples.size() < 2) return 0.0;
double mean = std::accumulate(samples.begin(), samples.end(), 0.0) / samples.size();
double sum_sq = 0.0;
for (double x : samples) {
sum_sq += (x - mean) * (x - mean);
}
return std::sqrt(sum_sq / (samples.size() - 1));
}
void
logProfilingResults();
class FunctionProfiler
{
public:
std::string functionName;
std::chrono::steady_clock::time_point start;
std::uint64_t cpuCycleStart;
inline static std::mutex mutex_;
struct StatisticData
{
std::vector<std::chrono::nanoseconds> time;
std::vector<std::uint64_t> cpuCycles;
};
inline static std::unordered_map<
std::string,
StatisticData>
funcionDurations;
FunctionProfiler(
std::string const& tag,
std::source_location location = std::source_location::current())
#if PROFILING
: functionName(location.function_name() + tag)
, start(std::chrono::steady_clock::now())
, cpuCycleStart(__rdtsc())
#endif
{
}
~FunctionProfiler() noexcept
{
#if PROFILING
auto duration = std::chrono::steady_clock::now() - start;
std::lock_guard<std::mutex> lock{mutex_};
funcionDurations[functionName].time.emplace_back(duration);
funcionDurations[functionName].cpuCycles.emplace_back((__rdtsc() - cpuCycleStart));
#endif
}
};
inline std::string
getProfilingResults()
{
#if PROFILING
std::lock_guard<std::mutex> lock{FunctionProfiler::mutex_};
std::stringstream ss;
ss << "Function profiling results:" << std::endl;
ss << "name,time,cpu cycles,count,average time(ns),time standard deviation,average cpu cycles,cpu cycles standard deviation" << std::endl;
for (auto const& [name, duration] : FunctionProfiler::funcionDurations)
{
std::vector<std::int64_t> times;
times.reserve(duration.time.size());
std::transform(std::begin(duration.time), std::end(duration.time), std::back_inserter(times), [](const std::chrono::nanoseconds& time) {
return static_cast<std::int64_t>(time.count());
});
auto timeInTotal = std::accumulate(std::begin(times), std::end(times), std::int64_t{0});
auto cpuCyclesInTotal = std::accumulate(std::begin(duration.cpuCycles), std::end(duration.cpuCycles), std::int64_t{0});
ss << name << "," << timeInTotal << ","
<< cpuCyclesInTotal << ","
<< duration.time.size() << ","
<< timeInTotal / (double)duration.time.size() << ","
<< compute_stddev(times) << ","
<< cpuCyclesInTotal / (double)duration.cpuCycles.size() << ","
<< compute_stddev(duration.cpuCycles)
<< std::endl;
}
return ss.str();
#else
return "";
#endif
}
} // namespace beast
#endif

View File

@@ -29,9 +29,11 @@
#include <charconv> #include <charconv>
#include <cstdlib> #include <cstdlib>
#include <iterator> #include <iterator>
#include <limits>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <typeinfo> #include <typeinfo>
#include <utility>
namespace beast { namespace beast {

View File

@@ -24,36 +24,14 @@
#include <boost/container/flat_set.hpp> #include <boost/container/flat_set.hpp>
#include <boost/endian/conversion.hpp> #include <boost/endian/conversion.hpp>
/*
Workaround for overzealous clang warning, which trips on libstdc++ headers
In file included from
/usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/stl_algo.h:61:
/usr/lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/stl_tempbuf.h:263:8:
error: 'get_temporary_buffer<std::pair<ripple::Quality, const
std::vector<std::unique_ptr<ripple::Step>> *>>' is deprecated
[-Werror,-Wdeprecated-declarations] 263 |
std::get_temporary_buffer<value_type>(_M_original_len));
^
*/
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <functional>
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#include <array> #include <array>
#include <chrono> #include <chrono>
#include <cstdint>
#include <cstring> #include <cstring>
#include <functional>
#include <map>
#include <memory> #include <memory>
#include <set>
#include <string> #include <string>
#include <system_error> #include <system_error>
#include <tuple> #include <tuple>

View File

@@ -30,7 +30,7 @@ namespace beast {
template <class Hasher = xxhasher> template <class Hasher = xxhasher>
struct uhash struct uhash
{ {
uhash() = default; explicit uhash() = default;
using result_type = typename Hasher::result_type; using result_type = typename Hasher::result_type;

View File

@@ -20,24 +20,48 @@
#ifndef BEAST_HASH_XXHASHER_H_INCLUDED #ifndef BEAST_HASH_XXHASHER_H_INCLUDED
#define BEAST_HASH_XXHASHER_H_INCLUDED #define BEAST_HASH_XXHASHER_H_INCLUDED
#include <xrpl/beast/core/FunctionProfiler.h>
#include <boost/endian/conversion.hpp> #include <boost/endian/conversion.hpp>
#include <xxhash.h> #include <xxhash.h>
#include <cstddef> #include <cstddef>
#include <iostream>
#include <new> #include <new>
#include <span>
#include <type_traits> #include <type_traits>
#define ORIGINAL_HASH 1
#define BIT_SHIFT_HASH 0
namespace beast { namespace beast {
class xxhasher class xxhasher
{ {
public:
using HashType = std::size_t;
private: private:
// requires 64-bit std::size_t // requires 64-bit std::size_t
static_assert(sizeof(std::size_t) == 8, ""); static_assert(sizeof(std::size_t) == 8, "");
#if ORIGINAL_HASH
XXH3_state_t* state_; XXH3_state_t* state_;
#endif
#if PROFILING
std::size_t totalSize_ = 0;
std::chrono::nanoseconds duration_{};
std::uint64_t cpuCycles = 0;
#endif
XXH64_hash_t seed_ = 0;
std::array<std::uint8_t, 40> buffer_;
std::span<std::uint8_t> readBuffer_;
std::span<std::uint8_t> writeBuffer_;
#if ORIGINAL_HASH
static XXH3_state_t* static XXH3_state_t*
allocState() allocState()
{ {
@@ -46,6 +70,24 @@ private:
throw std::bad_alloc(); throw std::bad_alloc();
return ret; return ret;
} }
#endif
void
setupBuffers()
{
writeBuffer_ = std::span{buffer_};
}
void
writeBuffer(void const* data, std::size_t len)
{
auto bytesToWrite = std::min(len, writeBuffer_.size());
std::memcpy(writeBuffer_.data(), data, bytesToWrite);
writeBuffer_ = writeBuffer_.subspan(bytesToWrite);
readBuffer_ = std::span{
std::begin(buffer_), buffer_.size() - writeBuffer_.size()};
}
public: public:
using result_type = std::size_t; using result_type = std::size_t;
@@ -58,22 +100,48 @@ public:
xxhasher() xxhasher()
{ {
#if PROFILING
auto start = std::chrono::steady_clock::now();
auto cpuCyclesStart = __rdtsc();
#endif
#if ORIGINAL_HASH
state_ = allocState(); state_ = allocState();
XXH3_64bits_reset(state_); XXH3_64bits_reset(state_);
#else
setupBuffers();
#endif
#if PROFILING
duration_ += std::chrono::steady_clock::now() - start;
cpuCycles += (__rdtsc() - cpuCyclesStart);
#endif
} }
#if ORIGINAL_HASH
~xxhasher() noexcept ~xxhasher() noexcept
{ {
XXH3_freeState(state_); XXH3_freeState(state_);
} }
#endif
template < template <
class Seed, class Seed,
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr> std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
explicit xxhasher(Seed seed) explicit xxhasher(Seed seed)
{ {
seed_ = seed;
#if ORIGINAL_HASH
auto start = std::chrono::steady_clock::now();
auto cpuCyclesStart = __rdtsc();
state_ = allocState(); state_ = allocState();
XXH3_64bits_reset_withSeed(state_, seed); XXH3_64bits_reset_withSeed(state_, seed);
duration_ += (std::chrono::steady_clock::now() - start);
cpuCycles += (__rdtsc() - cpuCyclesStart);
#else
setupBuffers();
#endif
} }
template < template <
@@ -81,20 +149,92 @@ public:
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr> std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
xxhasher(Seed seed, Seed) xxhasher(Seed seed, Seed)
{ {
#if PROFILING
auto start = std::chrono::steady_clock::now();
auto cpuCyclesStart = __rdtsc();
#endif
seed_ = seed;
#if ORIGINAL_HASH
state_ = allocState(); state_ = allocState();
XXH3_64bits_reset_withSeed(state_, seed); XXH3_64bits_reset_withSeed(state_, seed);
#else
setupBuffers();
#endif
#if PROFILING
duration_ += (std::chrono::steady_clock::now() - start);
cpuCycles += (__rdtsc() - cpuCyclesStart);
#endif
} }
void void
operator()(void const* key, std::size_t len) noexcept operator()(void const* key, std::size_t len) noexcept
{ {
#if PROFILING
totalSize_ += len;
auto start = std::chrono::steady_clock::now();
auto cpuCyclesStart = __rdtsc();
#endif
#if ORIGINAL_HASH
XXH3_64bits_update(state_, key, len); XXH3_64bits_update(state_, key, len);
#else
writeBuffer(key, len);
#endif
#if PROFILING
duration_ += (std::chrono::steady_clock::now() - start);
cpuCycles += (__rdtsc() - cpuCyclesStart);
#endif
} }
explicit explicit
operator std::size_t() noexcept operator HashType() noexcept
{ {
return XXH3_64bits_digest(state_); #if ORIGINAL_HASH == 0
if (readBuffer_.size() == 0) return 0;
#endif
#if PROFILING
auto start = std::chrono::steady_clock::now();
auto cpuCyclesStart = __rdtsc();
#endif
#if BIT_SHIFT_HASH
const size_t bit_width = readBuffer_.size() * 8;
const size_t shift = seed_ % bit_width;
// Copy input into a buffer long enough to safely extract 64 bits with wraparound
std::uint64_t buffer = 0;
// Load the first 8 bytes (or wrap if input < 8 bytes)
for (size_t i = 0; i < 8; ++i) {
size_t index = readBuffer_.size() - 1 - (i % readBuffer_.size());
buffer <<= 8;
buffer |= readBuffer_[index];
}
// Rotate and return
auto result = (buffer << shift) | (buffer >> (64 - shift));
#elif ORIGINAL_HASH
auto result = XXH3_64bits_digest(state_);
#else
auto result = seed_ == 0 ?
XXH3_64bits(readBuffer_.data(), readBuffer_.size()) :
XXH3_64bits_withSeed(readBuffer_.data(), readBuffer_.size(), seed_);
#endif
#if PROFILING
duration_ += (std::chrono::steady_clock::now() - start);
cpuCycles += (__rdtsc() - cpuCyclesStart);
std::lock_guard<std::mutex> lock{FunctionProfiler::mutex_};
FunctionProfiler::funcionDurations
["xxhasher-" + std::to_string(totalSize_)]
.time.emplace_back(duration_);
FunctionProfiler::funcionDurations
["xxhasher-" + std::to_string(totalSize_)]
.cpuCycles.emplace_back(cpuCycles);
#endif
return result;
} }
}; };

View File

@@ -29,7 +29,11 @@
#include <boost/asio/ip/address.hpp> #include <boost/asio/ip/address.hpp>
#include <boost/functional/hash.hpp> #include <boost/functional/hash.hpp>
#include <cstdint>
#include <ios>
#include <sstream>
#include <string> #include <string>
#include <typeinfo>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -24,6 +24,12 @@
#include <boost/asio/ip/address_v4.hpp> #include <boost/asio/ip/address_v4.hpp>
#include <cstdint>
#include <functional>
#include <ios>
#include <string>
#include <utility>
namespace beast { namespace beast {
namespace IP { namespace IP {

View File

@@ -24,6 +24,12 @@
#include <boost/asio/ip/address_v6.hpp> #include <boost/asio/ip/address_v6.hpp>
#include <cstdint>
#include <functional>
#include <ios>
#include <string>
#include <utility>
namespace beast { namespace beast {
namespace IP { namespace IP {

View File

@@ -25,6 +25,7 @@
#include <xrpl/beast/net/IPAddress.h> #include <xrpl/beast/net/IPAddress.h>
#include <cstdint> #include <cstdint>
#include <ios>
#include <optional> #include <optional>
#include <string> #include <string>
@@ -214,7 +215,7 @@ namespace std {
template <> template <>
struct hash<::beast::IP::Endpoint> struct hash<::beast::IP::Endpoint>
{ {
hash() = default; explicit hash() = default;
std::size_t std::size_t
operator()(::beast::IP::Endpoint const& endpoint) const operator()(::beast::IP::Endpoint const& endpoint) const
@@ -229,7 +230,7 @@ namespace boost {
template <> template <>
struct hash<::beast::IP::Endpoint> struct hash<::beast::IP::Endpoint>
{ {
hash() = default; explicit hash() = default;
std::size_t std::size_t
operator()(::beast::IP::Endpoint const& endpoint) const operator()(::beast::IP::Endpoint const& endpoint) const

View File

@@ -28,8 +28,10 @@
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
#include <cstdint>
#include <iterator> #include <iterator>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
namespace beast { namespace beast {

View File

@@ -13,6 +13,7 @@
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <condition_variable> #include <condition_variable>
#include <functional>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <vector> #include <vector>

View File

@@ -16,6 +16,7 @@
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <functional>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>

View File

@@ -13,6 +13,7 @@
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <mutex> #include <mutex>
#include <ostream>
#include <string> #include <string>
namespace beast { namespace beast {

View File

@@ -39,16 +39,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#endif #endif
#define XRPL_ASSERT ALWAYS_OR_UNREACHABLE #define XRPL_ASSERT ALWAYS_OR_UNREACHABLE
#define XRPL_ASSERT_PARTS(cond, function, description, ...) \
XRPL_ASSERT(cond, function " : " description)
// How to use the instrumentation macros: // How to use the instrumentation macros:
// //
// * XRPL_ASSERT if cond must be true but the line might not be reached during // * XRPL_ASSERT if cond must be true but the line might not be reached during
// fuzzing. Same like `assert` in normal use. // fuzzing. Same like `assert` in normal use.
// * XRPL_ASSERT_PARTS is for convenience, and works like XRPL_ASSERT, but
// splits the message param into "function" and "description", then joins
// them with " : " before passing to XRPL_ASSERT.
// * ALWAYS if cond must be true _and_ the line must be reached during fuzzing. // * ALWAYS if cond must be true _and_ the line must be reached during fuzzing.
// Same like `assert` in normal use. // Same like `assert` in normal use.
// * REACHABLE if the line must be reached during fuzzing // * REACHABLE if the line must be reached during fuzzing

View File

@@ -31,28 +31,36 @@ namespace beast {
template <class Generator> template <class Generator>
void void
rngfill(void* const buffer, std::size_t const bytes, Generator& g) rngfill(void* buffer, std::size_t bytes, Generator& g)
{ {
using result_type = typename Generator::result_type; using result_type = typename Generator::result_type;
constexpr std::size_t result_size = sizeof(result_type);
std::uint8_t* const buffer_start = static_cast<std::uint8_t*>(buffer); while (bytes >= sizeof(result_type))
std::size_t const complete_iterations = bytes / result_size;
std::size_t const bytes_remaining = bytes % result_size;
for (std::size_t count = 0; count < complete_iterations; ++count)
{ {
result_type const v = g(); auto const v = g();
std::size_t const offset = count * result_size; std::memcpy(buffer, &v, sizeof(v));
std::memcpy(buffer_start + offset, &v, result_size); buffer = reinterpret_cast<std::uint8_t*>(buffer) + sizeof(v);
bytes -= sizeof(v);
} }
if (bytes_remaining > 0) 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.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
if (bytes > 0)
{ {
result_type const v = g(); auto const v = g();
std::size_t const offset = complete_iterations * result_size; std::memcpy(buffer, &v, bytes);
std::memcpy(buffer_start + offset, &v, bytes_remaining);
} }
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
} }
template < template <

View File

@@ -20,7 +20,6 @@
#ifndef RIPPLE_JSON_JSON_VALUE_H_INCLUDED #ifndef RIPPLE_JSON_JSON_VALUE_H_INCLUDED
#define RIPPLE_JSON_JSON_VALUE_H_INCLUDED #define RIPPLE_JSON_JSON_VALUE_H_INCLUDED
#include <xrpl/basics/Number.h>
#include <xrpl/json/json_forwards.h> #include <xrpl/json/json_forwards.h>
#include <cstring> #include <cstring>
@@ -217,7 +216,6 @@ public:
Value(UInt value); Value(UInt value);
Value(double value); Value(double value);
Value(char const* value); Value(char const* value);
Value(ripple::Number const& value);
/** \brief Constructs a value from a static string. /** \brief Constructs a value from a static string.
* Like other value string constructor but do not duplicate the string for * Like other value string constructor but do not duplicate the string for
@@ -367,8 +365,6 @@ public:
*/ */
Value& Value&
operator[](StaticString const& key); operator[](StaticString const& key);
Value const&
operator[](StaticString const& key) const;
/// Return the member named key if it exist, defaultValue otherwise. /// Return the member named key if it exist, defaultValue otherwise.
Value Value
@@ -440,12 +436,6 @@ private:
int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
}; };
inline Value
to_json(ripple::Number const& number)
{
return to_string(number);
}
bool bool
operator==(Value const&, Value const&); operator==(Value const&, Value const&);

View File

@@ -48,6 +48,14 @@ class STObject;
class STAmount; class STAmount;
class Rules; class Rules;
/** Calculate AMM account ID.
*/
AccountID
ammAccountID(
std::uint16_t prefix,
uint256 const& parentHash,
uint256 const& ammID);
/** Calculate Liquidity Provider Token (LPT) Currency. /** Calculate Liquidity Provider Token (LPT) Currency.
*/ */
Currency Currency

View File

@@ -29,6 +29,7 @@
#include <xrpl/protocol/json_get_or_throw.h> #include <xrpl/protocol/json_get_or_throw.h>
#include <cstddef> #include <cstddef>
#include <mutex>
#include <optional> #include <optional>
#include <string> #include <string>
@@ -148,7 +149,7 @@ namespace std {
template <> template <>
struct hash<ripple::AccountID> : ripple::AccountID::hasher struct hash<ripple::AccountID> : ripple::AccountID::hasher
{ {
hash() = default; explicit hash() = default;
}; };
} // namespace std } // namespace std

View File

@@ -20,6 +20,7 @@
#ifndef RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED #ifndef RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED
#define RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED #define RIPPLE_PROTOCOL_APIVERSION_H_INCLUDED
#include <functional>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>

View File

@@ -20,7 +20,6 @@
#ifndef RIPPLE_PROTOCOL_ASSET_H_INCLUDED #ifndef RIPPLE_PROTOCOL_ASSET_H_INCLUDED
#define RIPPLE_PROTOCOL_ASSET_H_INCLUDED #define RIPPLE_PROTOCOL_ASSET_H_INCLUDED
#include <xrpl/basics/Number.h>
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/Issue.h> #include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/MPTIssue.h> #include <xrpl/protocol/MPTIssue.h>
@@ -28,7 +27,6 @@
namespace ripple { namespace ripple {
class Asset; class Asset;
class STAmount;
template <typename TIss> template <typename TIss>
concept ValidIssueType = concept ValidIssueType =
@@ -94,9 +92,6 @@ public:
void void
setJson(Json::Value& jv) const; setJson(Json::Value& jv) const;
STAmount
operator()(Number const&) const;
bool bool
native() const native() const
{ {
@@ -119,14 +114,6 @@ public:
equalTokens(Asset const& lhs, Asset const& rhs); equalTokens(Asset const& lhs, Asset const& rhs);
}; };
inline Json::Value
to_json(Asset const& asset)
{
Json::Value jv;
asset.setJson(jv);
return jv;
}
template <ValidIssueType TIss> template <ValidIssueType TIss>
constexpr bool constexpr bool
Asset::holds() const Asset::holds() const
@@ -232,6 +219,9 @@ validJSONAsset(Json::Value const& jv);
Asset Asset
assetFromJson(Json::Value const& jv); assetFromJson(Json::Value const& jv);
Json::Value
to_json(Asset const& asset);
} // namespace ripple } // namespace ripple
#endif // RIPPLE_PROTOCOL_ASSET_H_INCLUDED #endif // RIPPLE_PROTOCOL_ASSET_H_INCLUDED

View File

@@ -1,37 +0,0 @@
//------------------------------------------------------------------------------
/*
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 <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/STVector256.h>
#include <xrpl/protocol/Serializer.h>
namespace ripple {
inline void
serializeBatch(
Serializer& msg,
std::uint32_t const& flags,
std::vector<uint256> const& txids)
{
msg.add32(HashPrefix::batch);
msg.add32(flags);
msg.add32(std::uint32_t(txids.size()));
for (auto const& txid : txids)
msg.addBitString(txid);
}
} // namespace ripple

View File

@@ -21,7 +21,6 @@
#define RIPPLE_PROTOCOL_BOOK_H_INCLUDED #define RIPPLE_PROTOCOL_BOOK_H_INCLUDED
#include <xrpl/basics/CountedObject.h> #include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/protocol/Issue.h> #include <xrpl/protocol/Issue.h>
#include <boost/utility/base_from_member.hpp> #include <boost/utility/base_from_member.hpp>
@@ -37,17 +36,12 @@ class Book final : public CountedObject<Book>
public: public:
Issue in; Issue in;
Issue out; Issue out;
std::optional<uint256> domain;
Book() Book()
{ {
} }
Book( Book(Issue const& in_, Issue const& out_) : in(in_), out(out_)
Issue const& in_,
Issue const& out_,
std::optional<uint256> const& domain_)
: in(in_), out(out_), domain(domain_)
{ {
} }
}; };
@@ -67,8 +61,6 @@ hash_append(Hasher& h, Book const& b)
{ {
using beast::hash_append; using beast::hash_append;
hash_append(h, b.in, b.out); hash_append(h, b.in, b.out);
if (b.domain)
hash_append(h, *(b.domain));
} }
Book Book
@@ -79,8 +71,7 @@ reversed(Book const& book);
[[nodiscard]] inline constexpr bool [[nodiscard]] inline constexpr bool
operator==(Book const& lhs, Book const& rhs) operator==(Book const& lhs, Book const& rhs)
{ {
return (lhs.in == rhs.in) && (lhs.out == rhs.out) && return (lhs.in == rhs.in) && (lhs.out == rhs.out);
(lhs.domain == rhs.domain);
} }
/** @} */ /** @} */
@@ -91,18 +82,7 @@ operator<=>(Book const& lhs, Book const& rhs)
{ {
if (auto const c{lhs.in <=> rhs.in}; c != 0) if (auto const c{lhs.in <=> rhs.in}; c != 0)
return c; return c;
if (auto const c{lhs.out <=> rhs.out}; c != 0) return lhs.out <=> rhs.out;
return c;
// Manually compare optionals
if (lhs.domain && rhs.domain)
return *lhs.domain <=> *rhs.domain; // Compare values if both exist
if (!lhs.domain && rhs.domain)
return std::weak_ordering::less; // Empty is considered less
if (lhs.domain && !rhs.domain)
return std::weak_ordering::greater; // Non-empty is greater
return std::weak_ordering::equivalent; // Both are empty
} }
/** @} */ /** @} */
@@ -124,7 +104,7 @@ private:
boost::base_from_member<std::hash<ripple::AccountID>, 1>; boost::base_from_member<std::hash<ripple::AccountID>, 1>;
public: public:
hash() = default; explicit hash() = default;
using value_type = std::size_t; using value_type = std::size_t;
using argument_type = ripple::Issue; using argument_type = ripple::Issue;
@@ -146,14 +126,12 @@ template <>
struct hash<ripple::Book> struct hash<ripple::Book>
{ {
private: private:
using issue_hasher = std::hash<ripple::Issue>; using hasher = std::hash<ripple::Issue>;
using uint256_hasher = ripple::uint256::hasher;
issue_hasher m_issue_hasher; hasher m_hasher;
uint256_hasher m_uint256_hasher;
public: public:
hash() = default; explicit hash() = default;
using value_type = std::size_t; using value_type = std::size_t;
using argument_type = ripple::Book; using argument_type = ripple::Book;
@@ -161,12 +139,8 @@ public:
value_type value_type
operator()(argument_type const& value) const operator()(argument_type const& value) const
{ {
value_type result(m_issue_hasher(value.in)); value_type result(m_hasher(value.in));
boost::hash_combine(result, m_issue_hasher(value.out)); boost::hash_combine(result, m_hasher(value.out));
if (value.domain)
boost::hash_combine(result, m_uint256_hasher(*value.domain));
return result; return result;
} }
}; };
@@ -180,7 +154,7 @@ namespace boost {
template <> template <>
struct hash<ripple::Issue> : std::hash<ripple::Issue> struct hash<ripple::Issue> : std::hash<ripple::Issue>
{ {
hash() = default; explicit hash() = default;
using Base = std::hash<ripple::Issue>; using Base = std::hash<ripple::Issue>;
// VFALCO NOTE broken in vs2012 // VFALCO NOTE broken in vs2012
@@ -190,7 +164,7 @@ struct hash<ripple::Issue> : std::hash<ripple::Issue>
template <> template <>
struct hash<ripple::Book> : std::hash<ripple::Book> struct hash<ripple::Book> : std::hash<ripple::Book>
{ {
hash() = default; explicit hash() = default;
using Base = std::hash<ripple::Book>; using Base = std::hash<ripple::Book>;
// VFALCO NOTE broken in vs2012 // VFALCO NOTE broken in vs2012

View File

@@ -154,10 +154,7 @@ enum error_code_i {
// Simulate // Simulate
rpcTX_SIGNED = 96, rpcTX_SIGNED = 96,
// Pathfinding rpcLAST = rpcTX_SIGNED // rpcLAST should always equal the last code.
rpcDOMAIN_MALFORMED = 97,
rpcLAST = rpcDOMAIN_MALFORMED // rpcLAST should always equal the last code.
}; };
/** Codes returned in the `warnings` array of certain RPC commands. /** Codes returned in the `warnings` array of certain RPC commands.
@@ -169,8 +166,6 @@ enum warning_code_i {
warnRPC_AMENDMENT_BLOCKED = 1002, warnRPC_AMENDMENT_BLOCKED = 1002,
warnRPC_EXPIRED_VALIDATOR_LIST = 1003, warnRPC_EXPIRED_VALIDATOR_LIST = 1003,
// unused = 1004 // unused = 1004
warnRPC_FIELDS_DEPRECATED = 2004, // rippled needs to maintain
// compatibility with Clio on this code.
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -24,6 +24,7 @@
#include <boost/container/flat_map.hpp> #include <boost/container/flat_map.hpp>
#include <array>
#include <bitset> #include <bitset>
#include <map> #include <map>
#include <optional> #include <optional>
@@ -53,18 +54,6 @@
* then change the macro parameter in features.macro to * then change the macro parameter in features.macro to
* `VoteBehavior::DefaultYes`. The communication process is beyond * `VoteBehavior::DefaultYes`. The communication process is beyond
* the scope of these instructions. * the scope of these instructions.
* 5) If a supported feature (`Supported::yes`) was _ever_ in a released
* version, it can never be changed back to `Supported::no`, because
* it _may_ still become enabled at any time. This would cause newer
* versions of `rippled` to become amendment blocked.
* Instead, to prevent newer versions from voting on the feature, use
* `VoteBehavior::Obsolete`. Obsolete features can not be voted for
* by any versions of `rippled` built with that setting, but will still
* work correctly if they get enabled. If a feature remains obsolete
* for long enough that _all_ clients that could vote for it are
* amendment blocked, the feature can be removed from the code
* as if it was unsupported.
* *
* *
* When a feature has been enabled for several years, the conditional code * When a feature has been enabled for several years, the conditional code

View File

@@ -16,8 +16,8 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#ifndef PROTOCOL_UNITS_H_INCLUDED #ifndef BASICS_FEES_H_INCLUDED
#define PROTOCOL_UNITS_H_INCLUDED #define BASICS_FEES_H_INCLUDED
#include <xrpl/basics/safe_cast.h> #include <xrpl/basics/safe_cast.h>
#include <xrpl/beast/utility/Zero.h> #include <xrpl/beast/utility/Zero.h>
@@ -27,29 +27,34 @@
#include <boost/multiprecision/cpp_int.hpp> #include <boost/multiprecision/cpp_int.hpp>
#include <boost/operators.hpp> #include <boost/operators.hpp>
#include <cmath>
#include <ios>
#include <iosfwd> #include <iosfwd>
#include <limits> #include <limits>
#include <optional> #include <optional>
#include <sstream>
#include <string>
#include <utility>
namespace ripple { namespace ripple {
namespace unit { namespace feeunit {
/** "drops" are the smallest divisible amount of XRP. This is what most /** "drops" are the smallest divisible amount of XRP. This is what most
of the code uses. */ of the code uses. */
struct dropTag; 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. */
struct feeunitTag;
/** "fee levels" are used by the transaction queue to compare the relative /** "fee levels" are used by the transaction queue to compare the relative
cost of transactions that require different levels of effort to process. cost of transactions that require different levels of effort to process.
See also: src/ripple/app/misc/FeeEscalation.md#fee-level */ See also: src/ripple/app/misc/FeeEscalation.md#fee-level */
struct feelevelTag; struct feelevelTag;
/** unitless values are plain scalars wrapped in a ValueUnit. They are /** unitless values are plain scalars wrapped in a TaggedFee. They are
used for calculations in this header. */ used for calculations in this header. */
struct unitlessTag; struct unitlessTag;
/** Units to represent basis points (bips) and 1/10 basis points */
class BipsTag;
class TenthBipsTag;
template <class T> template <class T>
using enable_if_unit_t = typename std::enable_if_t< using enable_if_unit_t = typename std::enable_if_t<
std::is_class_v<T> && std::is_object_v<typename T::unit_type> && std::is_class_v<T> && std::is_object_v<typename T::unit_type> &&
@@ -57,33 +62,32 @@ using enable_if_unit_t = typename std::enable_if_t<
/** `is_usable_unit_v` is checked to ensure that only values with /** `is_usable_unit_v` is checked to ensure that only values with
known valid type tags can be used (sometimes transparently) in known valid type tags can be used (sometimes transparently) in
non-unit contexts. At the time of implementation, this includes non-fee contexts. At the time of implementation, this includes
all known tags, but more may be added in the future, and they all known tags, but more may be added in the future, and they
should not be added automatically unless determined to be should not be added automatically unless determined to be
appropriate. appropriate.
*/ */
template <class T, class = enable_if_unit_t<T>> template <class T, class = enable_if_unit_t<T>>
constexpr bool is_usable_unit_v = constexpr bool is_usable_unit_v =
std::is_same_v<typename T::unit_type, feeunitTag> ||
std::is_same_v<typename T::unit_type, feelevelTag> || std::is_same_v<typename T::unit_type, feelevelTag> ||
std::is_same_v<typename T::unit_type, unitlessTag> || std::is_same_v<typename T::unit_type, unitlessTag> ||
std::is_same_v<typename T::unit_type, dropTag> || std::is_same_v<typename T::unit_type, dropTag>;
std::is_same_v<typename T::unit_type, BipsTag> ||
std::is_same_v<typename T::unit_type, TenthBipsTag>;
template <class UnitTag, class T> template <class UnitTag, class T>
class ValueUnit : private boost::totally_ordered<ValueUnit<UnitTag, T>>, class TaggedFee : private boost::totally_ordered<TaggedFee<UnitTag, T>>,
private boost::additive<ValueUnit<UnitTag, T>>, private boost::additive<TaggedFee<UnitTag, T>>,
private boost::equality_comparable<ValueUnit<UnitTag, T>, T>, private boost::equality_comparable<TaggedFee<UnitTag, T>, T>,
private boost::dividable<ValueUnit<UnitTag, T>, T>, private boost::dividable<TaggedFee<UnitTag, T>, T>,
private boost::modable<ValueUnit<UnitTag, T>, T>, private boost::modable<TaggedFee<UnitTag, T>, T>,
private boost::unit_steppable<ValueUnit<UnitTag, T>> private boost::unit_steppable<TaggedFee<UnitTag, T>>
{ {
public: public:
using unit_type = UnitTag; using unit_type = UnitTag;
using value_type = T; using value_type = T;
private: private:
value_type value_; value_type fee_;
protected: protected:
template <class Other> template <class Other>
@@ -91,44 +95,44 @@ protected:
std::is_arithmetic_v<Other> && std::is_arithmetic_v<value_type> && std::is_arithmetic_v<Other> && std::is_arithmetic_v<value_type> &&
std::is_convertible_v<Other, value_type>; std::is_convertible_v<Other, value_type>;
template <class OtherValue, class = enable_if_unit_t<OtherValue>> template <class OtherFee, class = enable_if_unit_t<OtherFee>>
static constexpr bool is_compatiblevalue_v = static constexpr bool is_compatiblefee_v =
is_compatible_v<typename OtherValue::value_type> && is_compatible_v<typename OtherFee::value_type> &&
std::is_same_v<UnitTag, typename OtherValue::unit_type>; std::is_same_v<UnitTag, typename OtherFee::unit_type>;
template <class Other> template <class Other>
using enable_if_compatible_t = using enable_if_compatible_t =
typename std::enable_if_t<is_compatible_v<Other>>; typename std::enable_if_t<is_compatible_v<Other>>;
template <class OtherValue> template <class OtherFee>
using enable_if_compatiblevalue_t = using enable_if_compatiblefee_t =
typename std::enable_if_t<is_compatiblevalue_v<OtherValue>>; typename std::enable_if_t<is_compatiblefee_v<OtherFee>>;
public: public:
ValueUnit() = default; TaggedFee() = default;
constexpr ValueUnit(ValueUnit const& other) = default; constexpr TaggedFee(TaggedFee const& other) = default;
constexpr ValueUnit& constexpr TaggedFee&
operator=(ValueUnit const& other) = default; operator=(TaggedFee const& other) = default;
constexpr explicit ValueUnit(beast::Zero) : value_(0) constexpr explicit TaggedFee(beast::Zero) : fee_(0)
{ {
} }
constexpr ValueUnit& constexpr TaggedFee&
operator=(beast::Zero) operator=(beast::Zero)
{ {
value_ = 0; fee_ = 0;
return *this; return *this;
} }
constexpr explicit ValueUnit(value_type value) : value_(value) constexpr explicit TaggedFee(value_type fee) : fee_(fee)
{ {
} }
constexpr ValueUnit& TaggedFee&
operator=(value_type value) operator=(value_type fee)
{ {
value_ = value; fee_ = fee;
return *this; return *this;
} }
@@ -140,181 +144,153 @@ public:
class = std::enable_if_t< class = std::enable_if_t<
is_compatible_v<Other> && is_compatible_v<Other> &&
is_safetocasttovalue_v<value_type, Other>>> is_safetocasttovalue_v<value_type, Other>>>
constexpr ValueUnit(ValueUnit<unit_type, Other> const& value) constexpr TaggedFee(TaggedFee<unit_type, Other> const& fee)
: ValueUnit(safe_cast<value_type>(value.value())) : TaggedFee(safe_cast<value_type>(fee.fee()))
{ {
} }
constexpr ValueUnit constexpr TaggedFee
operator+(value_type const& rhs) const
{
return ValueUnit{value_ + rhs};
}
friend constexpr ValueUnit
operator+(value_type lhs, ValueUnit const& rhs)
{
// addition is commutative
return rhs + lhs;
}
constexpr ValueUnit
operator-(value_type const& rhs) const
{
return ValueUnit{value_ - rhs};
}
friend constexpr ValueUnit
operator-(value_type lhs, ValueUnit const& rhs)
{
// subtraction is NOT commutative, but (lhs + (-rhs)) is addition, which
// is
return -rhs + lhs;
}
constexpr ValueUnit
operator*(value_type const& rhs) const operator*(value_type const& rhs) const
{ {
return ValueUnit{value_ * rhs}; return TaggedFee{fee_ * rhs};
} }
friend constexpr ValueUnit friend constexpr TaggedFee
operator*(value_type lhs, ValueUnit const& rhs) operator*(value_type lhs, TaggedFee const& rhs)
{ {
// multiplication is commutative // multiplication is commutative
return rhs * lhs; return rhs * lhs;
} }
constexpr value_type constexpr value_type
operator/(ValueUnit const& rhs) const operator/(TaggedFee const& rhs) const
{ {
return value_ / rhs.value_; return fee_ / rhs.fee_;
} }
ValueUnit& TaggedFee&
operator+=(ValueUnit const& other) operator+=(TaggedFee const& other)
{ {
value_ += other.value(); fee_ += other.fee();
return *this; return *this;
} }
ValueUnit& TaggedFee&
operator-=(ValueUnit const& other) operator-=(TaggedFee const& other)
{ {
value_ -= other.value(); fee_ -= other.fee();
return *this; return *this;
} }
ValueUnit& TaggedFee&
operator++() operator++()
{ {
++value_; ++fee_;
return *this; return *this;
} }
ValueUnit& TaggedFee&
operator--() operator--()
{ {
--value_; --fee_;
return *this; return *this;
} }
ValueUnit& TaggedFee&
operator*=(value_type const& rhs) operator*=(value_type const& rhs)
{ {
value_ *= rhs; fee_ *= rhs;
return *this; return *this;
} }
ValueUnit& TaggedFee&
operator/=(value_type const& rhs) operator/=(value_type const& rhs)
{ {
value_ /= rhs; fee_ /= rhs;
return *this; return *this;
} }
template <class transparent = value_type> template <class transparent = value_type>
std::enable_if_t<std::is_integral_v<transparent>, ValueUnit&> std::enable_if_t<std::is_integral_v<transparent>, TaggedFee&>
operator%=(value_type const& rhs) operator%=(value_type const& rhs)
{ {
value_ %= rhs; fee_ %= rhs;
return *this; return *this;
} }
ValueUnit TaggedFee
operator-() const operator-() const
{ {
static_assert( static_assert(
std::is_signed_v<T>, "- operator illegal on unsigned value types"); std::is_signed_v<T>, "- operator illegal on unsigned fee types");
return ValueUnit{-value_}; return TaggedFee{-fee_};
} }
constexpr bool bool
operator==(ValueUnit const& other) const operator==(TaggedFee const& other) const
{ {
return value_ == other.value_; return fee_ == other.fee_;
} }
template <class Other, class = enable_if_compatible_t<Other>> template <class Other, class = enable_if_compatible_t<Other>>
constexpr bool bool
operator==(ValueUnit<unit_type, Other> const& other) const operator==(TaggedFee<unit_type, Other> const& other) const
{ {
return value_ == other.value(); return fee_ == other.fee();
} }
constexpr bool bool
operator==(value_type other) const operator==(value_type other) const
{ {
return value_ == other; return fee_ == other;
} }
template <class Other, class = enable_if_compatible_t<Other>> template <class Other, class = enable_if_compatible_t<Other>>
constexpr bool bool
operator!=(ValueUnit<unit_type, Other> const& other) const operator!=(TaggedFee<unit_type, Other> const& other) const
{ {
return !operator==(other); return !operator==(other);
} }
constexpr bool bool
operator<(ValueUnit const& other) const operator<(TaggedFee const& other) const
{ {
return value_ < other.value_; return fee_ < other.fee_;
} }
/** Returns true if the amount is not zero */ /** Returns true if the amount is not zero */
explicit constexpr explicit constexpr
operator bool() const noexcept operator bool() const noexcept
{ {
return value_ != 0; return fee_ != 0;
} }
/** Return the sign of the amount */ /** Return the sign of the amount */
constexpr int constexpr int
signum() const noexcept signum() const noexcept
{ {
return (value_ < 0) ? -1 : (value_ ? 1 : 0); return (fee_ < 0) ? -1 : (fee_ ? 1 : 0);
} }
/** Returns the number of drops */ /** Returns the number of drops */
// TODO: Move this to a new class, maybe with the old "TaggedFee" name
constexpr value_type constexpr value_type
fee() const fee() const
{ {
return value_; return fee_;
} }
template <class Other> template <class Other>
constexpr double constexpr double
decimalFromReference(ValueUnit<unit_type, Other> reference) const decimalFromReference(TaggedFee<unit_type, Other> reference) const
{ {
return static_cast<double>(value_) / reference.value(); return static_cast<double>(fee_) / reference.fee();
} }
// `is_usable_unit_v` is checked to ensure that only values with // `is_usable_unit_v` is checked to ensure that only values with
// known valid type tags can be converted to JSON. At the time // known valid type tags can be converted to JSON. At the time
// of implementation, that includes all known tags, but more may // of implementation, that includes all known tags, but more may
// be added in the future. // be added in the future.
std::enable_if_t<is_usable_unit_v<ValueUnit>, Json::Value> std::enable_if_t<is_usable_unit_v<TaggedFee>, Json::Value>
jsonClipped() const jsonClipped() const
{ {
if constexpr (std::is_integral_v<value_type>) if constexpr (std::is_integral_v<value_type>)
@@ -327,15 +303,15 @@ public:
constexpr auto min = std::numeric_limits<jsontype>::min(); constexpr auto min = std::numeric_limits<jsontype>::min();
constexpr auto max = std::numeric_limits<jsontype>::max(); constexpr auto max = std::numeric_limits<jsontype>::max();
if (value_ < min) if (fee_ < min)
return min; return min;
if (value_ > max) if (fee_ > max)
return max; return max;
return static_cast<jsontype>(value_); return static_cast<jsontype>(fee_);
} }
else else
{ {
return value_; return fee_;
} }
} }
@@ -346,30 +322,30 @@ public:
constexpr value_type constexpr value_type
value() const value() const
{ {
return value_; return fee_;
} }
friend std::istream& friend std::istream&
operator>>(std::istream& s, ValueUnit& val) operator>>(std::istream& s, TaggedFee& val)
{ {
s >> val.value_; s >> val.fee_;
return s; return s;
} }
}; };
// Output Values as just their numeric value. // Output Fees as just their numeric value.
template <class Char, class Traits, class UnitTag, class T> template <class Char, class Traits, class UnitTag, class T>
std::basic_ostream<Char, Traits>& std::basic_ostream<Char, Traits>&
operator<<(std::basic_ostream<Char, Traits>& os, ValueUnit<UnitTag, T> const& q) operator<<(std::basic_ostream<Char, Traits>& os, TaggedFee<UnitTag, T> const& q)
{ {
return os << q.value(); return os << q.value();
} }
template <class UnitTag, class T> template <class UnitTag, class T>
std::string std::string
to_string(ValueUnit<UnitTag, T> const& amount) to_string(TaggedFee<UnitTag, T> const& amount)
{ {
return std::to_string(amount.value()); return std::to_string(amount.fee());
} }
template <class Source, class = enable_if_unit_t<Source>> template <class Source, class = enable_if_unit_t<Source>>
@@ -432,10 +408,10 @@ using enable_muldiv_commute_t =
typename std::enable_if_t<can_muldiv_commute_v<Source1, Source2, Dest>>; typename std::enable_if_t<can_muldiv_commute_v<Source1, Source2, Dest>>;
template <class T> template <class T>
ValueUnit<unitlessTag, T> TaggedFee<unitlessTag, T>
scalar(T value) scalar(T value)
{ {
return ValueUnit<unitlessTag, T>{value}; return TaggedFee<unitlessTag, T>{value};
} }
template < template <
@@ -446,17 +422,18 @@ template <
std::optional<Dest> std::optional<Dest>
mulDivU(Source1 value, Dest mul, Source2 div) mulDivU(Source1 value, Dest mul, Source2 div)
{ {
// values can never be negative in any context. // Fees can never be negative in any context.
if (value.value() < 0 || mul.value() < 0 || div.value() < 0) if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
{ {
// split the asserts so if one hits, the user can tell which // split the asserts so if one hits, the user can tell which
// without a debugger. // without a debugger.
XRPL_ASSERT( XRPL_ASSERT(
value.value() >= 0, "ripple::unit::mulDivU : minimum value input"); value.value() >= 0,
"ripple::feeunit::mulDivU : minimum value input");
XRPL_ASSERT( XRPL_ASSERT(
mul.value() >= 0, "ripple::unit::mulDivU : minimum mul input"); mul.value() >= 0, "ripple::feeunit::mulDivU : minimum mul input");
XRPL_ASSERT( XRPL_ASSERT(
div.value() >= 0, "ripple::unit::mulDivU : minimum div input"); div.value() >= 0, "ripple::feeunit::mulDivU : minimum div input");
return std::nullopt; return std::nullopt;
} }
@@ -489,57 +466,46 @@ mulDivU(Source1 value, Dest mul, Source2 div)
return Dest{static_cast<desttype>(quotient)}; return Dest{static_cast<desttype>(quotient)};
} }
} // namespace unit } // namespace feeunit
// Fee Levels
template <class T> template <class T>
using FeeLevel = unit::ValueUnit<unit::feelevelTag, T>; using FeeLevel = feeunit::TaggedFee<feeunit::feelevelTag, T>;
using FeeLevel64 = FeeLevel<std::uint64_t>; using FeeLevel64 = FeeLevel<std::uint64_t>;
using FeeLevelDouble = FeeLevel<double>; using FeeLevelDouble = FeeLevel<double>;
// Basis points (Bips)
template <class T>
using Bips = unit::ValueUnit<unit::BipsTag, T>;
using Bips16 = Bips<std::uint16_t>;
using Bips32 = Bips<std::uint32_t>;
template <class T>
using TenthBips = unit::ValueUnit<unit::TenthBipsTag, T>;
using TenthBips16 = TenthBips<std::uint16_t>;
using TenthBips32 = TenthBips<std::uint32_t>;
template < template <
class Source1, class Source1,
class Source2, class Source2,
class Dest, class Dest,
class = unit::enable_muldiv_t<Source1, Source2, Dest>> class = feeunit::enable_muldiv_t<Source1, Source2, Dest>>
std::optional<Dest> std::optional<Dest>
mulDiv(Source1 value, Dest mul, Source2 div) mulDiv(Source1 value, Dest mul, Source2 div)
{ {
return unit::mulDivU(value, mul, div); return feeunit::mulDivU(value, mul, div);
} }
template < template <
class Source1, class Source1,
class Source2, class Source2,
class Dest, class Dest,
class = unit::enable_muldiv_commute_t<Source1, Source2, Dest>> class = feeunit::enable_muldiv_commute_t<Source1, Source2, Dest>>
std::optional<Dest> std::optional<Dest>
mulDiv(Dest value, Source1 mul, Source2 div) mulDiv(Dest value, Source1 mul, Source2 div)
{ {
// Multiplication is commutative // Multiplication is commutative
return unit::mulDivU(mul, value, div); return feeunit::mulDivU(mul, value, div);
} }
template <class Dest, class = unit::enable_muldiv_dest_t<Dest>> template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
std::optional<Dest> std::optional<Dest>
mulDiv(std::uint64_t value, Dest mul, std::uint64_t div) mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
{ {
// Give the scalars a non-tag so the // Give the scalars a non-tag so the
// unit-handling version gets called. // unit-handling version gets called.
return unit::mulDivU(unit::scalar(value), mul, unit::scalar(div)); return feeunit::mulDivU(feeunit::scalar(value), mul, feeunit::scalar(div));
} }
template <class Dest, class = unit::enable_muldiv_dest_t<Dest>> template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
std::optional<Dest> std::optional<Dest>
mulDiv(Dest value, std::uint64_t mul, std::uint64_t div) mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
{ {
@@ -550,13 +516,13 @@ mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
template < template <
class Source1, class Source1,
class Source2, class Source2,
class = unit::enable_muldiv_sources_t<Source1, Source2>> class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
std::optional<std::uint64_t> std::optional<std::uint64_t>
mulDiv(Source1 value, std::uint64_t mul, Source2 div) mulDiv(Source1 value, std::uint64_t mul, Source2 div)
{ {
// Give the scalars a dimensionless unit so the // Give the scalars a dimensionless unit so the
// unit-handling version gets called. // unit-handling version gets called.
auto unitresult = unit::mulDivU(value, unit::scalar(mul), div); auto unitresult = feeunit::mulDivU(value, feeunit::scalar(mul), div);
if (!unitresult) if (!unitresult)
return std::nullopt; return std::nullopt;
@@ -567,7 +533,7 @@ mulDiv(Source1 value, std::uint64_t mul, Source2 div)
template < template <
class Source1, class Source1,
class Source2, class Source2,
class = unit::enable_muldiv_sources_t<Source1, Source2>> class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
std::optional<std::uint64_t> std::optional<std::uint64_t>
mulDiv(std::uint64_t value, Source1 mul, Source2 div) mulDiv(std::uint64_t value, Source1 mul, Source2 div)
{ {
@@ -587,16 +553,6 @@ safe_cast(Src s) noexcept
return Dest{safe_cast<typename Dest::value_type>(s.value())}; return Dest{safe_cast<typename Dest::value_type>(s.value())};
} }
template <class Dest, class Src>
constexpr std::enable_if_t<
std::is_integral_v<typename Dest::value_type> && std::is_integral_v<Src>,
Dest>
safe_cast(Src s) noexcept
{
// Dest may not have an explicit value constructor
return Dest{safe_cast<typename Dest::value_type>(s)};
}
template <class Dest, class Src> template <class Dest, class Src>
constexpr std::enable_if_t< constexpr std::enable_if_t<
std::is_same_v<typename Dest::unit_type, typename Src::unit_type> && std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
@@ -609,16 +565,6 @@ unsafe_cast(Src s) noexcept
return Dest{unsafe_cast<typename Dest::value_type>(s.value())}; return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
} }
template <class Dest, class Src>
constexpr std::enable_if_t<
std::is_integral_v<typename Dest::value_type> && std::is_integral_v<Src>,
Dest>
unsafe_cast(Src s) noexcept
{
// Dest may not have an explicit value constructor
return Dest{unsafe_cast<typename Dest::value_type>(s)};
}
} // namespace ripple } // namespace ripple
#endif // PROTOCOL_UNITS_H_INCLUDED #endif // BASICS_FEES_H_INCLUDED

View File

@@ -88,9 +88,6 @@ enum class HashPrefix : std::uint32_t {
/** Credentials signature */ /** Credentials signature */
credential = detail::make_hash_prefix('C', 'R', 'D'), credential = detail::make_hash_prefix('C', 'R', 'D'),
/** Batch */
batch = detail::make_hash_prefix('B', 'C', 'H'),
}; };
template <class Hasher> template <class Hasher>

View File

@@ -28,6 +28,7 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <utility>
namespace ripple { namespace ripple {
@@ -98,12 +99,6 @@ public:
static IOUAmount static IOUAmount
minPositiveAmount(); minPositiveAmount();
friend std::ostream&
operator<<(std::ostream& os, IOUAmount const& x)
{
return os << to_string(x);
}
}; };
inline IOUAmount::IOUAmount(beast::Zero) inline IOUAmount::IOUAmount(beast::Zero)

View File

@@ -32,7 +32,6 @@
#include <xrpl/protocol/jss.h> #include <xrpl/protocol/jss.h>
#include <cstdint> #include <cstdint>
#include <set>
namespace ripple { namespace ripple {
@@ -335,33 +334,6 @@ mptoken(uint256 const& mptokenKey)
Keylet Keylet
mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept; mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept;
Keylet
vault(AccountID const& owner, std::uint32_t seq) noexcept;
inline Keylet
vault(uint256 const& vaultKey)
{
return {ltVAULT, vaultKey};
}
Keylet
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept;
inline Keylet
loanbroker(uint256 const& vaultKey)
{
return {ltLOAN_BROKER, vaultKey};
}
Keylet
loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept;
inline Keylet
loan(uint256 const& vaultKey)
{
return {ltLOAN, vaultKey};
}
Keylet Keylet
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept; permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept;

View File

@@ -24,6 +24,9 @@
#include <xrpl/json/json_value.h> #include <xrpl/json/json_value.h>
#include <xrpl/protocol/UintTypes.h> #include <xrpl/protocol/UintTypes.h>
#include <functional>
#include <type_traits>
namespace ripple { namespace ripple {
/** A currency issued by an account. /** A currency issued by an account.

View File

@@ -145,15 +145,13 @@ enum LedgerSpecificFlags {
0x10000000, // True, reject new paychans 0x10000000, // True, reject new paychans
lsfDisallowIncomingTrustline = lsfDisallowIncomingTrustline =
0x20000000, // True, reject new trustlines (only if no issued assets) 0x20000000, // True, reject new trustlines (only if no issued assets)
lsfAllowTrustLineLocking = // 0x40000000 is available
0x40000000, // True, enable trustline locking
lsfAllowTrustLineClawback = lsfAllowTrustLineClawback =
0x80000000, // True, enable clawback 0x80000000, // True, enable clawback
// ltOFFER // ltOFFER
lsfPassive = 0x00010000, lsfPassive = 0x00010000,
lsfSell = 0x00020000, // True, offer was placed as a sell. lsfSell = 0x00020000, // True, offer was placed as a sell.
lsfHybrid = 0x00040000, // True, offer is hybrid.
// ltRIPPLE_STATE // ltRIPPLE_STATE
lsfLowReserve = 0x00010000, // True, if entry counts toward reserve. lsfLowReserve = 0x00010000, // True, if entry counts toward reserve.
@@ -193,14 +191,6 @@ enum LedgerSpecificFlags {
// ltCREDENTIAL // ltCREDENTIAL
lsfAccepted = 0x00010000, lsfAccepted = 0x00010000,
// ltVAULT
lsfVaultPrivate = 0x00010000,
// ltLOAN
lsfLoanDefault = 0x00010000,
lsfLoanImpaired = 0x00020000,
lsfLoanOverpayment = 0x00040000, // True, loan allows overpayments
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -24,12 +24,15 @@
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/basics/safe_cast.h> #include <xrpl/basics/safe_cast.h>
#include <xrpl/beast/utility/Zero.h> #include <xrpl/beast/utility/Zero.h>
#include <xrpl/json/json_value.h>
#include <boost/multiprecision/cpp_int.hpp> #include <boost/multiprecision/cpp_int.hpp>
#include <boost/operators.hpp> #include <boost/operators.hpp>
#include <cstdint> #include <cstdint>
#include <optional>
#include <string> #include <string>
#include <type_traits>
namespace ripple { namespace ripple {

View File

@@ -42,11 +42,8 @@ public:
AccountID const& AccountID const&
getIssuer() const; getIssuer() const;
constexpr MPTID const& MPTID const&
getMptID() const getMptID() const;
{
return mptID_;
}
std::string std::string
getText() const; getText() const;

View File

@@ -28,6 +28,7 @@
#include <concepts> #include <concepts>
#include <cstdlib> #include <cstdlib>
#include <functional> #include <functional>
#include <limits>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>

View File

@@ -28,8 +28,6 @@
namespace ripple { namespace ripple {
namespace RPC {
/** /**
Adds common synthetic fields to transaction-related JSON responses Adds common synthetic fields to transaction-related JSON responses
@@ -42,7 +40,6 @@ insertNFTSyntheticInJson(
TxMeta const&); TxMeta const&);
/** @} */ /** @} */
} // namespace RPC
} // namespace ripple } // namespace ripple
#endif #endif

View File

@@ -25,6 +25,7 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
namespace ripple { namespace ripple {
/** /**

View File

@@ -23,8 +23,6 @@
#include <xrpl/basics/ByteUtilities.h> #include <xrpl/basics/ByteUtilities.h>
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/basics/partitioned_unordered_map.h> #include <xrpl/basics/partitioned_unordered_map.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/protocol/Units.h>
#include <cstdint> #include <cstdint>
@@ -84,90 +82,6 @@ std::size_t constexpr maxDeletableTokenOfferEntries = 500;
*/ */
std::uint16_t constexpr maxTransferFee = 50000; std::uint16_t constexpr maxTransferFee = 50000;
/** There are 10,000 basis points (bips) in 100%.
*
* Basis points represent 0.01%.
*
* Given a value X, to find the amount for B bps,
* use X * B / bipsPerUnity
*
* Example: If a loan broker has 999 XRP of debt, and must maintain 1,000 bps of
* that debt as cover (10%), then the minimum cover amount is 999,000,000 drops
* * 1000 / bipsPerUnity = 99,900,00 drops or 99.9 XRP.
*
* Given a percentage P, to find the number of bps that percentage represents,
* use P * bipsPerUnity.
*
* Example: 50% is 0.50 * bipsPerUnity = 5,000 bps.
*/
Bips32 constexpr bipsPerUnity(100 * 100);
TenthBips32 constexpr tenthBipsPerUnity(bipsPerUnity.value() * 10);
constexpr Bips32
percentageToBips(std::uint32_t percentage)
{
return Bips32(percentage * bipsPerUnity.value() / 100);
}
constexpr TenthBips32
percentageToTenthBips(std::uint32_t percentage)
{
return TenthBips32(percentage * tenthBipsPerUnity.value() / 100);
}
template <typename T, class TBips>
constexpr T
bipsOfValue(T value, Bips<TBips> bips)
{
return value * bips.value() / bipsPerUnity.value();
}
template <typename T, class TBips>
constexpr T
tenthBipsOfValue(T value, TenthBips<TBips> bips)
{
return value * bips.value() / tenthBipsPerUnity.value();
}
/** The maximum management fee rate allowed by a loan broker in 1/10 bips.
Valid values are between 0 and 10% inclusive.
*/
TenthBips16 constexpr maxManagementFeeRate(
unsafe_cast<std::uint16_t>(percentageToTenthBips(10).value()));
static_assert(maxManagementFeeRate == TenthBips16(std::uint16_t(10'000u)));
/** The maximum coverage rate required of a loan broker in 1/10 bips.
Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxCoverRate = percentageToTenthBips(100);
static_assert(maxCoverRate == TenthBips32(100'000u));
/** The maximum overpayment fee on a loan in 1/10 bips.
*
Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxOverpaymentFee = percentageToTenthBips(100);
/** The maximum premium added to the interest rate for late payments on a loan
* in 1/10 bips.
*
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxLateInterestRate = percentageToTenthBips(100);
/** The maximum close interest rate charged for repaying a loan early in 1/10
* bips.
*
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxCloseInterestRate = percentageToTenthBips(100);
/** The maximum overpayment interest rate charged on loan overpayments in 1/10
* bips.
*
* Valid values are between 0 and 100% inclusive.
*/
TenthBips32 constexpr maxOverpaymentInterestRate = percentageToTenthBips(100);
/** The maximum length of a URI inside an NFT */ /** The maximum length of a URI inside an NFT */
std::size_t constexpr maxTokenURILength = 256; std::size_t constexpr maxTokenURILength = 256;
@@ -202,16 +116,6 @@ std::size_t constexpr maxMPTokenMetadataLength = 1024;
/** The maximum amount of MPTokenIssuance */ /** The maximum amount of MPTokenIssuance */
std::uint64_t constexpr maxMPTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull; std::uint64_t constexpr maxMPTokenAmount = 0x7FFF'FFFF'FFFF'FFFFull;
/** The maximum length of Data payload */
std::size_t constexpr maxDataPayloadLength = 256;
/** Vault withdrawal policies */
std::uint8_t constexpr vaultStrategyFirstComeFirstServe = 1;
/** Maximum recursion depth for vault shares being put as an asset inside
* another vault; counted from 0 */
std::uint8_t constexpr maxAssetCheckDepth = 5;
/** A ledger index. */ /** A ledger index. */
using LedgerIndex = std::uint32_t; using LedgerIndex = std::uint32_t;
@@ -255,9 +159,6 @@ std::size_t constexpr maxTrim = 25;
*/ */
std::size_t constexpr permissionMaxSize = 10; std::size_t constexpr permissionMaxSize = 10;
/** The maximum number of transactions that can be in a batch. */
std::size_t constexpr maxBatchTxCount = 8;
} // namespace ripple } // namespace ripple
#endif #endif

View File

@@ -32,6 +32,7 @@
#include <cstring> #include <cstring>
#include <optional> #include <optional>
#include <ostream> #include <ostream>
#include <utility>
namespace ripple { namespace ripple {

View File

@@ -28,9 +28,6 @@
namespace ripple { namespace ripple {
bool
isFeatureEnabled(uint256 const& feature);
class DigestAwareReadView; class DigestAwareReadView;
/** Rules controlling protocol behavior. */ /** Rules controlling protocol behavior. */

View File

@@ -22,10 +22,10 @@
#include <xrpl/basics/safe_cast.h> #include <xrpl/basics/safe_cast.h>
#include <xrpl/json/json_value.h> #include <xrpl/json/json_value.h>
#include <xrpl/protocol/Units.h>
#include <cstdint> #include <cstdint>
#include <map> #include <map>
#include <utility>
namespace ripple { namespace ripple {
@@ -137,8 +137,8 @@ field_code(int id, int index)
SFields are created at compile time. SFields are created at compile time.
Each SField, once constructed, lives until program termination, and there Each SField, once constructed, lives until program termination, and there
is only one instance per fieldType/fieldValue pair which serves the is only one instance per fieldType/fieldValue pair which serves the entire
entire application. application.
*/ */
class SField class SField
{ {
@@ -149,10 +149,8 @@ public:
sMD_ChangeNew = 0x02, // new value when it changes sMD_ChangeNew = 0x02, // new value when it changes
sMD_DeleteFinal = 0x04, // final value when it is deleted sMD_DeleteFinal = 0x04, // final value when it is deleted
sMD_Create = 0x08, // value when it's created sMD_Create = 0x08, // value when it's created
sMD_Always = 0x10, // value when node containing it is affected at all sMD_Always = 0x10, // value when node containing it is affected at all
sMD_BaseTen = 0x20, // value is treated as base 10, overriding behavior sMD_BaseTen = 0x20,
sMD_PseudoAccount = 0x40, // if this field is set in an ACCOUNT_ROOT
// _only_, then it is a pseudo-account
sMD_Default = sMD_Default =
sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create
}; };
@@ -309,7 +307,6 @@ public:
private: private:
static int num; static int num;
static std::map<int, SField const*> knownCodeToField; static std::map<int, SField const*> knownCodeToField;
static std::map<std::string, SField const*> knownNameToField;
}; };
/** A field with a type known at compile time. */ /** A field with a type known at compile time. */

View File

@@ -25,6 +25,7 @@
#include <functional> #include <functional>
#include <initializer_list> #include <initializer_list>
#include <memory>
#include <stdexcept> #include <stdexcept>
namespace ripple { namespace ripple {

View File

@@ -153,12 +153,6 @@ public:
template <AssetType A> template <AssetType A>
STAmount(A const& asset, int mantissa, int exponent = 0); STAmount(A const& asset, int mantissa, int exponent = 0);
template <AssetType A>
STAmount(A const& asset, Number const& number)
: STAmount(asset, number.mantissa(), number.exponent())
{
}
// Legacy support for new-style amounts // Legacy support for new-style amounts
STAmount(IOUAmount const& amount, Issue const& issue); STAmount(IOUAmount const& amount, Issue const& issue);
STAmount(XRPAmount const& amount); STAmount(XRPAmount const& amount);
@@ -236,9 +230,6 @@ public:
STAmount& STAmount&
operator=(XRPAmount const& amount); operator=(XRPAmount const& amount);
STAmount&
operator=(Number const&);
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// //
// Modification // Modification
@@ -277,7 +268,7 @@ public:
std::string std::string
getText() const override; getText() const override;
Json::Value getJson(JsonOptions = JsonOptions::none) const override; Json::Value getJson(JsonOptions) const override;
void void
add(Serializer& s) const override; add(Serializer& s) const override;
@@ -426,7 +417,7 @@ STAmount
amountFromQuality(std::uint64_t rate); amountFromQuality(std::uint64_t rate);
STAmount STAmount
amountFromString(Asset const& asset, std::string const& amount); amountFromString(Asset const& issue, std::string const& amount);
STAmount STAmount
amountFromJson(SField const& name, Json::Value const& v); amountFromJson(SField const& name, Json::Value const& v);
@@ -550,16 +541,6 @@ STAmount::operator=(XRPAmount const& amount)
return *this; return *this;
} }
inline STAmount&
STAmount::operator=(Number const& number)
{
mIsNegative = number.mantissa() < 0;
mValue = mIsNegative ? -number.mantissa() : number.mantissa();
mOffset = number.exponent();
canonicalize();
return *this;
}
inline void inline void
STAmount::negate() STAmount::negate()
{ {
@@ -695,36 +676,6 @@ divRoundStrict(
std::uint64_t std::uint64_t
getRate(STAmount const& offerOut, STAmount const& offerIn); getRate(STAmount const& offerOut, STAmount const& offerIn);
STAmount
roundToReference(
STAmount const value,
STAmount referenceValue,
Number::rounding_mode rounding = Number::getround());
/** Round an arbitrary precision Number to the precision of a given Asset.
*
* @param asset The relevant asset
* @param value The value to be rounded
* @param referenceValue Only relevant to IOU assets. A reference value to
* establish the precision limit of `value`. Should be larger than
* `value`.
* @param rounding Optional Number rounding mode
*/
template <AssetType A>
Number
roundToAsset(
A const& asset,
Number const& value,
Number const& referenceValue,
Number::rounding_mode rounding = Number::getround())
{
NumberRoundModeGuard mg(rounding);
STAmount const ret{asset, value};
if (ret.asset().native() || !ret.asset().holds<Issue>())
return ret;
return roundToReference(ret, STAmount{asset, referenceValue});
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
inline bool inline bool
@@ -733,16 +684,10 @@ isXRP(STAmount const& amount)
return amount.native(); return amount.native();
} }
bool // Since `canonicalize` does not have access to a ledger, this is needed to put
canAdd(STAmount const& amt1, STAmount const& amt2); // the low-level routine stAmountCanonicalize on an amendment switch. Only
// transactions need to use this switchover. Outside of a transaction it's safe
bool // to unconditionally use the new behavior.
canSubtract(STAmount const& amt1, STAmount const& amt2);
// Since `canonicalize` does not have access to a ledger, this is needed to
// put the low-level routine stAmountCanonicalize on an amendment switch.
// Only transactions need to use this switchover. Outside of a transaction
// it's safe to unconditionally use the new behavior.
bool bool
getSTAmountCanonicalizeSwitchover(); getSTAmountCanonicalizeSwitchover();

View File

@@ -24,6 +24,7 @@
#include <xrpl/protocol/SField.h> #include <xrpl/protocol/SField.h>
#include <xrpl/protocol/Serializer.h> #include <xrpl/protocol/Serializer.h>
#include <memory>
#include <ostream> #include <ostream>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
@@ -91,16 +92,6 @@ struct JsonOptions
} }
}; };
template <typename T>
requires requires(T const& t) {
{ t.getJson(JsonOptions::none) } -> std::convertible_to<Json::Value>;
}
Json::Value
to_json(T const& t)
{
return t.getJson(JsonOptions::none);
}
namespace detail { namespace detail {
class STVar; class STVar;
} }
@@ -166,7 +157,7 @@ public:
virtual std::string virtual std::string
getText() const; getText() const;
virtual Json::Value getJson(JsonOptions = JsonOptions::none) const; virtual Json::Value getJson(JsonOptions /*options*/) const;
virtual void virtual void
add(Serializer& s) const; add(Serializer& s) const;

View File

@@ -27,6 +27,7 @@
#include <xrpl/protocol/STBase.h> #include <xrpl/protocol/STBase.h>
#include <cstring> #include <cstring>
#include <memory>
namespace ripple { namespace ripple {

View File

@@ -37,7 +37,6 @@ public:
using value_type = Asset; using value_type = Asset;
STIssue() = default; STIssue() = default;
STIssue(STIssue const& rhs) = default;
explicit STIssue(SerialIter& sit, SField const& name); explicit STIssue(SerialIter& sit, SField const& name);
@@ -46,9 +45,6 @@ public:
explicit STIssue(SField const& name); explicit STIssue(SField const& name);
STIssue&
operator=(STIssue const& rhs) = default;
template <ValidIssueType TIss> template <ValidIssueType TIss>
TIss const& TIss const&
get() const; get() const;

View File

@@ -26,9 +26,7 @@
namespace ripple { namespace ripple {
class Rules; class Rules;
namespace test {
class Invariants_test; class Invariants_test;
}
class STLedgerEntry final : public STObject, public CountedObject<STLedgerEntry> class STLedgerEntry final : public STObject, public CountedObject<STLedgerEntry>
{ {
@@ -38,8 +36,6 @@ class STLedgerEntry final : public STObject, public CountedObject<STLedgerEntry>
public: public:
using pointer = std::shared_ptr<STLedgerEntry>; using pointer = std::shared_ptr<STLedgerEntry>;
using ref = std::shared_ptr<STLedgerEntry> const&; using ref = std::shared_ptr<STLedgerEntry> const&;
using const_pointer = std::shared_ptr<STLedgerEntry const>;
using const_ref = std::shared_ptr<STLedgerEntry const> const&;
/** Create an empty object with the given key and type. */ /** Create an empty object with the given key and type. */
explicit STLedgerEntry(Keylet const& k); explicit STLedgerEntry(Keylet const& k);
@@ -58,7 +54,7 @@ public:
getText() const override; getText() const override;
Json::Value Json::Value
getJson(JsonOptions options = JsonOptions::none) const override; getJson(JsonOptions options) const override;
/** Returns the 'key' (or 'index') of this item. /** Returns the 'key' (or 'index') of this item.
The key identifies this entry's position in The key identifies this entry's position in
@@ -88,8 +84,7 @@ private:
void void
setSLEType(); setSLEType();
friend test::Invariants_test; // this test wants access to the private friend Invariants_test; // this test wants access to the private type_
// type_
STBase* STBase*
copy(std::size_t n, void* buf) const override; copy(std::size_t n, void* buf) const override;

View File

@@ -63,13 +63,6 @@ public:
void void
setValue(Number const& v); setValue(Number const& v);
STNumber&
operator=(Number const& rhs)
{
setValue(rhs);
return *this;
}
bool bool
isEquivalent(STBase const& t) const override; isEquivalent(STBase const& t) const override;
bool bool
@@ -90,19 +83,6 @@ private:
std::ostream& std::ostream&
operator<<(std::ostream& out, STNumber const& rhs); operator<<(std::ostream& out, STNumber const& rhs);
struct NumberParts
{
std::uint64_t mantissa = 0;
int exponent = 0;
bool negative = false;
};
NumberParts
partsFromString(std::string const& number);
STNumber
numberFromJson(SField const& field, Json::Value const& value);
} // namespace ripple } // namespace ripple
#endif #endif

View File

@@ -25,6 +25,7 @@
#include <xrpl/basics/chrono.h> #include <xrpl/basics/chrono.h>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/FeeUnits.h>
#include <xrpl/protocol/HashPrefix.h> #include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/SOTemplate.h> #include <xrpl/protocol/SOTemplate.h>
#include <xrpl/protocol/STAmount.h> #include <xrpl/protocol/STAmount.h>
@@ -33,7 +34,6 @@
#include <xrpl/protocol/STIssue.h> #include <xrpl/protocol/STIssue.h>
#include <xrpl/protocol/STPathSet.h> #include <xrpl/protocol/STPathSet.h>
#include <xrpl/protocol/STVector256.h> #include <xrpl/protocol/STVector256.h>
#include <xrpl/protocol/Units.h>
#include <xrpl/protocol/detail/STVar.h> #include <xrpl/protocol/detail/STVar.h>
#include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/transform_iterator.hpp>
@@ -154,7 +154,8 @@ public:
getText() const override; getText() const override;
// TODO(tom): options should be an enum. // TODO(tom): options should be an enum.
Json::Value getJson(JsonOptions = JsonOptions::none) const override; Json::Value
getJson(JsonOptions options) const override;
void void
addWithoutSigningFields(Serializer& s) const; addWithoutSigningFields(Serializer& s) const;
@@ -242,9 +243,6 @@ public:
getFieldPathSet(SField const& field) const; getFieldPathSet(SField const& field) const;
STVector256 const& STVector256 const&
getFieldV256(SField const& field) const; getFieldV256(SField const& field) const;
// If not found, returns an object constructed with the given field
STObject
getFieldObject(SField const& field) const;
STArray const& STArray const&
getFieldArray(SField const& field) const; getFieldArray(SField const& field) const;
STCurrency const& STCurrency const&
@@ -486,19 +484,9 @@ private:
template <class T> template <class T>
class STObject::Proxy class STObject::Proxy
{ {
public: protected:
using value_type = typename T::value_type; using value_type = typename T::value_type;
value_type
value() const;
value_type
operator*() const;
T const*
operator->() const;
protected:
STObject* st_; STObject* st_;
SOEStyle style_; SOEStyle style_;
TypedField<T> const* f_; TypedField<T> const* f_;
@@ -507,6 +495,9 @@ protected:
Proxy(STObject* st, TypedField<T> const* f); Proxy(STObject* st, TypedField<T> const* f);
value_type
value() const;
T const* T const*
find() const; find() const;
@@ -518,29 +509,10 @@ protected:
// Constraint += and -= ValueProxy operators // Constraint += and -= ValueProxy operators
// to value types that support arithmetic operations // to value types that support arithmetic operations
template <typename U> template <typename U>
concept IsArithmeticNumber = std::is_arithmetic_v<U> || concept IsArithmetic = std::is_arithmetic_v<U> || std::is_same_v<U, STAmount>;
std::is_same_v<U, Number> || std::is_same_v<U, STAmount>;
template <
typename U,
typename Value = typename U::value_type,
typename Unit = typename U::unit_type>
concept IsArithmeticValueUnit =
std::is_same_v<U, unit::ValueUnit<Unit, Value>> &&
IsArithmeticNumber<Value> && std::is_class_v<Unit>;
template <typename U, typename Value = typename U::value_type>
concept IsArithmeticST = !IsArithmeticValueUnit<U> && IsArithmeticNumber<Value>;
template <typename U>
concept IsArithmetic =
IsArithmeticNumber<U> || IsArithmeticST<U> || IsArithmeticValueUnit<U>;
template <class T, class U>
concept Addable = requires(T t, U u) { t = t + u; };
template <typename T, typename U>
concept IsArithmeticCompatible =
IsArithmetic<typename T::value_type> && Addable<typename T::value_type, U>;
template <class T> template <class T>
class STObject::ValueProxy : public Proxy<T> class STObject::ValueProxy : private Proxy<T>
{ {
private: private:
using value_type = typename T::value_type; using value_type = typename T::value_type;
@@ -557,24 +529,15 @@ public:
// Convenience operators for value types supporting // Convenience operators for value types supporting
// arithmetic operations // arithmetic operations
template <IsArithmetic U> template <IsArithmetic U>
requires IsArithmeticCompatible<T, U>
ValueProxy& ValueProxy&
operator+=(U const& u); operator+=(U const& u);
template <IsArithmetic U> template <IsArithmetic U>
requires IsArithmeticCompatible<T, U>
ValueProxy& ValueProxy&
operator-=(U const& u); operator-=(U const& u);
operator value_type() const; operator value_type() const;
template <typename U>
friend bool
operator==(U const& lhs, STObject::ValueProxy<T> const& rhs)
{
return rhs.value() == lhs;
}
private: private:
friend class STObject; friend class STObject;
@@ -582,7 +545,7 @@ private:
}; };
template <class T> template <class T>
class STObject::OptionalProxy : public Proxy<T> class STObject::OptionalProxy : private Proxy<T>
{ {
private: private:
using value_type = typename T::value_type; using value_type = typename T::value_type;
@@ -602,6 +565,15 @@ public:
explicit explicit
operator bool() const noexcept; operator bool() const noexcept;
/** Return the contained value
Throws:
STObject::FieldErr if !engaged()
*/
value_type
operator*() const;
operator optional_type() const; operator optional_type() const;
/** Explicit conversion to std::optional */ /** Explicit conversion to std::optional */
@@ -745,20 +717,6 @@ STObject::Proxy<T>::value() const -> value_type
return value_type{}; return value_type{};
} }
template <class T>
auto
STObject::Proxy<T>::operator*() const -> value_type
{
return this->value();
}
template <class T>
T const*
STObject::Proxy<T>::operator->() const
{
return this->find();
}
template <class T> template <class T>
inline T const* inline T const*
STObject::Proxy<T>::find() const STObject::Proxy<T>::find() const
@@ -798,7 +756,6 @@ STObject::ValueProxy<T>::operator=(U&& u)
template <typename T> template <typename T>
template <IsArithmetic U> template <IsArithmetic U>
requires IsArithmeticCompatible<T, U>
STObject::ValueProxy<T>& STObject::ValueProxy<T>&
STObject::ValueProxy<T>::operator+=(U const& u) STObject::ValueProxy<T>::operator+=(U const& u)
{ {
@@ -808,7 +765,6 @@ STObject::ValueProxy<T>::operator+=(U const& u)
template <class T> template <class T>
template <IsArithmetic U> template <IsArithmetic U>
requires IsArithmeticCompatible<T, U>
STObject::ValueProxy<T>& STObject::ValueProxy<T>&
STObject::ValueProxy<T>::operator-=(U const& u) STObject::ValueProxy<T>::operator-=(U const& u)
{ {
@@ -836,6 +792,13 @@ STObject::OptionalProxy<T>::operator bool() const noexcept
return engaged(); return engaged();
} }
template <class T>
auto
STObject::OptionalProxy<T>::operator*() const -> value_type
{
return this->value();
}
template <class T> template <class T>
STObject::OptionalProxy<T>::operator typename STObject::OptionalProxy< STObject::OptionalProxy<T>::operator typename STObject::OptionalProxy<
T>::optional_type() const T>::optional_type() const

View File

@@ -88,13 +88,7 @@ public:
// Outer transaction functions / signature functions. // Outer transaction functions / signature functions.
Blob Blob
getSignature(STObject const& sigObject) const; getSignature() const;
Blob
getSignature() const
{
return getSignature(*this);
}
uint256 uint256
getSigningHash() const; getSigningHash() const;
@@ -108,10 +102,6 @@ public:
SeqProxy SeqProxy
getSeqProxy() const; getSeqProxy() const;
/** Returns the first non-zero value of (Sequence, TicketSequence). */
std::uint32_t
getSeqValue() const;
boost::container::flat_set<AccountID> boost::container::flat_set<AccountID>
getMentionedAccounts() const; getMentionedAccounts() const;
@@ -127,37 +117,14 @@ public:
void void
sign(PublicKey const& publicKey, SecretKey const& secretKey); sign(PublicKey const& publicKey, SecretKey const& secretKey);
/** Check the signature.
@return `true` if valid signature. If invalid, the error message string.
*/
enum class RequireFullyCanonicalSig : bool { no, yes }; enum class RequireFullyCanonicalSig : bool { no, yes };
/** Check the signature.
@param requireCanonicalSig If `true`, check that the signature is fully
canonical. If `false`, only check that the signature is valid.
@param rules The current ledger rules.
@param pSig Pointer to object that contains the signature fields, if not
using "this". Will most often be null
@return `true` if valid signature. If invalid, the error message string.
*/
Expected<void, std::string>
checkSign(
RequireFullyCanonicalSig requireCanonicalSig,
Rules const& rules,
STObject const* pSig) const;
/** Check the signature.
@param requireCanonicalSig If `true`, check that the signature is fully
canonical. If `false`, only check that the signature is valid.
@param rules The current ledger rules.
@return `true` if valid signature. If invalid, the error message string.
*/
Expected<void, std::string> Expected<void, std::string>
checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const& rules) checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const& rules)
const; const;
Expected<void, std::string>
checkBatchSign(
RequireFullyCanonicalSig requireCanonicalSig,
Rules const& rules) const;
// SQL Functions with metadata. // SQL Functions with metadata.
static std::string const& static std::string const&
getMetaSQLInsertReplaceHeader(); getMetaSQLInsertReplaceHeader();
@@ -173,29 +140,12 @@ public:
char status, char status,
std::string const& escapedMetaData) const; std::string const& escapedMetaData) const;
std::vector<uint256>
getBatchTransactionIDs() const;
private: private:
Expected<void, std::string> Expected<void, std::string>
checkSingleSign( checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig) const;
RequireFullyCanonicalSig requireCanonicalSig,
STObject const* pSig) const;
Expected<void, std::string> Expected<void, std::string>
checkMultiSign( checkMultiSign(
RequireFullyCanonicalSig requireCanonicalSig,
Rules const& rules,
STObject const* pSig) const;
Expected<void, std::string>
checkBatchSingleSign(
STObject const& batchSigner,
RequireFullyCanonicalSig requireCanonicalSig) const;
Expected<void, std::string>
checkBatchMultiSign(
STObject const& batchSigner,
RequireFullyCanonicalSig requireCanonicalSig, RequireFullyCanonicalSig requireCanonicalSig,
Rules const& rules) const; Rules const& rules) const;
@@ -205,7 +155,6 @@ private:
move(std::size_t n, void* buf) override; move(std::size_t n, void* buf) override;
friend class detail::STVar; friend class detail::STVar;
mutable std::vector<uint256> batch_txn_ids_;
}; };
bool bool

View File

@@ -22,12 +22,14 @@
#include <xrpl/basics/Log.h> #include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/FeeUnits.h>
#include <xrpl/protocol/PublicKey.h> #include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/STObject.h> #include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/SecretKey.h> #include <xrpl/protocol/SecretKey.h>
#include <xrpl/protocol/Units.h>
#include <cstdint> #include <cstdint>
#include <functional>
#include <memory>
#include <optional> #include <optional>
#include <sstream> #include <sstream>

View File

@@ -33,6 +33,7 @@
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <iomanip>
#include <type_traits> #include <type_traits>
namespace ripple { namespace ripple {

View File

@@ -25,6 +25,8 @@
#include <xrpl/protocol/STObject.h> #include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/SecretKey.h> #include <xrpl/protocol/SecretKey.h>
#include <utility>
namespace ripple { namespace ripple {
/** Sign an STObject /** Sign an STObject

View File

@@ -139,8 +139,8 @@ enum TEMcodes : TERUnderlyingType {
temARRAY_EMPTY, temARRAY_EMPTY,
temARRAY_TOO_LARGE, temARRAY_TOO_LARGE,
temBAD_TRANSFER_FEE, temBAD_TRANSFER_FEE,
temINVALID_INNER_BATCH,
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -225,8 +225,6 @@ enum TERcodes : TERUnderlyingType {
terQUEUED, // Transaction is being held in TxQ until fee drops terQUEUED, // Transaction is being held in TxQ until fee drops
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
terNO_AMM, // AMM doesn't exist for the asset pair terNO_AMM, // AMM doesn't exist for the asset pair
terADDRESS_COLLISION, // Failed to allocate AccountID when trying to
// create a pseudo-account
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -267,17 +265,6 @@ enum TECcodes : TERUnderlyingType {
// Otherwise, treated as terRETRY. // Otherwise, treated as terRETRY.
// //
// DO NOT CHANGE THESE NUMBERS: They appear in ledger meta data. // DO NOT CHANGE THESE NUMBERS: They appear in ledger meta data.
//
// Note:
// tecNO_ENTRY is often used interchangeably with tecOBJECT_NOT_FOUND.
// While there does not seem to be a clear rule which to use when, the
// following guidance will help to keep errors consistent with the
// majority of (but not all) transaction types:
// - tecNO_ENTRY : cannot find the primary ledger object on which the
// transaction is being attempted
// - tecOBJECT_NOT_FOUND : cannot find the additional object(s) needed to
// complete the transaction
tecCLAIM = 100, tecCLAIM = 100,
tecPATH_PARTIAL = 101, tecPATH_PARTIAL = 101,
tecUNFUNDED_ADD = 102, // Unused legacy code tecUNFUNDED_ADD = 102, // Unused legacy code
@@ -357,11 +344,6 @@ enum TECcodes : TERUnderlyingType {
tecARRAY_TOO_LARGE = 191, tecARRAY_TOO_LARGE = 191,
tecLOCKED = 192, tecLOCKED = 192,
tecBAD_CREDENTIALS = 193, tecBAD_CREDENTIALS = 193,
tecWRONG_ASSET = 194,
tecLIMIT_EXCEEDED = 195,
tecPSEUDO_ACCOUNT = 196,
tecPRECISION_LOSS = 197,
tecNO_DELEGATE_PERMISSION = 198,
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -647,37 +629,37 @@ using TER = TERSubset<CanCvtToTER>;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
inline bool inline bool
isTelLocal(TER x) noexcept isTelLocal(TER x)
{ {
return (x >= telLOCAL_ERROR && x < temMALFORMED); return ((x) >= telLOCAL_ERROR && (x) < temMALFORMED);
} }
inline bool inline bool
isTemMalformed(TER x) noexcept isTemMalformed(TER x)
{ {
return (x >= temMALFORMED && x < tefFAILURE); return ((x) >= temMALFORMED && (x) < tefFAILURE);
} }
inline bool inline bool
isTefFailure(TER x) noexcept isTefFailure(TER x)
{ {
return (x >= tefFAILURE && x < terRETRY); return ((x) >= tefFAILURE && (x) < terRETRY);
} }
inline bool inline bool
isTerRetry(TER x) noexcept isTerRetry(TER x)
{ {
return (x >= terRETRY && x < tesSUCCESS); return ((x) >= terRETRY && (x) < tesSUCCESS);
} }
inline bool inline bool
isTesSuccess(TER x) noexcept isTesSuccess(TER x)
{ {
return (x == tesSUCCESS); return ((x) == tesSUCCESS);
} }
inline bool inline bool
isTecClaim(TER x) noexcept isTecClaim(TER x)
{ {
return ((x) >= tecCLAIM); return ((x) >= tecCLAIM);
} }

View File

@@ -58,8 +58,7 @@ namespace ripple {
// clang-format off // clang-format off
// Universal Transaction flags: // Universal Transaction flags:
constexpr std::uint32_t tfFullyCanonicalSig = 0x80000000; constexpr std::uint32_t tfFullyCanonicalSig = 0x80000000;
constexpr std::uint32_t tfInnerBatchTxn = 0x40000000; constexpr std::uint32_t tfUniversal = tfFullyCanonicalSig;
constexpr std::uint32_t tfUniversal = tfFullyCanonicalSig | tfInnerBatchTxn;
constexpr std::uint32_t tfUniversalMask = ~tfUniversal; constexpr std::uint32_t tfUniversalMask = ~tfUniversal;
// AccountSet flags: // AccountSet flags:
@@ -92,16 +91,14 @@ constexpr std::uint32_t asfDisallowIncomingCheck = 13;
constexpr std::uint32_t asfDisallowIncomingPayChan = 14; constexpr std::uint32_t asfDisallowIncomingPayChan = 14;
constexpr std::uint32_t asfDisallowIncomingTrustline = 15; constexpr std::uint32_t asfDisallowIncomingTrustline = 15;
constexpr std::uint32_t asfAllowTrustLineClawback = 16; constexpr std::uint32_t asfAllowTrustLineClawback = 16;
constexpr std::uint32_t asfAllowTrustLineLocking = 17;
// OfferCreate flags: // OfferCreate flags:
constexpr std::uint32_t tfPassive = 0x00010000; constexpr std::uint32_t tfPassive = 0x00010000;
constexpr std::uint32_t tfImmediateOrCancel = 0x00020000; constexpr std::uint32_t tfImmediateOrCancel = 0x00020000;
constexpr std::uint32_t tfFillOrKill = 0x00040000; constexpr std::uint32_t tfFillOrKill = 0x00040000;
constexpr std::uint32_t tfSell = 0x00080000; constexpr std::uint32_t tfSell = 0x00080000;
constexpr std::uint32_t tfHybrid = 0x00100000;
constexpr std::uint32_t tfOfferCreateMask = constexpr std::uint32_t tfOfferCreateMask =
~(tfUniversal | tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell | tfHybrid); ~(tfUniversal | tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
// Payment flags: // Payment flags:
constexpr std::uint32_t tfNoRippleDirect = 0x00010000; constexpr std::uint32_t tfNoRippleDirect = 0x00010000;
@@ -122,13 +119,17 @@ constexpr std::uint32_t tfClearDeepFreeze = 0x00800000;
constexpr std::uint32_t tfTrustSetMask = constexpr std::uint32_t tfTrustSetMask =
~(tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple | tfSetFreeze | ~(tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple | tfSetFreeze |
tfClearFreeze | tfSetDeepFreeze | tfClearDeepFreeze); tfClearFreeze | tfSetDeepFreeze | tfClearDeepFreeze);
constexpr std::uint32_t tfTrustSetPermissionMask = ~(tfUniversal | tfSetfAuth | tfSetFreeze | tfClearFreeze);
// valid flags for granular permission
constexpr std::uint32_t tfTrustSetGranularMask = tfSetfAuth | tfSetFreeze | tfClearFreeze;
// bits representing supportedGranularMask are set to 0 and the bits
// representing other flags are set to 1 in tfPermissionMask.
constexpr std::uint32_t tfTrustSetPermissionMask = (~tfTrustSetMask) & (~tfTrustSetGranularMask);
// EnableAmendment flags: // EnableAmendment flags:
constexpr std::uint32_t tfGotMajority = 0x00010000; constexpr std::uint32_t tfGotMajority = 0x00010000;
constexpr std::uint32_t tfLostMajority = 0x00020000; constexpr std::uint32_t tfLostMajority = 0x00020000;
constexpr std::uint32_t tfChangeMask =
~( tfUniversal | tfGotMajority | tfLostMajority);
// PaymentChannelClaim flags: // PaymentChannelClaim flags:
constexpr std::uint32_t tfRenew = 0x00010000; constexpr std::uint32_t tfRenew = 0x00010000;
@@ -143,8 +144,7 @@ constexpr std::uint32_t const tfTransferable = 0x00000008;
constexpr std::uint32_t const tfMutable = 0x00000010; constexpr std::uint32_t const tfMutable = 0x00000010;
// MPTokenIssuanceCreate flags: // MPTokenIssuanceCreate flags:
// NOTE - there is intentionally no flag here for lsfMPTLocked, which // NOTE - there is intentionally no flag here for lsfMPTLocked, which this transaction cannot mutate.
// this transaction cannot mutate.
constexpr std::uint32_t const tfMPTCanLock = lsfMPTCanLock; constexpr std::uint32_t const tfMPTCanLock = lsfMPTCanLock;
constexpr std::uint32_t const tfMPTRequireAuth = lsfMPTRequireAuth; constexpr std::uint32_t const tfMPTRequireAuth = lsfMPTRequireAuth;
constexpr std::uint32_t const tfMPTCanEscrow = lsfMPTCanEscrow; constexpr std::uint32_t const tfMPTCanEscrow = lsfMPTCanEscrow;
@@ -162,7 +162,8 @@ constexpr std::uint32_t const tfMPTokenAuthorizeMask = ~(tfUniversal | tfMPTUna
constexpr std::uint32_t const tfMPTLock = 0x00000001; constexpr std::uint32_t const tfMPTLock = 0x00000001;
constexpr std::uint32_t const tfMPTUnlock = 0x00000002; constexpr std::uint32_t const tfMPTUnlock = 0x00000002;
constexpr std::uint32_t const tfMPTokenIssuanceSetMask = ~(tfUniversal | tfMPTLock | tfMPTUnlock); constexpr std::uint32_t const tfMPTokenIssuanceSetMask = ~(tfUniversal | tfMPTLock | tfMPTUnlock);
constexpr std::uint32_t const tfMPTokenIssuanceSetPermissionMask = ~(tfUniversal | tfMPTLock | tfMPTUnlock); constexpr std::uint32_t const tfMPTokenIssuanceSetGranularMask = tfMPTLock | tfMPTUnlock;
constexpr std::uint32_t const tfMPTokenIssuanceSetPermissionMask = (~tfMPTokenIssuanceSetMask) & (~tfMPTokenIssuanceSetGranularMask);
// MPTokenIssuanceDestroy flags: // MPTokenIssuanceDestroy flags:
constexpr std::uint32_t const tfMPTokenIssuanceDestroyMask = ~tfUniversal; constexpr std::uint32_t const tfMPTokenIssuanceDestroyMask = ~tfUniversal;
@@ -232,37 +233,6 @@ constexpr std::uint32_t tfAMMClawbackMask = ~(tfUniversal | tfClawTwoAssets);
// BridgeModify flags: // BridgeModify flags:
constexpr std::uint32_t tfClearAccountCreateAmount = 0x00010000; constexpr std::uint32_t tfClearAccountCreateAmount = 0x00010000;
constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount); constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount);
// VaultCreate flags:
constexpr std::uint32_t const tfVaultPrivate = 0x00010000;
static_assert(tfVaultPrivate == lsfVaultPrivate);
constexpr std::uint32_t const tfVaultShareNonTransferable = 0x00020000;
constexpr std::uint32_t const tfVaultCreateMask = ~(tfUniversal | tfVaultPrivate | tfVaultShareNonTransferable);
// Batch Flags:
constexpr std::uint32_t tfAllOrNothing = 0x00010000;
constexpr std::uint32_t tfOnlyOne = 0x00020000;
constexpr std::uint32_t tfUntilFailure = 0x00040000;
constexpr std::uint32_t tfIndependent = 0x00080000;
/**
* @note If nested Batch transactions are supported in the future, the tfInnerBatchTxn flag
* will need to be removed from this mask to allow Batch transaction to be inside
* the sfRawTransactions array.
*/
constexpr std::uint32_t const tfBatchMask =
~(tfUniversal | tfAllOrNothing | tfOnlyOne | tfUntilFailure | tfIndependent) | tfInnerBatchTxn;
// LoanSet flags:
// True, indicates the loan supports overpayments
constexpr std::uint32_t const tfLoanOverpayment = 0x00010000;
constexpr std::uint32_t const tfLoanSetMask = ~(tfUniversal | tfLoanOverpayment);
// LoanManage flags:
constexpr std::uint32_t const tfLoanDefault = 0x00010000;
constexpr std::uint32_t const tfLoanImpair = 0x00020000;
constexpr std::uint32_t const tfLoanUnimpair = 0x00040000;
constexpr std::uint32_t const tfLoanManageMask = ~(tfUniversal | tfLoanDefault | tfLoanImpair | tfLoanUnimpair);
// clang-format on // clang-format on
} // namespace ripple } // namespace ripple

View File

@@ -59,8 +59,7 @@ enum TxType : std::uint16_t
#pragma push_macro("TRANSACTION") #pragma push_macro("TRANSACTION")
#undef TRANSACTION #undef TRANSACTION
#define TRANSACTION(tag, value, ...) \ #define TRANSACTION(tag, value, name, delegatable, fields) tag = value,
tag = value,
#include <xrpl/protocol/detail/transactions.macro> #include <xrpl/protocol/detail/transactions.macro>

View File

@@ -46,10 +46,7 @@ private:
CtorHelper); CtorHelper);
public: public:
TxMeta( TxMeta(uint256 const& transactionID, std::uint32_t ledger);
uint256 const& transactionID,
std::uint32_t ledger,
std::optional<uint256> parentBatchId = std::nullopt);
TxMeta(uint256 const& txID, std::uint32_t ledger, Blob const&); TxMeta(uint256 const& txID, std::uint32_t ledger, Blob const&);
TxMeta(uint256 const& txID, std::uint32_t ledger, std::string const&); TxMeta(uint256 const& txID, std::uint32_t ledger, std::string const&);
TxMeta(uint256 const& txID, std::uint32_t ledger, STObject const&); TxMeta(uint256 const& txID, std::uint32_t ledger, STObject const&);
@@ -133,27 +130,6 @@ public:
return static_cast<bool>(mDelivered); return static_cast<bool>(mDelivered);
} }
void
setParentBatchId(uint256 const& parentBatchId)
{
mParentBatchId = parentBatchId;
}
uint256
getParentBatchId() const
{
XRPL_ASSERT(
hasParentBatchId(),
"ripple::TxMeta::getParentBatchId : non-null batch id");
return *mParentBatchId;
}
bool
hasParentBatchId() const
{
return static_cast<bool>(mParentBatchId);
}
private: private:
uint256 mTransactionID; uint256 mTransactionID;
std::uint32_t mLedger; std::uint32_t mLedger;
@@ -161,7 +137,6 @@ private:
int mResult; int mResult;
std::optional<STAmount> mDelivered; std::optional<STAmount> mDelivered;
std::optional<uint256> mParentBatchId;
STArray mNodes; STArray mNodes;
}; };

View File

@@ -63,9 +63,6 @@ using NodeID = base_uint<160, detail::NodeIDTag>;
* and a 160-bit account */ * and a 160-bit account */
using MPTID = base_uint<192>; using MPTID = base_uint<192>;
/** Domain is a 256-bit hash representing a specific domain. */
using Domain = base_uint<256>;
/** XRP currency. */ /** XRP currency. */
Currency const& Currency const&
xrpCurrency(); xrpCurrency();
@@ -122,25 +119,25 @@ namespace std {
template <> template <>
struct hash<ripple::Currency> : ripple::Currency::hasher struct hash<ripple::Currency> : ripple::Currency::hasher
{ {
hash() = default; explicit hash() = default;
}; };
template <> template <>
struct hash<ripple::NodeID> : ripple::NodeID::hasher struct hash<ripple::NodeID> : ripple::NodeID::hasher
{ {
hash() = default; explicit hash() = default;
}; };
template <> template <>
struct hash<ripple::Directory> : ripple::Directory::hasher struct hash<ripple::Directory> : ripple::Directory::hasher
{ {
hash() = default; explicit hash() = default;
}; };
template <> template <>
struct hash<ripple::uint256> : ripple::uint256::hasher struct hash<ripple::uint256> : ripple::uint256::hasher
{ {
hash() = default; explicit hash() = default;
}; };
} // namespace std } // namespace std

View File

@@ -35,6 +35,8 @@
#include <boost/container/vector.hpp> #include <boost/container/vector.hpp>
#include <cstddef> #include <cstddef>
#include <type_traits>
#include <unordered_map>
#include <vector> #include <vector>
namespace ripple { namespace ripple {

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