Compare commits

..

1 Commits

Author SHA1 Message Date
Ed Hennis
f1905a30cc Make a final "success" job for each CI test suite
- That job can be used in branch protection rules
2025-03-19 17:37:35 -04:00
612 changed files with 15774 additions and 46355 deletions

View File

@@ -94,4 +94,3 @@ SpacesInSquareBrackets: false
Standard: Cpp11 Standard: Cpp11
TabWidth: 8 TabWidth: 8
UseTab: Never UseTab: Never
QualifierAlignment: Right

View File

@@ -7,13 +7,13 @@ comment:
show_carryforward_flags: false show_carryforward_flags: false
coverage: coverage:
range: "70..85" range: "60..80"
precision: 1 precision: 1
round: nearest round: nearest
status: status:
project: project:
default: default:
target: 75% target: 60%
threshold: 2% threshold: 2%
patch: patch:
default: default:

8
.github/CODEOWNERS vendored
View File

@@ -1,8 +0,0 @@
# Allow anyone to review any change by default.
*
# Require the rpc-reviewers team to review changes to the rpc code.
include/xrpl/protocol/ @xrplf/rpc-reviewers
src/libxrpl/protocol/ @xrplf/rpc-reviewers
src/xrpld/rpc/ @xrplf/rpc-reviewers
src/xrpld/app/misc/ @xrplf/rpc-reviewers

View File

@@ -6,32 +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 9.7.3 external/rocksdb conan export external/snappy snappy/1.1.10@
conan export --version 4.0.3 external/soci 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_URL != '' && 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
@@ -47,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

@@ -1,30 +1,30 @@
name: clang-format name: clang-format
on: on: [push, pull_request]
push:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
jobs: jobs:
check: check:
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:
- 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 -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
pwd
whoami
ls -la .git
git branch
git diff --exit-code | tee "clang-format.patch" git diff --exit-code | tee "clang-format.patch"
- name: Upload patch - name: Upload patch
if: failure() && steps.assert.outcome == 'failure' if: failure() && steps.assert.outcome == 'failure'
@@ -54,6 +54,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,11 +10,11 @@ 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
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e container: rippleci/rippled-build-ubuntu:aaf5e3e
steps: steps:
- name: checkout - name: checkout
uses: actions/checkout@v4 uses: actions/checkout@v4

View File

@@ -1,13 +1,9 @@
name: levelization name: levelization
on: on: [push, pull_request]
push:
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
jobs: jobs:
check: check:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
CLANG_VERSION: 10 CLANG_VERSION: 10

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:
@@ -8,21 +8,19 @@ on:
paths: paths:
- 'src/libxrpl/protocol/BuildInfo.cpp' - 'src/libxrpl/protocol/BuildInfo.cpp'
- '.github/workflows/libxrpl.yml' - '.github/workflows/libxrpl.yml'
types: [opened, reopened, synchronize, ready_for_review]
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
publish: publish:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
name: Publish libXRPL name: Publish libXRPL
outputs: outputs:
outcome: ${{ steps.upload.outputs.outcome }} outcome: ${{ steps.upload.outputs.outcome }}
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
channel: ${{ steps.channel.outputs.channel }} channel: ${{ steps.channel.outputs.channel }}
runs-on: [self-hosted, heavy] runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e container: rippleci/rippled-build-ubuntu:aaf5e3e
steps: steps:
- name: Wait for essential checks to succeed - name: Wait for essential checks to succeed
uses: lewagon/wait-on-check-action@v1.3.4 uses: lewagon/wait-on-check-action@v1.3.4

View File

@@ -1,7 +1,6 @@
name: macos name: macos
on: on:
pull_request: pull_request:
types: [opened, reopened, synchronize, ready_for_review]
push: push:
# If the branches list is ever changed, be sure to change it on all # If the branches list is ever changed, be sure to change it on all
# build/test jobs (nix, macos, windows, instrumentation) # build/test jobs (nix, macos, windows, instrumentation)
@@ -15,25 +14,10 @@ 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()}}
core:default_build_profile=libxrpl
core:default_profile=libxrpl
tools.build:jobs={{ (os.cpu_count() * 4/5) | int }}
tools.build:verbosity=verbose
tools.compilation:verbosity=verbose
jobs: jobs:
test: test:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
strategy: strategy:
matrix: matrix:
platform: platform:
@@ -42,22 +26,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
@@ -84,32 +69,16 @@ jobs:
nproc --version nproc --version
echo -n "nproc returns: " echo -n "nproc returns: "
nproc nproc
system_profiler SPHardwareDataType
sysctl -n hw.logicalcpu
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 9.7.3 external/rocksdb
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
@@ -122,7 +91,11 @@ 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} success:
./rippled --unittest --unittest-jobs $n name: mac test success
ctest -j $n --output-on-failure needs: test
runs-on: ubuntu-latest
steps:
- run: true

View File

@@ -1,7 +1,6 @@
name: nix name: nix
on: on:
pull_request: pull_request:
types: [opened, reopened, synchronize, ready_for_review]
push: push:
# If the branches list is ever changed, be sure to change it on all # If the branches list is ever changed, be sure to change it on all
# build/test jobs (nix, macos, windows) # build/test jobs (nix, macos, windows)
@@ -16,21 +15,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() }}
core:default_build_profile=libxrpl
core:default_profile=libxrpl
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").
@@ -55,7 +39,6 @@ env:
jobs: jobs:
dependencies: dependencies:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -69,46 +52,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: 17 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: rippleci/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:
@@ -123,32 +119,26 @@ jobs:
configuration: configuration:
- Debug - Debug
- Release - Release
include:
- compiler: gcc
compiler_version: 12
distro: ubuntu
codename: jammy
- compiler: clang
compiler_version: 17
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: rippleci/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
@@ -156,9 +146,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
@@ -167,72 +159,16 @@ 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: success:
strategy: name: nix test success
fail-fast: false needs: test
matrix: runs-on: ubuntu-latest
platform:
- linux
compiler:
- gcc
configuration:
- Debug
cmake-args:
- "-DUNIT_TEST_REFERENCE_FEE=200"
- "-DUNIT_TEST_REFERENCE_FEE=1000"
needs: dependencies
runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
env:
build_dir: .build
steps: steps:
- name: download cache - run: true
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
- name: extract cache
run: |
mkdir -p ${CONAN_HOME}
tar -xzf conan.tar.gz -C ${CONAN_HOME}
- name: check environment
run: |
env | sort
echo ${PATH} | tr ':' '\n'
conan --version
cmake --version
- name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: dependencies
uses: ./.github/actions/dependencies
with:
configuration: ${{ matrix.configuration }}
- name: build
uses: ./.github/actions/build
with:
generator: Ninja
configuration: ${{ matrix.configuration }}
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
- name: test
run: |
cd ${build_dir}
./rippled --unittest --unittest-jobs $(nproc)
ctest -j $(nproc) --output-on-failure
coverage: coverage:
strategy: strategy:
@@ -246,18 +182,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: rippleci/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,<8"
- name: check environment - name: check environment
run: | run: |
echo ${PATH} | tr ':' '\n' echo ${PATH} | tr ':' '\n'
@@ -265,11 +206,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
@@ -291,7 +234,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
@@ -313,23 +256,22 @@ jobs:
conan: conan:
needs: dependencies needs: dependencies
runs-on: [self-hosted, heavy] runs-on: [self-hosted, heavy]
container: container: rippleci/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
@@ -337,22 +279,27 @@ 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 examples/example
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}
@@ -364,32 +311,62 @@ jobs:
# later # later
instrumentation-build: instrumentation-build:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }} env:
CLANG_RELEASE: 16
strategy:
fail-fast: false
runs-on: [self-hosted, heavy] runs-on: [self-hosted, heavy]
container: ghcr.io/xrplf/ci/debian-bookworm:clang-17 container: debian:bookworm
steps: steps:
- name: install prerequisites
env:
DEBIAN_FRONTEND: noninteractive
run: |
apt-get update
apt-get install --yes --no-install-recommends \
clang-${CLANG_RELEASE} clang++-${CLANG_RELEASE} \
python3-pip python-is-python3 make cmake git wget
apt-get clean
update-alternatives --install \
/usr/bin/clang clang /usr/bin/clang-${CLANG_RELEASE} 100 \
--slave /usr/bin/clang++ clang++ /usr/bin/clang++-${CLANG_RELEASE}
update-alternatives --auto clang
pip install --no-cache --break-system-packages "conan<2"
- name: checkout - name: checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 uses: actions/checkout@v4
- name: prepare environment - name: prepare environment
run: | run: |
mkdir ${GITHUB_WORKSPACE}/.build mkdir ${GITHUB_WORKSPACE}/.build
echo "SOURCE_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV echo "SOURCE_DIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV
echo "BUILD_DIR=$GITHUB_WORKSPACE/.build" >> $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 - name: configure Conan
run: | run: |
echo "${CONAN_GLOBAL_CONF}" >> $(conan config home)/global.conf conan profile new --detect default
conan config install conan/profiles/ -tf $(conan config home)/profiles/ conan profile update settings.compiler=clang default
conan profile show 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 - name: build dependencies
run: | run: |
cd ${BUILD_DIR} cd ${BUILD_DIR}
conan install ${SOURCE_DIR} \ conan install ${SOURCE_DIR} \
--output-folder ${BUILD_DIR} \ --output-folder ${BUILD_DIR} \
--install-folder ${BUILD_DIR} \
--build missing \ --build missing \
--settings:all build_type=Debug --settings build_type=Debug
- name: build with instrumentation - name: build with instrumentation
run: | run: |
@@ -414,4 +391,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

@@ -2,7 +2,6 @@ name: windows
on: on:
pull_request: pull_request:
types: [opened, reopened, synchronize, ready_for_review]
push: push:
# If the branches list is ever changed, be sure to change it on all # If the branches list is ever changed, be sure to change it on all
# build/test jobs (nix, macos, windows, instrumentation) # build/test jobs (nix, macos, windows, instrumentation)
@@ -18,25 +17,10 @@ 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()}}
core:default_build_profile=libxrpl
core:default_profile=libxrpl
tools.build:jobs=24
tools.build:verbosity=verbose
tools.compilation:verbosity=verbose
jobs: jobs:
test: test:
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -56,11 +40,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
@@ -68,12 +52,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:
@@ -84,27 +68,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 9.7.3 external/rocksdb
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
@@ -119,6 +93,12 @@ 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
success:
name: windows test success
needs: test
runs-on: ubuntu-latest
steps:
- run: true

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

@@ -83,17 +83,9 @@ The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conve
The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead. The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead.
## XRP Ledger server version 2.5.0
As of 2025-04-04, version 2.5.0 is in development. You can use a pre-release version by building from source or [using the `nightly` package](https://xrpl.org/docs/infrastructure/installation/install-rippled-on-ubuntu).
### Additions and bugfixes in 2.5.0
- `channel_authorize`: If `signing_support` is not enabled in the config, the RPC is disabled.
## XRP Ledger server version 2.4.0 ## XRP Ledger server version 2.4.0
[Version 2.4.0](https://github.com/XRPLF/rippled/releases/tag/2.4.0) was released on March 4, 2025. As of 2025-01-28, version 2.4.0 is in development. You can use a pre-release version by building from source or [using the `nightly` package](https://xrpl.org/docs/infrastructure/installation/install-rippled-on-ubuntu).
### Additions and bugfixes in 2.4.0 ### Additions and bugfixes in 2.4.0

View File

@@ -167,6 +167,8 @@ 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
``` ```
@@ -175,6 +177,8 @@ Export our [Conan recipe for RocksDB](./external/rocksdb).
It does not override paths to dependencies when building with Visual Studio. 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 2.x
conan export --version 9.7.3 external/rocksdb conan export --version 9.7.3 external/rocksdb
``` ```
@@ -183,10 +187,23 @@ 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.
@@ -271,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

@@ -43,7 +43,6 @@ test.consensus > xrpl.basics
test.consensus > xrpld.app test.consensus > xrpld.app
test.consensus > xrpld.consensus test.consensus > xrpld.consensus
test.consensus > xrpld.ledger test.consensus > xrpld.ledger
test.consensus > xrpl.json
test.core > test.jtx test.core > test.jtx
test.core > test.toplevel test.core > test.toplevel
test.core > test.unit_test test.core > test.unit_test
@@ -132,7 +131,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

@@ -16,18 +16,6 @@ set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
# GCC-specific fixes
add_compile_options(-Wno-unknown-pragmas -Wno-subobject-linkage)
# -Wno-subobject-linkage can be removed when we upgrade GCC version to at least 13.3
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Clang-specific fixes
add_compile_options(-Wno-unknown-warning-option) # Ignore unknown warning options
elseif(MSVC)
# MSVC-specific fixes
add_compile_options(/wd4068) # Ignore unknown pragmas
endif()
# make GIT_COMMIT_HASH define available to all sources # make GIT_COMMIT_HASH define available to all sources
find_package(Git) find_package(Git)
if(Git_FOUND) if(Git_FOUND)
@@ -90,11 +78,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 +132,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()

View File

@@ -1,5 +1,3 @@
[![codecov](https://codecov.io/gh/XRPLF/rippled/graph/badge.svg?token=WyFr5ajq3O)](https://codecov.io/gh/XRPLF/rippled)
# The XRP Ledger # The XRP Ledger
The [XRP Ledger](https://xrpl.org/) is a decentralized cryptographic ledger powered by a network of peer-to-peer nodes. The XRP Ledger uses a novel Byzantine Fault Tolerant consensus algorithm to settle and record transactions in a secure distributed database without a central operator. The [XRP Ledger](https://xrpl.org/) is a decentralized cryptographic ledger powered by a network of peer-to-peer nodes. The XRP Ledger uses a novel Byzantine Fault Tolerant consensus algorithm to settle and record transactions in a secure distributed database without a central operator.

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

@@ -26,7 +26,7 @@
# #
# Examples: # Examples:
# https://vl.ripple.com # https://vl.ripple.com
# https://unl.xrplf.org # https://vl.xrplf.org
# http://127.0.0.1:8000 # http://127.0.0.1:8000
# file:///etc/opt/ripple/vl.txt # file:///etc/opt/ripple/vl.txt
# #

View File

@@ -98,9 +98,6 @@
# 2024-04-03, Bronek Kozicki # 2024-04-03, Bronek Kozicki
# - add support for output formats: jacoco, clover, lcov # - add support for output formats: jacoco, clover, lcov
# #
# 2025-05-12, Jingchen Wu
# - add -fprofile-update=atomic to ensure atomic profile generation
#
# USAGE: # USAGE:
# #
# 1. Copy this file into your cmake modules path. # 1. Copy this file into your cmake modules path.
@@ -203,27 +200,15 @@ set(COVERAGE_COMPILER_FLAGS "-g --coverage"
CACHE INTERNAL "") CACHE INTERNAL "")
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
include(CheckCCompilerFlag)
check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path) check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path)
if(HAVE_cxx_fprofile_abs_path) if(HAVE_cxx_fprofile_abs_path)
set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
endif() endif()
include(CheckCCompilerFlag)
check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path) check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path)
if(HAVE_c_fprofile_abs_path) if(HAVE_c_fprofile_abs_path)
set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path") set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
endif() endif()
check_cxx_compiler_flag(-fprofile-update HAVE_cxx_fprofile_update)
if(HAVE_cxx_fprofile_update)
set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-update=atomic")
endif()
check_c_compiler_flag(-fprofile-update HAVE_c_fprofile_update)
if(HAVE_c_fprofile_update)
set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-update=atomic")
endif()
endif() endif()
set(CMAKE_Fortran_FLAGS_COVERAGE set(CMAKE_Fortran_FLAGS_COVERAGE

View File

@@ -136,9 +136,6 @@ if(xrpld)
add_executable(rippled) add_executable(rippled)
if(tests) if(tests)
target_compile_definitions(rippled PUBLIC ENABLE_TESTS) target_compile_definitions(rippled PUBLIC ENABLE_TESTS)
target_compile_definitions(rippled PRIVATE
UNIT_TEST_REFERENCE_FEE=${UNIT_TEST_REFERENCE_FEE}
)
endif() endif()
target_include_directories(rippled target_include_directories(rippled
PRIVATE PRIVATE

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

@@ -11,14 +11,8 @@ option(assert "Enables asserts, even in release builds" OFF)
option(xrpld "Build xrpld" ON) option(xrpld "Build xrpld" ON)
option(tests "Build tests" ON) option(tests "Build tests" ON)
if(tests)
# This setting allows making a separate workflow to test fees other than default 10
if(NOT UNIT_TEST_REFERENCE_FEE)
set(UNIT_TEST_REFERENCE_FEE "10" CACHE STRING "")
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,19 +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 }}
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 %}

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 = [
'grpc/1.72.0', 'date/3.0.3',
'libarchive/3.8.1', 'grpc/1.50.1',
'nudb/2.0.9', 'libarchive/3.7.6',
'openssl/1.1.1w', 'nudb/2.0.8',
'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/6.30.1', '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/6.30.1', 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/9.7.3') self.requires('rocksdb/9.7.3')
self.requires('xxhash/0.8.3', **transitive_headers_opt)
exports_sources = ( exports_sources = (
'CMakeLists.txt', 'CMakeLists.txt',
@@ -143,8 +136,6 @@ class Xrpl(ConanFile):
tc.variables['static'] = self.options.static tc.variables['static'] = self.options.static
tc.variables['unity'] = self.options.unity tc.variables['unity'] = self.options.unity
tc.variables['xrpld'] = self.options.xrpld tc.variables['xrpld'] = self.options.xrpld
if self.settings.compiler == 'clang' and self.settings.compiler.version == 16:
tc.extra_cxxflags = ["-DBOOST_ASIO_DISABLE_CONCEPTS"]
tc.generate() tc.generate()
def build(self): def build(self):
@@ -170,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

@@ -558,7 +558,7 @@ struct ConsensusResult
ConsensusTimer roundTime; ConsensusTimer roundTime;
// Indicates state in which consensus ended. Once in the accept phase // Indicates state in which consensus ended. Once in the accept phase
// will be either Yes or MovedOn or Expired // will be either Yes or MovedOn
ConsensusState state = ConsensusState::No; ConsensusState state = ConsensusState::No;
}; };

View File

@@ -9,7 +9,7 @@ project(
LANGUAGES CXX LANGUAGES CXX
) )
find_package(xrpl CONFIG REQUIRED) find_package(xrpl REQUIRED)
add_executable(example) add_executable(example)
target_sources(example PRIVATE src/example.cpp) target_sources(example PRIVATE src/example.cpp)

View File

@@ -0,0 +1,59 @@
from conan import ConanFile, conan_version
from conan.tools.cmake import CMake, cmake_layout
class Example(ConanFile):
def set_name(self):
if self.name is None:
self.name = 'example'
def set_version(self):
if self.version is None:
self.version = '0.1.0'
license = 'ISC'
author = 'John Freeman <jfreeman08@gmail.com>'
settings = 'os', 'compiler', 'build_type', 'arch'
options = {'shared': [True, False], 'fPIC': [True, False]}
default_options = {
'shared': False,
'fPIC': True,
'xrpl:xrpld': False,
}
requires = ['xrpl/2.2.0-rc1@jfreeman/nodestore']
generators = ['CMakeDeps', 'CMakeToolchain']
exports_sources = [
'CMakeLists.txt',
'cmake/*',
'external/*',
'include/*',
'src/*',
]
# For out-of-source build.
# https://docs.conan.io/en/latest/reference/build_helpers/cmake.html#configure
no_copy_source = True
def layout(self):
cmake_layout(self)
def config_options(self):
if self.settings.os == 'Windows':
del self.options.fPIC
def build(self):
cmake = CMake(self)
cmake.configure(variables={'BUILD_TESTING': 'NO'})
cmake.build()
def package(self):
cmake = CMake(self)
cmake.install()
def package_info(self):
path = f'{self.package_folder}/share/{self.name}/cpp_info.py'
with open(path, 'r') as file:
exec(file.read(), {}, {'self': self.cpp_info})

View File

@@ -2,9 +2,7 @@
#include <cstdio> #include <cstdio>
int int main(int argc, char const** argv) {
main(int argc, char const** argv)
{
std::printf("%s\n", ripple::BuildInfo::getVersionString().c_str()); std::printf("%s\n", ripple::BuildInfo::getVersionString().c_str());
return 0; return 0;
} }

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 {

View File

@@ -367,7 +367,7 @@ get(Section const& section,
} }
inline std::string inline std::string
get(Section const& section, std::string const& name, char const* defaultValue) get(Section const& section, std::string const& name, const char* defaultValue)
{ {
try try
{ {

View File

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

View File

@@ -55,7 +55,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
auto compressed = bf(outCapacity); auto compressed = bf(outCapacity);
auto compressedSize = LZ4_compress_default( auto compressedSize = LZ4_compress_default(
reinterpret_cast<char const*>(in), reinterpret_cast<const char*>(in),
reinterpret_cast<char*>(compressed), reinterpret_cast<char*>(compressed),
inSize, inSize,
outCapacity); outCapacity);
@@ -89,7 +89,7 @@ lz4Decompress(
Throw<std::runtime_error>("lz4Decompress: integer overflow (output)"); Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
if (LZ4_decompress_safe( if (LZ4_decompress_safe(
reinterpret_cast<char const*>(in), reinterpret_cast<const char*>(in),
reinterpret_cast<char*>(decompressed), reinterpret_cast<char*>(decompressed),
inSize, inSize,
decompressedSize) != decompressedSize) decompressedSize) != decompressedSize)

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 {
@@ -103,7 +93,7 @@ public:
{ {
} }
constexpr E const& constexpr const E&
value() const& value() const&
{ {
return val_; return val_;
@@ -121,7 +111,7 @@ public:
return std::move(val_); return std::move(val_);
} }
constexpr E const&& constexpr const E&&
value() const&& value() const&&
{ {
return std::move(val_); return std::move(val_);

View File

@@ -1,515 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2023 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BASICS_INTRUSIVEPOINTER_H_INCLUDED
#define RIPPLE_BASICS_INTRUSIVEPOINTER_H_INCLUDED
#include <concepts>
#include <cstdint>
#include <type_traits>
#include <utility>
namespace ripple {
//------------------------------------------------------------------------------
/** Tag to create an intrusive pointer from another intrusive pointer by using a
static cast. This is useful to create an intrusive pointer to a derived
class from an intrusive pointer to a base class.
*/
struct StaticCastTagSharedIntrusive
{
};
/** Tag to create an intrusive pointer from another intrusive pointer by using a
dynamic cast. This is useful to create an intrusive pointer to a derived
class from an intrusive pointer to a base class. If the cast fails an empty
(null) intrusive pointer is created.
*/
struct DynamicCastTagSharedIntrusive
{
};
/** When creating or adopting a raw pointer, controls whether the strong count
is incremented or not. Use this tag to increment the strong count.
*/
struct SharedIntrusiveAdoptIncrementStrongTag
{
};
/** When creating or adopting a raw pointer, controls whether the strong count
is incremented or not. Use this tag to leave the strong count unchanged.
*/
struct SharedIntrusiveAdoptNoIncrementTag
{
};
//------------------------------------------------------------------------------
//
template <class T>
concept CAdoptTag = std::is_same_v<T, SharedIntrusiveAdoptIncrementStrongTag> ||
std::is_same_v<T, SharedIntrusiveAdoptNoIncrementTag>;
//------------------------------------------------------------------------------
/** A shared intrusive pointer class that supports weak pointers.
This is meant to be used for SHAMapInnerNodes, but may be useful for other
cases. Since the reference counts are stored on the pointee, the pointee is
not destroyed until both the strong _and_ weak pointer counts go to zero.
When the strong pointer count goes to zero, the "partialDestructor" is
called. This can be used to destroy as much of the object as possible while
still retaining the reference counts. For example, for SHAMapInnerNodes the
children may be reset in that function. Note that std::shared_poiner WILL
run the destructor when the strong count reaches zero, but may not free the
memory used by the object until the weak count reaches zero. In rippled, we
typically allocate shared pointers with the `make_shared` function. When
that is used, the memory is not reclaimed until the weak count reaches zero.
*/
template <class T>
class SharedIntrusive
{
public:
SharedIntrusive() = default;
template <CAdoptTag TAdoptTag>
SharedIntrusive(T* p, TAdoptTag) noexcept;
SharedIntrusive(SharedIntrusive const& rhs);
template <class TT>
// TODO: convertible_to isn't quite right. That include a static castable.
// Find the right concept.
requires std::convertible_to<TT*, T*>
SharedIntrusive(SharedIntrusive<TT> const& rhs);
SharedIntrusive(SharedIntrusive&& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedIntrusive(SharedIntrusive<TT>&& rhs);
SharedIntrusive&
operator=(SharedIntrusive const& rhs);
bool
operator!=(std::nullptr_t) const;
bool
operator==(std::nullptr_t) const;
template <class TT>
requires std::convertible_to<TT*, T*>
SharedIntrusive&
operator=(SharedIntrusive<TT> const& rhs);
SharedIntrusive&
operator=(SharedIntrusive&& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedIntrusive&
operator=(SharedIntrusive<TT>&& rhs);
/** Adopt the raw pointer. The strong reference may or may not be
incremented, depending on the TAdoptTag
*/
template <CAdoptTag TAdoptTag = SharedIntrusiveAdoptIncrementStrongTag>
void
adopt(T* p);
~SharedIntrusive();
/** Create a new SharedIntrusive by statically casting the pointer
controlled by the rhs param.
*/
template <class TT>
SharedIntrusive(
StaticCastTagSharedIntrusive,
SharedIntrusive<TT> const& rhs);
/** Create a new SharedIntrusive by statically casting the pointer
controlled by the rhs param.
*/
template <class TT>
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs);
/** Create a new SharedIntrusive by dynamically casting the pointer
controlled by the rhs param.
*/
template <class TT>
SharedIntrusive(
DynamicCastTagSharedIntrusive,
SharedIntrusive<TT> const& rhs);
/** Create a new SharedIntrusive by dynamically casting the pointer
controlled by the rhs param.
*/
template <class TT>
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs);
T&
operator*() const noexcept;
T*
operator->() const noexcept;
explicit
operator bool() const noexcept;
/** Set the pointer to null, decrement the strong count, and run the
appropriate release action.
*/
void
reset();
/** Get the raw pointer */
T*
get() const;
/** Return the strong count */
std::size_t
use_count() const;
template <class TT, class... Args>
friend SharedIntrusive<TT>
make_SharedIntrusive(Args&&... args);
template <class TT>
friend class SharedIntrusive;
template <class TT>
friend class SharedWeakUnion;
template <class TT>
friend class WeakIntrusive;
private:
/** Return the raw pointer held by this object. */
T*
unsafeGetRawPtr() const;
/** Exchange the current raw pointer held by this object with the given
pointer. Decrement the strong count of the raw pointer previously held
by this object and run the appropriate release action.
*/
void
unsafeReleaseAndStore(T* next);
/** Set the raw pointer directly. This is wrapped in a function so the class
can support both atomic and non-atomic pointers in a future patch.
*/
void
unsafeSetRawPtr(T* p);
/** Exchange the raw pointer directly.
This sets the raw pointer to the given value and returns the previous
value. This is wrapped in a function so the class can support both
atomic and non-atomic pointers in a future patch.
*/
T*
unsafeExchange(T* p);
/** pointer to the type with an intrusive count */
T* ptr_{nullptr};
};
//------------------------------------------------------------------------------
/** A weak intrusive pointer class for the SharedIntrusive pointer class.
Note that this weak pointer class asks differently from normal weak pointer
classes. When the strong pointer count goes to zero, the "partialDestructor"
is called. See the comment on SharedIntrusive for a fuller explanation.
*/
template <class T>
class WeakIntrusive
{
public:
WeakIntrusive() = default;
WeakIntrusive(WeakIntrusive const& rhs);
WeakIntrusive(WeakIntrusive&& rhs);
WeakIntrusive(SharedIntrusive<T> const& rhs);
// There is no move constructor from a strong intrusive ptr because
// moving would be move expensive than copying in this case (the strong
// ref would need to be decremented)
WeakIntrusive(SharedIntrusive<T> const&& rhs) = delete;
// Since there are no current use cases for copy assignment in
// WeakIntrusive, we delete this operator to simplify the implementation. If
// a need arises in the future, we can reintroduce it with proper
// consideration."
WeakIntrusive&
operator=(WeakIntrusive const&) = delete;
template <class TT>
requires std::convertible_to<TT*, T*>
WeakIntrusive&
operator=(SharedIntrusive<TT> const& rhs);
/** Adopt the raw pointer and increment the weak count. */
void
adopt(T* ptr);
~WeakIntrusive();
/** Get a strong pointer from the weak pointer, if possible. This will
only return a seated pointer if the strong count on the raw pointer
is non-zero before locking.
*/
SharedIntrusive<T>
lock() const;
/** Return true if the strong count is zero. */
bool
expired() const;
/** Set the pointer to null and decrement the weak count.
Note: This may run the destructor if the strong count is zero.
*/
void
reset();
private:
T* ptr_ = nullptr;
/** Decrement the weak count. This does _not_ set the raw pointer to
null.
Note: This may run the destructor if the strong count is zero.
*/
void
unsafeReleaseNoStore();
};
//------------------------------------------------------------------------------
/** A combination of a strong and a weak intrusive pointer stored in the
space of a single pointer.
This class is similar to a `std::variant<SharedIntrusive,WeakIntrusive>`
with some optimizations. In particular, it uses a low-order bit to
determine if the raw pointer represents a strong pointer or a weak
pointer. It can also be quickly switched between its strong pointer and
weak pointer representations. This class is useful for storing intrusive
pointers in tagged caches.
*/
template <class T>
class SharedWeakUnion
{
// Tagged pointer. Low bit determines if this is a strong or a weak
// pointer. The low bit must be masked to zero when converting back to a
// pointer. If the low bit is '1', this is a weak pointer.
static_assert(
alignof(T) >= 2,
"Bad alignment: Combo pointer requires low bit to be zero");
public:
SharedWeakUnion() = default;
SharedWeakUnion(SharedWeakUnion const& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakUnion(SharedIntrusive<TT> const& rhs);
SharedWeakUnion(SharedWeakUnion&& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakUnion(SharedIntrusive<TT>&& rhs);
SharedWeakUnion&
operator=(SharedWeakUnion const& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakUnion&
operator=(SharedIntrusive<TT> const& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakUnion&
operator=(SharedIntrusive<TT>&& rhs);
~SharedWeakUnion();
/** Return a strong pointer if this is already a strong pointer (i.e.
don't lock the weak pointer. Use the `lock` method if that's what's
needed)
*/
SharedIntrusive<T>
getStrong() const;
/** Return true if this is a strong pointer and the strong pointer is
seated.
*/
explicit
operator bool() const noexcept;
/** Set the pointer to null, decrement the appropriate ref count, and
run the appropriate release action.
*/
void
reset();
/** If this is a strong pointer, return the raw pointer. Otherwise
return null.
*/
T*
get() const;
/** If this is a strong pointer, return the strong count. Otherwise
* return 0
*/
std::size_t
use_count() const;
/** Return true if there is a non-zero strong count. */
bool
expired() const;
/** If this is a strong pointer, return the strong pointer. Otherwise
attempt to lock the weak pointer.
*/
SharedIntrusive<T>
lock() const;
/** Return true is this represents a strong pointer. */
bool
isStrong() const;
/** Return true is this represents a weak pointer. */
bool
isWeak() const;
/** If this is a weak pointer, attempt to convert it to a strong
pointer.
@return true if successfully converted to a strong pointer (or was
already a strong pointer). Otherwise false.
*/
bool
convertToStrong();
/** If this is a strong pointer, attempt to convert it to a weak
pointer.
@return false if the pointer is null. Otherwise return true.
*/
bool
convertToWeak();
private:
// Tagged pointer. Low bit determines if this is a strong or a weak
// pointer. The low bit must be masked to zero when converting back to a
// pointer. If the low bit is '1', this is a weak pointer.
std::uintptr_t tp_{0};
static constexpr std::uintptr_t tagMask = 1;
static constexpr std::uintptr_t ptrMask = ~tagMask;
private:
/** Return the raw pointer held by this object.
*/
T*
unsafeGetRawPtr() const;
enum class RefStrength { strong, weak };
/** Set the raw pointer and tag bit directly.
*/
void
unsafeSetRawPtr(T* p, RefStrength rs);
/** Set the raw pointer and tag bit to all zeros (strong null pointer).
*/
void unsafeSetRawPtr(std::nullptr_t);
/** Decrement the appropriate ref count, and run the appropriate release
action. Note: this does _not_ set the raw pointer to null.
*/
void
unsafeReleaseNoStore();
};
//------------------------------------------------------------------------------
/** Create a shared intrusive pointer.
Note: unlike std::shared_ptr, where there is an advantage of allocating
the pointer and control block together, there is no benefit for intrusive
pointers.
*/
template <class TT, class... Args>
SharedIntrusive<TT>
make_SharedIntrusive(Args&&... args)
{
auto p = new TT(std::forward<Args>(args)...);
static_assert(
noexcept(SharedIntrusive<TT>(
std::declval<TT*>(),
std::declval<SharedIntrusiveAdoptNoIncrementTag>())),
"SharedIntrusive constructor should not throw or this can leak "
"memory");
return SharedIntrusive<TT>(p, SharedIntrusiveAdoptNoIncrementTag{});
}
//------------------------------------------------------------------------------
namespace intr_ptr {
template <class T>
using SharedPtr = SharedIntrusive<T>;
template <class T>
using WeakPtr = WeakIntrusive<T>;
template <class T>
using SharedWeakUnionPtr = SharedWeakUnion<T>;
template <class T, class... A>
SharedPtr<T>
make_shared(A&&... args)
{
return make_SharedIntrusive<T>(std::forward<A>(args)...);
}
template <class T, class TT>
SharedPtr<T>
static_pointer_cast(TT const& v)
{
return SharedPtr<T>(StaticCastTagSharedIntrusive{}, v);
}
template <class T, class TT>
SharedPtr<T>
dynamic_pointer_cast(TT const& v)
{
return SharedPtr<T>(DynamicCastTagSharedIntrusive{}, v);
}
} // namespace intr_ptr
} // namespace ripple
#endif

View File

@@ -1,740 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2023 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BASICS_INTRUSIVEPOINTER_IPP_INCLUDED
#define RIPPLE_BASICS_INTRUSIVEPOINTER_IPP_INCLUDED
#include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/basics/IntrusiveRefCounts.h>
#include <utility>
namespace ripple {
template <class T>
template <CAdoptTag TAdoptTag>
SharedIntrusive<T>::SharedIntrusive(T* p, TAdoptTag) noexcept : ptr_{p}
{
if constexpr (std::is_same_v<
TAdoptTag,
SharedIntrusiveAdoptIncrementStrongTag>)
{
if (p)
p->addStrongRef();
}
}
template <class T>
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive const& rhs)
: ptr_{[&] {
auto p = rhs.unsafeGetRawPtr();
if (p)
p->addStrongRef();
return p;
}()}
{
}
template <class T>
template <class TT>
requires std::convertible_to<TT*, T*>
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT> const& rhs)
: ptr_{[&] {
auto p = rhs.unsafeGetRawPtr();
if (p)
p->addStrongRef();
return p;
}()}
{
}
template <class T>
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive&& rhs)
: ptr_{rhs.unsafeExchange(nullptr)}
{
}
template <class T>
template <class TT>
requires std::convertible_to<TT*, T*>
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT>&& rhs)
: ptr_{rhs.unsafeExchange(nullptr)}
{
}
template <class T>
SharedIntrusive<T>&
SharedIntrusive<T>::operator=(SharedIntrusive const& rhs)
{
if (this == &rhs)
return *this;
auto p = rhs.unsafeGetRawPtr();
if (p)
p->addStrongRef();
unsafeReleaseAndStore(p);
return *this;
}
template <class T>
template <class TT>
// clang-format off
requires std::convertible_to<TT*, T*>
// clang-format on
SharedIntrusive<T>&
SharedIntrusive<T>::operator=(SharedIntrusive<TT> const& rhs)
{
if constexpr (std::is_same_v<T, TT>)
{
// This case should never be hit. The operator above will run instead.
// (The normal operator= is needed or it will be marked `deleted`)
if (this == &rhs)
return *this;
}
auto p = rhs.unsafeGetRawPtr();
if (p)
p->addStrongRef();
unsafeReleaseAndStore(p);
return *this;
}
template <class T>
SharedIntrusive<T>&
SharedIntrusive<T>::operator=(SharedIntrusive&& rhs)
{
if (this == &rhs)
return *this;
unsafeReleaseAndStore(rhs.unsafeExchange(nullptr));
return *this;
}
template <class T>
template <class TT>
// clang-format off
requires std::convertible_to<TT*, T*>
// clang-format on
SharedIntrusive<T>&
SharedIntrusive<T>::operator=(SharedIntrusive<TT>&& rhs)
{
static_assert(
!std::is_same_v<T, TT>,
"This overload should not be instantiated for T == TT");
unsafeReleaseAndStore(rhs.unsafeExchange(nullptr));
return *this;
}
template <class T>
bool
SharedIntrusive<T>::operator!=(std::nullptr_t) const
{
return this->get() != nullptr;
}
template <class T>
bool
SharedIntrusive<T>::operator==(std::nullptr_t) const
{
return this->get() == nullptr;
}
template <class T>
template <CAdoptTag TAdoptTag>
void
SharedIntrusive<T>::adopt(T* p)
{
if constexpr (std::is_same_v<
TAdoptTag,
SharedIntrusiveAdoptIncrementStrongTag>)
{
if (p)
p->addStrongRef();
}
unsafeReleaseAndStore(p);
}
template <class T>
SharedIntrusive<T>::~SharedIntrusive()
{
unsafeReleaseAndStore(nullptr);
};
template <class T>
template <class TT>
SharedIntrusive<T>::SharedIntrusive(
StaticCastTagSharedIntrusive,
SharedIntrusive<TT> const& rhs)
: ptr_{[&] {
auto p = static_cast<T*>(rhs.unsafeGetRawPtr());
if (p)
p->addStrongRef();
return p;
}()}
{
}
template <class T>
template <class TT>
SharedIntrusive<T>::SharedIntrusive(
StaticCastTagSharedIntrusive,
SharedIntrusive<TT>&& rhs)
: ptr_{static_cast<T*>(rhs.unsafeExchange(nullptr))}
{
}
template <class T>
template <class TT>
SharedIntrusive<T>::SharedIntrusive(
DynamicCastTagSharedIntrusive,
SharedIntrusive<TT> const& rhs)
: ptr_{[&] {
auto p = dynamic_cast<T*>(rhs.unsafeGetRawPtr());
if (p)
p->addStrongRef();
return p;
}()}
{
}
template <class T>
template <class TT>
SharedIntrusive<T>::SharedIntrusive(
DynamicCastTagSharedIntrusive,
SharedIntrusive<TT>&& rhs)
{
// This can be simplified without the `exchange`, but the `exchange` is kept
// in anticipation of supporting atomic operations.
auto toSet = rhs.unsafeExchange(nullptr);
if (toSet)
{
ptr_ = dynamic_cast<T*>(toSet);
if (!ptr_)
// need to set the pointer back or will leak
rhs.unsafeExchange(toSet);
}
}
template <class T>
T&
SharedIntrusive<T>::operator*() const noexcept
{
return *unsafeGetRawPtr();
}
template <class T>
T*
SharedIntrusive<T>::operator->() const noexcept
{
return unsafeGetRawPtr();
}
template <class T>
SharedIntrusive<T>::operator bool() const noexcept
{
return bool(unsafeGetRawPtr());
}
template <class T>
void
SharedIntrusive<T>::reset()
{
unsafeReleaseAndStore(nullptr);
}
template <class T>
T*
SharedIntrusive<T>::get() const
{
return unsafeGetRawPtr();
}
template <class T>
std::size_t
SharedIntrusive<T>::use_count() const
{
if (auto p = unsafeGetRawPtr())
return p->use_count();
return 0;
}
template <class T>
T*
SharedIntrusive<T>::unsafeGetRawPtr() const
{
return ptr_;
}
template <class T>
void
SharedIntrusive<T>::unsafeSetRawPtr(T* p)
{
ptr_ = p;
}
template <class T>
T*
SharedIntrusive<T>::unsafeExchange(T* p)
{
return std::exchange(ptr_, p);
}
template <class T>
void
SharedIntrusive<T>::unsafeReleaseAndStore(T* next)
{
auto prev = unsafeExchange(next);
if (!prev)
return;
using enum ReleaseStrongRefAction;
auto action = prev->releaseStrongRef();
switch (action)
{
case noop:
break;
case destroy:
delete prev;
break;
case partialDestroy:
prev->partialDestructor();
partialDestructorFinished(&prev);
// prev is null and may no longer be used
break;
}
}
//------------------------------------------------------------------------------
template <class T>
WeakIntrusive<T>::WeakIntrusive(WeakIntrusive const& rhs) : ptr_{rhs.ptr_}
{
if (ptr_)
ptr_->addWeakRef();
}
template <class T>
WeakIntrusive<T>::WeakIntrusive(WeakIntrusive&& rhs) : ptr_{rhs.ptr_}
{
rhs.ptr_ = nullptr;
}
template <class T>
WeakIntrusive<T>::WeakIntrusive(SharedIntrusive<T> const& rhs)
: ptr_{rhs.unsafeGetRawPtr()}
{
if (ptr_)
ptr_->addWeakRef();
}
template <class T>
template <class TT>
// clang-format off
requires std::convertible_to<TT*, T*>
// clang-format on
WeakIntrusive<T>&
WeakIntrusive<T>::operator=(SharedIntrusive<TT> const& rhs)
{
unsafeReleaseNoStore();
auto p = rhs.unsafeGetRawPtr();
if (p)
p->addWeakRef();
return *this;
}
template <class T>
void
WeakIntrusive<T>::adopt(T* ptr)
{
unsafeReleaseNoStore();
if (ptr)
ptr->addWeakRef();
ptr_ = ptr;
}
template <class T>
WeakIntrusive<T>::~WeakIntrusive()
{
unsafeReleaseNoStore();
}
template <class T>
SharedIntrusive<T>
WeakIntrusive<T>::lock() const
{
if (ptr_ && ptr_->checkoutStrongRefFromWeak())
{
return SharedIntrusive<T>{ptr_, SharedIntrusiveAdoptNoIncrementTag{}};
}
return {};
}
template <class T>
bool
WeakIntrusive<T>::expired() const
{
return (!ptr_ || ptr_->expired());
}
template <class T>
void
WeakIntrusive<T>::reset()
{
unsafeReleaseNoStore();
ptr_ = nullptr;
}
template <class T>
void
WeakIntrusive<T>::unsafeReleaseNoStore()
{
if (!ptr_)
return;
using enum ReleaseWeakRefAction;
auto action = ptr_->releaseWeakRef();
switch (action)
{
case noop:
break;
case destroy:
delete ptr_;
break;
}
}
//------------------------------------------------------------------------------
template <class T>
SharedWeakUnion<T>::SharedWeakUnion(SharedWeakUnion const& rhs) : tp_{rhs.tp_}
{
auto p = rhs.unsafeGetRawPtr();
if (!p)
return;
if (rhs.isStrong())
p->addStrongRef();
else
p->addWeakRef();
}
template <class T>
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakUnion<T>::SharedWeakUnion(SharedIntrusive<TT> const& rhs)
{
auto p = rhs.unsafeGetRawPtr();
if (p)
p->addStrongRef();
unsafeSetRawPtr(p, RefStrength::strong);
}
template <class T>
SharedWeakUnion<T>::SharedWeakUnion(SharedWeakUnion&& rhs) : tp_{rhs.tp_}
{
rhs.unsafeSetRawPtr(nullptr);
}
template <class T>
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakUnion<T>::SharedWeakUnion(SharedIntrusive<TT>&& rhs)
{
auto p = rhs.unsafeGetRawPtr();
if (p)
unsafeSetRawPtr(p, RefStrength::strong);
rhs.unsafeSetRawPtr(nullptr);
}
template <class T>
SharedWeakUnion<T>&
SharedWeakUnion<T>::operator=(SharedWeakUnion const& rhs)
{
if (this == &rhs)
return *this;
unsafeReleaseNoStore();
if (auto p = rhs.unsafeGetRawPtr())
{
if (rhs.isStrong())
{
p->addStrongRef();
unsafeSetRawPtr(p, RefStrength::strong);
}
else
{
p->addWeakRef();
unsafeSetRawPtr(p, RefStrength::weak);
}
}
else
{
unsafeSetRawPtr(nullptr);
}
return *this;
}
template <class T>
template <class TT>
// clang-format off
requires std::convertible_to<TT*, T*>
// clang-format on
SharedWeakUnion<T>&
SharedWeakUnion<T>::operator=(SharedIntrusive<TT> const& rhs)
{
unsafeReleaseNoStore();
auto p = rhs.unsafeGetRawPtr();
if (p)
p->addStrongRef();
unsafeSetRawPtr(p, RefStrength::strong);
return *this;
}
template <class T>
template <class TT>
// clang-format off
requires std::convertible_to<TT*, T*>
// clang-format on
SharedWeakUnion<T>&
SharedWeakUnion<T>::operator=(SharedIntrusive<TT>&& rhs)
{
unsafeReleaseNoStore();
unsafeSetRawPtr(rhs.unsafeGetRawPtr(), RefStrength::strong);
rhs.unsafeSetRawPtr(nullptr);
return *this;
}
template <class T>
SharedWeakUnion<T>::~SharedWeakUnion()
{
unsafeReleaseNoStore();
};
// Return a strong pointer if this is already a strong pointer (i.e. don't
// lock the weak pointer. Use the `lock` method if that's what's needed)
template <class T>
SharedIntrusive<T>
SharedWeakUnion<T>::getStrong() const
{
SharedIntrusive<T> result;
auto p = unsafeGetRawPtr();
if (p && isStrong())
{
result.template adopt<SharedIntrusiveAdoptIncrementStrongTag>(p);
}
return result;
}
template <class T>
SharedWeakUnion<T>::operator bool() const noexcept
{
return bool(get());
}
template <class T>
void
SharedWeakUnion<T>::reset()
{
unsafeReleaseNoStore();
unsafeSetRawPtr(nullptr);
}
template <class T>
T*
SharedWeakUnion<T>::get() const
{
return isStrong() ? unsafeGetRawPtr() : nullptr;
}
template <class T>
std::size_t
SharedWeakUnion<T>::use_count() const
{
if (auto p = get())
return p->use_count();
return 0;
}
template <class T>
bool
SharedWeakUnion<T>::expired() const
{
auto p = unsafeGetRawPtr();
return (!p || p->expired());
}
template <class T>
SharedIntrusive<T>
SharedWeakUnion<T>::lock() const
{
SharedIntrusive<T> result;
auto p = unsafeGetRawPtr();
if (!p)
return result;
if (isStrong())
{
result.template adopt<SharedIntrusiveAdoptIncrementStrongTag>(p);
return result;
}
if (p->checkoutStrongRefFromWeak())
{
result.template adopt<SharedIntrusiveAdoptNoIncrementTag>(p);
return result;
}
return result;
}
template <class T>
bool
SharedWeakUnion<T>::isStrong() const
{
return !(tp_ & tagMask);
}
template <class T>
bool
SharedWeakUnion<T>::isWeak() const
{
return tp_ & tagMask;
}
template <class T>
bool
SharedWeakUnion<T>::convertToStrong()
{
if (isStrong())
return true;
auto p = unsafeGetRawPtr();
if (p && p->checkoutStrongRefFromWeak())
{
[[maybe_unused]] auto action = p->releaseWeakRef();
XRPL_ASSERT(
(action == ReleaseWeakRefAction::noop),
"ripple::SharedWeakUnion::convertToStrong : "
"action is noop");
unsafeSetRawPtr(p, RefStrength::strong);
return true;
}
return false;
}
template <class T>
bool
SharedWeakUnion<T>::convertToWeak()
{
if (isWeak())
return true;
auto p = unsafeGetRawPtr();
if (!p)
return false;
using enum ReleaseStrongRefAction;
auto action = p->addWeakReleaseStrongRef();
switch (action)
{
case noop:
break;
case destroy:
// We just added a weak ref. How could we destroy?
UNREACHABLE(
"ripple::SharedWeakUnion::convertToWeak : destroying freshly "
"added ref");
delete p;
unsafeSetRawPtr(nullptr);
return true; // Should never happen
case partialDestroy:
// This is a weird case. We just converted the last strong
// pointer to a weak pointer.
p->partialDestructor();
partialDestructorFinished(&p);
// p is null and may no longer be used
break;
}
unsafeSetRawPtr(p, RefStrength::weak);
return true;
}
template <class T>
T*
SharedWeakUnion<T>::unsafeGetRawPtr() const
{
return reinterpret_cast<T*>(tp_ & ptrMask);
}
template <class T>
void
SharedWeakUnion<T>::unsafeSetRawPtr(T* p, RefStrength rs)
{
tp_ = reinterpret_cast<std::uintptr_t>(p);
if (tp_ && rs == RefStrength::weak)
tp_ |= tagMask;
}
template <class T>
void
SharedWeakUnion<T>::unsafeSetRawPtr(std::nullptr_t)
{
tp_ = 0;
}
template <class T>
void
SharedWeakUnion<T>::unsafeReleaseNoStore()
{
auto p = unsafeGetRawPtr();
if (!p)
return;
if (isStrong())
{
using enum ReleaseStrongRefAction;
auto strongAction = p->releaseStrongRef();
switch (strongAction)
{
case noop:
break;
case destroy:
delete p;
break;
case partialDestroy:
p->partialDestructor();
partialDestructorFinished(&p);
// p is null and may no longer be used
break;
}
}
else
{
using enum ReleaseWeakRefAction;
auto weakAction = p->releaseWeakRef();
switch (weakAction)
{
case noop:
break;
case destroy:
delete p;
break;
}
}
}
} // namespace ripple
#endif

View File

@@ -1,502 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2023 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BASICS_INTRUSIVEREFCOUNTS_H_INCLUDED
#define RIPPLE_BASICS_INTRUSIVEREFCOUNTS_H_INCLUDED
#include <xrpl/beast/utility/instrumentation.h>
#include <atomic>
#include <cstdint>
namespace ripple {
/** Action to perform when releasing a strong pointer.
noop: Do nothing. For example, a `noop` action will occur when a count is
decremented to a non-zero value.
partialDestroy: Run the `partialDestructor`. This action will happen when a
strong count is decremented to zero and the weak count is non-zero.
destroy: Run the destructor. This action will occur when either the strong
count or weak count is decremented and the other count is also zero.
*/
enum class ReleaseStrongRefAction { noop, partialDestroy, destroy };
/** Action to perform when releasing a weak pointer.
noop: Do nothing. For example, a `noop` action will occur when a count is
decremented to a non-zero value.
destroy: Run the destructor. This action will occur when either the strong
count or weak count is decremented and the other count is also zero.
*/
enum class ReleaseWeakRefAction { noop, destroy };
/** Implement the strong count, weak count, and bit flags for an intrusive
pointer.
A class can satisfy the requirements of a ripple::IntrusivePointer by
inheriting from this class.
*/
struct IntrusiveRefCounts
{
virtual ~IntrusiveRefCounts() noexcept;
// This must be `noexcept` or the make_SharedIntrusive function could leak
// memory.
void
addStrongRef() const noexcept;
void
addWeakRef() const noexcept;
ReleaseStrongRefAction
releaseStrongRef() const;
// Same as:
// {
// addWeakRef();
// return releaseStrongRef;
// }
// done as one atomic operation
ReleaseStrongRefAction
addWeakReleaseStrongRef() const;
ReleaseWeakRefAction
releaseWeakRef() const;
// Returns true is able to checkout a strong ref. False otherwise
bool
checkoutStrongRefFromWeak() const noexcept;
bool
expired() const noexcept;
std::size_t
use_count() const noexcept;
// This function MUST be called after a partial destructor finishes running.
// Calling this function may cause other threads to delete the object
// pointed to by `o`, so `o` should never be used after calling this
// function. The parameter will be set to a `nullptr` after calling this
// function to emphasize that it should not be used.
// Note: This is intentionally NOT called at the end of `partialDestructor`.
// The reason for this is if new classes are written to support this smart
// pointer class, they need to write their own `partialDestructor` function
// and ensure `partialDestructorFinished` is called at the end. Putting this
// call inside the smart pointer class itself is expected to be less error
// prone.
// Note: The "two-star" programming is intentional. It emphasizes that `o`
// may be deleted and the unergonomic API is meant to signal the special
// nature of this function call to callers.
// Note: This is a template to support incompletely defined classes.
template <class T>
friend void
partialDestructorFinished(T** o);
private:
// TODO: We may need to use a uint64_t for both counts. This will reduce the
// memory savings. We need to audit the code to make sure 16 bit counts are
// enough for strong pointers and 14 bit counts are enough for weak
// pointers. Use type aliases to make it easy to switch types.
using CountType = std::uint16_t;
static constexpr size_t StrongCountNumBits = sizeof(CountType) * 8;
static constexpr size_t WeakCountNumBits = StrongCountNumBits - 2;
using FieldType = std::uint32_t;
static constexpr size_t FieldTypeBits = sizeof(FieldType) * 8;
static constexpr FieldType one = 1;
/** `refCounts` consists of four fields that are treated atomically:
1. Strong count. This is a count of the number of shared pointers that
hold a reference to this object. When the strong counts goes to zero,
if the weak count is zero, the destructor is run. If the weak count is
non-zero when the strong count goes to zero then the partialDestructor
is run.
2. Weak count. This is a count of the number of weak pointer that hold
a reference to this object. When the weak count goes to zero and the
strong count is also zero, then the destructor is run.
3. Partial destroy started bit. This bit is set if the
`partialDestructor` function has been started (or is about to be
started). This is used to prevent the destructor from running
concurrently with the partial destructor. This can easily happen when
the last strong pointer release its reference in one thread and starts
the partialDestructor, while in another thread the last weak pointer
goes out of scope and starts the destructor while the partialDestructor
is still running. Both a start and finished bit is needed to handle a
corner-case where the last strong pointer goes out of scope, then then
last `weakPointer` goes out of scope, but this happens before the
`partialDestructor` bit is set. It would be possible to use a single
bit if it could also be set atomically when the strong count goes to
zero and the weak count is non-zero, but that would add complexity (and
likely slow down common cases as well).
4. Partial destroy finished bit. This bit is set when the
`partialDestructor` has finished running. See (3) above for more
information.
*/
mutable std::atomic<FieldType> refCounts{strongDelta};
/** Amount to change the strong count when adding or releasing a reference
Note: The strong count is stored in the low `StrongCountNumBits` bits
of refCounts
*/
static constexpr FieldType strongDelta = 1;
/** Amount to change the weak count when adding or releasing a reference
Note: The weak count is stored in the high `WeakCountNumBits` bits of
refCounts
*/
static constexpr FieldType weakDelta = (one << StrongCountNumBits);
/** Flag that is set when the partialDestroy function has started running
(or is about to start running).
See description of the `refCounts` field for a fuller description of
this field.
*/
static constexpr FieldType partialDestroyStartedMask =
(one << (FieldTypeBits - 1));
/** Flag that is set when the partialDestroy function has finished running
See description of the `refCounts` field for a fuller description of
this field.
*/
static constexpr FieldType partialDestroyFinishedMask =
(one << (FieldTypeBits - 2));
/** Mask that will zero out all the `count` bits and leave the tag bits
unchanged.
*/
static constexpr FieldType tagMask =
partialDestroyStartedMask | partialDestroyFinishedMask;
/** Mask that will zero out the `tag` bits and leave the count bits
unchanged.
*/
static constexpr FieldType valueMask = ~tagMask;
/** Mask that will zero out everything except the strong count.
*/
static constexpr FieldType strongMask =
((one << StrongCountNumBits) - 1) & valueMask;
/** Mask that will zero out everything except the weak count.
*/
static constexpr FieldType weakMask =
(((one << WeakCountNumBits) - 1) << StrongCountNumBits) & valueMask;
/** Unpack the count and tag fields from the packed atomic integer form. */
struct RefCountPair
{
CountType strong;
CountType weak;
/** The `partialDestroyStartedBit` is set to on when the partial
destroy function is started. It is not a boolean; it is a uint32
with all bits zero with the possible exception of the
`partialDestroyStartedMask` bit. This is done so it can be directly
masked into the `combinedValue`.
*/
FieldType partialDestroyStartedBit{0};
/** The `partialDestroyFinishedBit` is set to on when the partial
destroy function has finished.
*/
FieldType partialDestroyFinishedBit{0};
RefCountPair(FieldType v) noexcept;
RefCountPair(CountType s, CountType w) noexcept;
/** Convert back to the packed integer form. */
FieldType
combinedValue() const noexcept;
static constexpr CountType maxStrongValue =
static_cast<CountType>((one << StrongCountNumBits) - 1);
static constexpr CountType maxWeakValue =
static_cast<CountType>((one << WeakCountNumBits) - 1);
/** Put an extra margin to detect when running up against limits.
This is only used in debug code, and is useful if we reduce the
number of bits in the strong and weak counts (to 16 and 14 bits).
*/
static constexpr CountType checkStrongMaxValue = maxStrongValue - 32;
static constexpr CountType checkWeakMaxValue = maxWeakValue - 32;
};
};
inline void
IntrusiveRefCounts::addStrongRef() const noexcept
{
refCounts.fetch_add(strongDelta, std::memory_order_acq_rel);
}
inline void
IntrusiveRefCounts::addWeakRef() const noexcept
{
refCounts.fetch_add(weakDelta, std::memory_order_acq_rel);
}
inline ReleaseStrongRefAction
IntrusiveRefCounts::releaseStrongRef() const
{
// Subtract `strongDelta` from refCounts. If this releases the last strong
// ref, set the `partialDestroyStarted` bit. It is important that the ref
// count and the `partialDestroyStartedBit` are changed atomically (hence
// the loop and `compare_exchange` op). If this didn't need to be done
// atomically, the loop could be replaced with a `fetch_sub` and a
// conditional `fetch_or`. This loop will almost always run once.
using enum ReleaseStrongRefAction;
auto prevIntVal = refCounts.load(std::memory_order_acquire);
while (1)
{
RefCountPair const prevVal{prevIntVal};
XRPL_ASSERT(
(prevVal.strong >= strongDelta),
"ripple::IntrusiveRefCounts::releaseStrongRef : previous ref "
"higher than new");
auto nextIntVal = prevIntVal - strongDelta;
ReleaseStrongRefAction action = noop;
if (prevVal.strong == 1)
{
if (prevVal.weak == 0)
{
action = destroy;
}
else
{
nextIntVal |= partialDestroyStartedMask;
action = partialDestroy;
}
}
if (refCounts.compare_exchange_weak(
prevIntVal, nextIntVal, std::memory_order_acq_rel))
{
// Can't be in partial destroy because only decrementing the strong
// count to zero can start a partial destroy, and that can't happen
// twice.
XRPL_ASSERT(
(action == noop) || !(prevIntVal & partialDestroyStartedMask),
"ripple::IntrusiveRefCounts::releaseStrongRef : not in partial "
"destroy");
return action;
}
}
}
inline ReleaseStrongRefAction
IntrusiveRefCounts::addWeakReleaseStrongRef() const
{
using enum ReleaseStrongRefAction;
static_assert(weakDelta > strongDelta);
auto constexpr delta = weakDelta - strongDelta;
auto prevIntVal = refCounts.load(std::memory_order_acquire);
// This loop will almost always run once. The loop is needed to atomically
// change the counts and flags (the count could be atomically changed, but
// the flags depend on the current value of the counts).
//
// Note: If this becomes a perf bottleneck, the `partialDestoryStartedMask`
// may be able to be set non-atomically. But it is easier to reason about
// the code if the flag is set atomically.
while (1)
{
RefCountPair const prevVal{prevIntVal};
// Converted the last strong pointer to a weak pointer.
//
// Can't be in partial destroy because only decrementing the
// strong count to zero can start a partial destroy, and that
// can't happen twice.
XRPL_ASSERT(
(!prevVal.partialDestroyStartedBit),
"ripple::IntrusiveRefCounts::addWeakReleaseStrongRef : not in "
"partial destroy");
auto nextIntVal = prevIntVal + delta;
ReleaseStrongRefAction action = noop;
if (prevVal.strong == 1)
{
if (prevVal.weak == 0)
{
action = noop;
}
else
{
nextIntVal |= partialDestroyStartedMask;
action = partialDestroy;
}
}
if (refCounts.compare_exchange_weak(
prevIntVal, nextIntVal, std::memory_order_acq_rel))
{
XRPL_ASSERT(
(!(prevIntVal & partialDestroyStartedMask)),
"ripple::IntrusiveRefCounts::addWeakReleaseStrongRef : not "
"started partial destroy");
return action;
}
}
}
inline ReleaseWeakRefAction
IntrusiveRefCounts::releaseWeakRef() const
{
auto prevIntVal = refCounts.fetch_sub(weakDelta, std::memory_order_acq_rel);
RefCountPair prev = prevIntVal;
if (prev.weak == 1 && prev.strong == 0)
{
if (!prev.partialDestroyStartedBit)
{
// This case should only be hit if the partialDestroyStartedBit is
// set non-atomically (and even then very rarely). The code is kept
// in case we need to set the flag non-atomically for perf reasons.
refCounts.wait(prevIntVal, std::memory_order_acquire);
prevIntVal = refCounts.load(std::memory_order_acquire);
prev = RefCountPair{prevIntVal};
}
if (!prev.partialDestroyFinishedBit)
{
// partial destroy MUST finish before running a full destroy (when
// using weak pointers)
refCounts.wait(prevIntVal - weakDelta, std::memory_order_acquire);
}
return ReleaseWeakRefAction::destroy;
}
return ReleaseWeakRefAction::noop;
}
inline bool
IntrusiveRefCounts::checkoutStrongRefFromWeak() const noexcept
{
auto curValue = RefCountPair{1, 1}.combinedValue();
auto desiredValue = RefCountPair{2, 1}.combinedValue();
while (!refCounts.compare_exchange_weak(
curValue, desiredValue, std::memory_order_acq_rel))
{
RefCountPair const prev{curValue};
if (!prev.strong)
return false;
desiredValue = curValue + strongDelta;
}
return true;
}
inline bool
IntrusiveRefCounts::expired() const noexcept
{
RefCountPair const val = refCounts.load(std::memory_order_acquire);
return val.strong == 0;
}
inline std::size_t
IntrusiveRefCounts::use_count() const noexcept
{
RefCountPair const val = refCounts.load(std::memory_order_acquire);
return val.strong;
}
inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
{
#ifndef NDEBUG
auto v = refCounts.load(std::memory_order_acquire);
XRPL_ASSERT(
(!(v & valueMask)),
"ripple::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
auto t = v & tagMask;
XRPL_ASSERT(
(!t || t == tagMask),
"ripple::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
#endif
}
//------------------------------------------------------------------------------
inline IntrusiveRefCounts::RefCountPair::RefCountPair(
IntrusiveRefCounts::FieldType v) noexcept
: strong{static_cast<CountType>(v & strongMask)}
, weak{static_cast<CountType>((v & weakMask) >> StrongCountNumBits)}
, partialDestroyStartedBit{v & partialDestroyStartedMask}
, partialDestroyFinishedBit{v & partialDestroyFinishedMask}
{
XRPL_ASSERT(
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
"ripple::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside "
"range");
}
inline IntrusiveRefCounts::RefCountPair::RefCountPair(
IntrusiveRefCounts::CountType s,
IntrusiveRefCounts::CountType w) noexcept
: strong{s}, weak{w}
{
XRPL_ASSERT(
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
"ripple::IntrusiveRefCounts::RefCountPair(CountType, CountType) : "
"inputs inside range");
}
inline IntrusiveRefCounts::FieldType
IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept
{
XRPL_ASSERT(
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
"ripple::IntrusiveRefCounts::RefCountPair::combinedValue : inputs "
"inside range");
return (static_cast<IntrusiveRefCounts::FieldType>(weak)
<< IntrusiveRefCounts::StrongCountNumBits) |
static_cast<IntrusiveRefCounts::FieldType>(strong) |
partialDestroyStartedBit | partialDestroyFinishedBit;
}
template <class T>
inline void
partialDestructorFinished(T** o)
{
T& self = **o;
IntrusiveRefCounts::RefCountPair p =
self.refCounts.fetch_or(IntrusiveRefCounts::partialDestroyFinishedMask);
XRPL_ASSERT(
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit &&
!p.strong),
"ripple::partialDestructorFinished : not a weak ref");
if (!p.weak)
{
// There was a weak count before the partial destructor ran (or we would
// have run the full destructor) and now there isn't a weak count. Some
// thread is waiting to run the destructor.
self.refCounts.notify_one();
}
// Set the pointer to null to emphasize that the object shouldn't be used
// after calling this function as it may be destroyed in another thread.
*o = nullptr;
}
//------------------------------------------------------------------------------
} // namespace ripple
#endif

View File

@@ -1,135 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2023 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_H_INCLUDED
#define RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_H_INCLUDED
#include <memory>
#include <variant>
namespace ripple {
/** A combination of a std::shared_ptr and a std::weak_pointer.
This class is a wrapper to a `std::variant<std::shared_ptr,std::weak_ptr>`
This class is useful for storing intrusive pointers in tagged caches using less
memory than storing both pointers directly.
*/
template <class T>
class SharedWeakCachePointer
{
public:
SharedWeakCachePointer() = default;
SharedWeakCachePointer(SharedWeakCachePointer const& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakCachePointer(std::shared_ptr<TT> const& rhs);
SharedWeakCachePointer(SharedWeakCachePointer&& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakCachePointer(std::shared_ptr<TT>&& rhs);
SharedWeakCachePointer&
operator=(SharedWeakCachePointer const& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakCachePointer&
operator=(std::shared_ptr<TT> const& rhs);
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakCachePointer&
operator=(std::shared_ptr<TT>&& rhs);
~SharedWeakCachePointer();
/** Return a strong pointer if this is already a strong pointer (i.e. don't
lock the weak pointer. Use the `lock` method if that's what's needed)
*/
std::shared_ptr<T> const&
getStrong() const;
/** Return true if this is a strong pointer and the strong pointer is
seated.
*/
explicit
operator bool() const noexcept;
/** Set the pointer to null, decrement the appropriate ref count, and run
the appropriate release action.
*/
void
reset();
/** If this is a strong pointer, return the raw pointer. Otherwise return
null.
*/
T*
get() const;
/** If this is a strong pointer, return the strong count. Otherwise return 0
*/
std::size_t
use_count() const;
/** Return true if there is a non-zero strong count. */
bool
expired() const;
/** If this is a strong pointer, return the strong pointer. Otherwise
attempt to lock the weak pointer.
*/
std::shared_ptr<T>
lock() const;
/** Return true is this represents a strong pointer. */
bool
isStrong() const;
/** Return true is this represents a weak pointer. */
bool
isWeak() const;
/** If this is a weak pointer, attempt to convert it to a strong pointer.
@return true if successfully converted to a strong pointer (or was
already a strong pointer). Otherwise false.
*/
bool
convertToStrong();
/** If this is a strong pointer, attempt to convert it to a weak pointer.
@return false if the pointer is null. Otherwise return true.
*/
bool
convertToWeak();
private:
std::variant<std::shared_ptr<T>, std::weak_ptr<T>> combo_;
};
} // namespace ripple
#endif

View File

@@ -1,192 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2023 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_IPP_INCLUDED
#define RIPPLE_BASICS_SHAREDWEAKCACHEPOINTER_IPP_INCLUDED
#include <xrpl/basics/SharedWeakCachePointer.h>
namespace ripple {
template <class T>
SharedWeakCachePointer<T>::SharedWeakCachePointer(
SharedWeakCachePointer const& rhs) = default;
template <class T>
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakCachePointer<T>::SharedWeakCachePointer(
std::shared_ptr<TT> const& rhs)
: combo_{rhs}
{
}
template <class T>
SharedWeakCachePointer<T>::SharedWeakCachePointer(
SharedWeakCachePointer&& rhs) = default;
template <class T>
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakCachePointer<T>::SharedWeakCachePointer(std::shared_ptr<TT>&& rhs)
: combo_{std::move(rhs)}
{
}
template <class T>
SharedWeakCachePointer<T>&
SharedWeakCachePointer<T>::operator=(SharedWeakCachePointer const& rhs) =
default;
template <class T>
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakCachePointer<T>&
SharedWeakCachePointer<T>::operator=(std::shared_ptr<TT> const& rhs)
{
combo_ = rhs;
return *this;
}
template <class T>
template <class TT>
requires std::convertible_to<TT*, T*>
SharedWeakCachePointer<T>&
SharedWeakCachePointer<T>::operator=(std::shared_ptr<TT>&& rhs)
{
combo_ = std::move(rhs);
return *this;
}
template <class T>
SharedWeakCachePointer<T>::~SharedWeakCachePointer() = default;
// Return a strong pointer if this is already a strong pointer (i.e. don't
// lock the weak pointer. Use the `lock` method if that's what's needed)
template <class T>
std::shared_ptr<T> const&
SharedWeakCachePointer<T>::getStrong() const
{
static std::shared_ptr<T> const empty;
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
return *p;
return empty;
}
template <class T>
SharedWeakCachePointer<T>::operator bool() const noexcept
{
return !!std::get_if<std::shared_ptr<T>>(&combo_);
}
template <class T>
void
SharedWeakCachePointer<T>::reset()
{
combo_ = std::shared_ptr<T>{};
}
template <class T>
T*
SharedWeakCachePointer<T>::get() const
{
return std::get_if<std::shared_ptr<T>>(&combo_).get();
}
template <class T>
std::size_t
SharedWeakCachePointer<T>::use_count() const
{
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
return p->use_count();
return 0;
}
template <class T>
bool
SharedWeakCachePointer<T>::expired() const
{
if (auto p = std::get_if<std::weak_ptr<T>>(&combo_))
return p->expired();
return !std::get_if<std::shared_ptr<T>>(&combo_);
}
template <class T>
std::shared_ptr<T>
SharedWeakCachePointer<T>::lock() const
{
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
return *p;
if (auto p = std::get_if<std::weak_ptr<T>>(&combo_))
return p->lock();
return {};
}
template <class T>
bool
SharedWeakCachePointer<T>::isStrong() const
{
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
return !!p->get();
return false;
}
template <class T>
bool
SharedWeakCachePointer<T>::isWeak() const
{
return !isStrong();
}
template <class T>
bool
SharedWeakCachePointer<T>::convertToStrong()
{
if (isStrong())
return true;
if (auto p = std::get_if<std::weak_ptr<T>>(&combo_))
{
if (auto s = p->lock())
{
combo_ = std::move(s);
return true;
}
}
return false;
}
template <class T>
bool
SharedWeakCachePointer<T>::convertToWeak()
{
if (isWeak())
return true;
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
{
combo_ = std::weak_ptr<T>(*p);
return true;
}
return false;
}
} // namespace ripple
#endif

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,9 +20,7 @@
#ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED #ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED #define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
#include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/basics/Log.h> #include <xrpl/basics/Log.h>
#include <xrpl/basics/SharedWeakCachePointer.ipp>
#include <xrpl/basics/UnorderedContainers.h> #include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/hardened_hash.h> #include <xrpl/basics/hardened_hash.h>
#include <xrpl/beast/clock/abstract_clock.h> #include <xrpl/beast/clock/abstract_clock.h>
@@ -53,8 +51,6 @@ template <
class Key, class Key,
class T, class T,
bool IsKeyCache = false, bool IsKeyCache = false,
class SharedWeakUnionPointerType = SharedWeakCachePointer<T>,
class SharedPointerType = std::shared_ptr<T>,
class Hash = hardened_hash<>, class Hash = hardened_hash<>,
class KeyEqual = std::equal_to<Key>, class KeyEqual = std::equal_to<Key>,
class Mutex = std::recursive_mutex> class Mutex = std::recursive_mutex>
@@ -65,8 +61,6 @@ public:
using key_type = Key; using key_type = Key;
using mapped_type = T; using mapped_type = T;
using clock_type = beast::abstract_clock<std::chrono::steady_clock>; using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
using shared_weak_combo_pointer_type = SharedWeakUnionPointerType;
using shared_pointer_type = SharedPointerType;
public: public:
TaggedCache( TaggedCache(
@@ -76,48 +70,231 @@ public:
clock_type& clock, clock_type& clock,
beast::Journal journal, beast::Journal journal,
beast::insight::Collector::ptr const& collector = beast::insight::Collector::ptr const& collector =
beast::insight::NullCollector::New()); beast::insight::NullCollector::New())
: m_journal(journal)
, m_clock(clock)
, m_stats(
name,
std::bind(&TaggedCache::collect_metrics, this),
collector)
, m_name(name)
, m_target_size(size)
, m_target_age(expiration)
, m_cache_count(0)
, m_hits(0)
, m_misses(0)
{
}
public: public:
/** Return the clock associated with the cache. */ /** Return the clock associated with the cache. */
clock_type& clock_type&
clock(); clock()
{
return m_clock;
}
/** Returns the number of items in the container. */ /** Returns the number of items in the container. */
std::size_t std::size_t
size() const; size() const
{
std::lock_guard lock(m_mutex);
return m_cache.size();
}
void
setTargetSize(int s)
{
std::lock_guard lock(m_mutex);
m_target_size = s;
if (s > 0)
{
for (auto& partition : m_cache.map())
{
partition.rehash(static_cast<std::size_t>(
(s + (s >> 2)) /
(partition.max_load_factor() * m_cache.partitions()) +
1));
}
}
JLOG(m_journal.debug()) << m_name << " target size set to " << s;
}
clock_type::duration
getTargetAge() const
{
std::lock_guard lock(m_mutex);
return m_target_age;
}
void
setTargetAge(clock_type::duration s)
{
std::lock_guard lock(m_mutex);
m_target_age = s;
JLOG(m_journal.debug())
<< m_name << " target age set to " << m_target_age.count();
}
int int
getCacheSize() const; getCacheSize() const
{
std::lock_guard lock(m_mutex);
return m_cache_count;
}
int int
getTrackSize() const; getTrackSize() const
{
std::lock_guard lock(m_mutex);
return m_cache.size();
}
float float
getHitRate(); getHitRate()
{
std::lock_guard lock(m_mutex);
auto const total = static_cast<float>(m_hits + m_misses);
return m_hits * (100.0f / std::max(1.0f, total));
}
void void
clear(); clear()
{
std::lock_guard lock(m_mutex);
m_cache.clear();
m_cache_count = 0;
}
void void
reset(); reset()
{
std::lock_guard lock(m_mutex);
m_cache.clear();
m_cache_count = 0;
m_hits = 0;
m_misses = 0;
}
/** Refresh the last access time on a key if present. /** Refresh the last access time on a key if present.
@return `true` If the key was found. @return `true` If the key was found.
*/ */
template <class KeyComparable> template <class KeyComparable>
bool bool
touch_if_exists(KeyComparable const& key); touch_if_exists(KeyComparable const& key)
{
std::lock_guard lock(m_mutex);
auto const iter(m_cache.find(key));
if (iter == m_cache.end())
{
++m_stats.misses;
return false;
}
iter->second.touch(m_clock.now());
++m_stats.hits;
return true;
}
using SweptPointersVector = std::vector<SharedWeakUnionPointerType>; using SweptPointersVector = std::pair<
std::vector<std::shared_ptr<mapped_type>>,
std::vector<std::weak_ptr<mapped_type>>>;
void void
sweep(); sweep()
{
// Keep references to all the stuff we sweep
// For performance, each worker thread should exit before the swept data
// is destroyed but still within the main cache lock.
std::vector<SweptPointersVector> allStuffToSweep(m_cache.partitions());
clock_type::time_point const now(m_clock.now());
clock_type::time_point when_expire;
auto const start = std::chrono::steady_clock::now();
{
std::lock_guard lock(m_mutex);
if (m_target_size == 0 ||
(static_cast<int>(m_cache.size()) <= m_target_size))
{
when_expire = now - m_target_age;
}
else
{
when_expire =
now - m_target_age * m_target_size / m_cache.size();
clock_type::duration const minimumAge(std::chrono::seconds(1));
if (when_expire > (now - minimumAge))
when_expire = now - minimumAge;
JLOG(m_journal.trace())
<< m_name << " is growing fast " << m_cache.size() << " of "
<< m_target_size << " aging at "
<< (now - when_expire).count() << " of "
<< m_target_age.count();
}
std::vector<std::thread> workers;
workers.reserve(m_cache.partitions());
std::atomic<int> allRemovals = 0;
for (std::size_t p = 0; p < m_cache.partitions(); ++p)
{
workers.push_back(sweepHelper(
when_expire,
now,
m_cache.map()[p],
allStuffToSweep[p],
allRemovals,
lock));
}
for (std::thread& worker : workers)
worker.join();
m_cache_count -= allRemovals;
}
// At this point allStuffToSweep will go out of scope outside the lock
// and decrement the reference count on each strong pointer.
JLOG(m_journal.debug())
<< m_name << " TaggedCache sweep lock duration "
<< std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - start)
.count()
<< "ms";
}
bool bool
del(key_type const& key, bool valid); del(const key_type& key, bool valid)
{
// Remove from cache, if !valid, remove from map too. Returns true if
// removed from cache
std::lock_guard lock(m_mutex);
auto cit = m_cache.find(key);
if (cit == m_cache.end())
return false;
Entry& entry = cit->second;
bool ret = false;
if (entry.isCached())
{
--m_cache_count;
entry.ptr.reset();
ret = true;
}
if (!valid || entry.isExpired())
m_cache.erase(cit);
return ret;
}
public:
/** Replace aliased objects with originals. /** Replace aliased objects with originals.
Due to concurrency it is possible for two separate objects with Due to concurrency it is possible for two separate objects with
@@ -131,23 +308,100 @@ public:
@return `true` If the key already existed. @return `true` If the key already existed.
*/ */
template <class R> public:
bool bool
canonicalize( canonicalize(
key_type const& key, const key_type& key,
SharedPointerType& data, std::shared_ptr<T>& data,
R&& replaceCallback); std::function<bool(std::shared_ptr<T> const&)>&& replace)
{
// Return canonical value, store if needed, refresh in cache
// Return values: true=we had the data already
std::lock_guard lock(m_mutex);
auto cit = m_cache.find(key);
if (cit == m_cache.end())
{
m_cache.emplace(
std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(m_clock.now(), data));
++m_cache_count;
return false;
}
Entry& entry = cit->second;
entry.touch(m_clock.now());
if (entry.isCached())
{
if (replace(entry.ptr))
{
entry.ptr = data;
entry.weak_ptr = data;
}
else
{
data = entry.ptr;
}
return true;
}
auto cachedData = entry.lock();
if (cachedData)
{
if (replace(entry.ptr))
{
entry.ptr = data;
entry.weak_ptr = data;
}
else
{
entry.ptr = cachedData;
data = cachedData;
}
++m_cache_count;
return true;
}
entry.ptr = data;
entry.weak_ptr = data;
++m_cache_count;
return false;
}
bool bool
canonicalize_replace_cache( canonicalize_replace_cache(
key_type const& key, const key_type& key,
SharedPointerType const& data); std::shared_ptr<T> const& data)
{
return canonicalize(
key,
const_cast<std::shared_ptr<T>&>(data),
[](std::shared_ptr<T> const&) { return true; });
}
bool bool
canonicalize_replace_client(key_type const& key, SharedPointerType& data); canonicalize_replace_client(const key_type& key, std::shared_ptr<T>& data)
{
return canonicalize(
key, data, [](std::shared_ptr<T> const&) { return false; });
}
SharedPointerType std::shared_ptr<T>
fetch(key_type const& key); fetch(const key_type& key)
{
std::lock_guard<mutex_type> l(m_mutex);
auto ret = initialFetch(key, l);
if (!ret)
++m_misses;
return ret;
}
/** Insert the element into the container. /** Insert the element into the container.
If the key already exists, nothing happens. If the key already exists, nothing happens.
@@ -156,11 +410,26 @@ public:
template <class ReturnType = bool> template <class ReturnType = bool>
auto auto
insert(key_type const& key, T const& value) insert(key_type const& key, T const& value)
-> std::enable_if_t<!IsKeyCache, ReturnType>; -> std::enable_if_t<!IsKeyCache, ReturnType>
{
auto p = std::make_shared<T>(std::cref(value));
return canonicalize_replace_client(key, p);
}
template <class ReturnType = bool> template <class ReturnType = bool>
auto auto
insert(key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>; insert(key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>
{
std::lock_guard lock(m_mutex);
clock_type::time_point const now(m_clock.now());
auto [it, inserted] = m_cache.emplace(
std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(now));
if (!inserted)
it->second.last_access = now;
return inserted;
}
// VFALCO NOTE It looks like this returns a copy of the data in // VFALCO NOTE It looks like this returns a copy of the data in
// the output parameter 'data'. This could be expensive. // the output parameter 'data'. This could be expensive.
@@ -168,18 +437,50 @@ public:
// simply return an iterator. // simply return an iterator.
// //
bool bool
retrieve(key_type const& key, T& data); retrieve(const key_type& key, T& data)
{
// retrieve the value of the stored data
auto entry = fetch(key);
if (!entry)
return false;
data = *entry;
return true;
}
mutex_type& mutex_type&
peekMutex(); peekMutex()
{
return m_mutex;
}
std::vector<key_type> std::vector<key_type>
getKeys() const; getKeys() const
{
std::vector<key_type> v;
{
std::lock_guard lock(m_mutex);
v.reserve(m_cache.size());
for (auto const& _ : m_cache)
v.push_back(_.first);
}
return v;
}
// CachedSLEs functions. // CachedSLEs functions.
/** Returns the fraction of cache hits. */ /** Returns the fraction of cache hits. */
double double
rate() const; rate() const
{
std::lock_guard lock(m_mutex);
auto const tot = m_hits + m_misses;
if (tot == 0)
return 0;
return double(m_hits) / tot;
}
/** Fetch an item from the cache. /** Fetch an item from the cache.
If the digest was not found, Handler If the digest was not found, Handler
@@ -187,16 +488,73 @@ public:
std::shared_ptr<SLE const>(void) std::shared_ptr<SLE const>(void)
*/ */
template <class Handler> template <class Handler>
SharedPointerType std::shared_ptr<T>
fetch(key_type const& digest, Handler const& h); fetch(key_type const& digest, Handler const& h)
{
{
std::lock_guard l(m_mutex);
if (auto ret = initialFetch(digest, l))
return ret;
}
auto sle = h();
if (!sle)
return {};
std::lock_guard l(m_mutex);
++m_misses;
auto const [it, inserted] =
m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle)));
if (!inserted)
it->second.touch(m_clock.now());
return it->second.ptr;
}
// End CachedSLEs functions. // End CachedSLEs functions.
private: private:
SharedPointerType std::shared_ptr<T>
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l); initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l)
{
auto cit = m_cache.find(key);
if (cit == m_cache.end())
return {};
Entry& entry = cit->second;
if (entry.isCached())
{
++m_hits;
entry.touch(m_clock.now());
return entry.ptr;
}
entry.ptr = entry.lock();
if (entry.isCached())
{
// independent of cache size, so not counted as a hit
++m_cache_count;
entry.touch(m_clock.now());
return entry.ptr;
}
m_cache.erase(cit);
return {};
}
void void
collect_metrics(); collect_metrics()
{
m_stats.size.set(getCacheSize());
{
beast::insight::Gauge::value_type hit_rate(0);
{
std::lock_guard lock(m_mutex);
auto const total(m_hits + m_misses);
if (total != 0)
hit_rate = (m_hits * 100) / total;
}
m_stats.hit_rate.set(hit_rate);
}
}
private: private:
struct Stats struct Stats
@@ -242,37 +600,36 @@ private:
class ValueEntry class ValueEntry
{ {
public: public:
shared_weak_combo_pointer_type ptr; std::shared_ptr<mapped_type> ptr;
std::weak_ptr<mapped_type> weak_ptr;
clock_type::time_point last_access; clock_type::time_point last_access;
ValueEntry( ValueEntry(
clock_type::time_point const& last_access_, clock_type::time_point const& last_access_,
shared_pointer_type const& ptr_) std::shared_ptr<mapped_type> const& ptr_)
: ptr(ptr_), last_access(last_access_) : ptr(ptr_), weak_ptr(ptr_), last_access(last_access_)
{ {
} }
bool bool
isWeak() const isWeak() const
{ {
if (!ptr) return ptr == nullptr;
return true;
return ptr.isWeak();
} }
bool bool
isCached() const isCached() const
{ {
return ptr && ptr.isStrong(); return ptr != nullptr;
} }
bool bool
isExpired() const isExpired() const
{ {
return ptr.expired(); return weak_ptr.expired();
} }
SharedPointerType std::shared_ptr<mapped_type>
lock() lock()
{ {
return ptr.lock(); return weak_ptr.lock();
} }
void void
touch(clock_type::time_point const& now) touch(clock_type::time_point const& now)
@@ -301,7 +658,72 @@ private:
typename KeyValueCacheType::map_type& partition, typename KeyValueCacheType::map_type& partition,
SweptPointersVector& stuffToSweep, SweptPointersVector& stuffToSweep,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
std::lock_guard<std::recursive_mutex> const&); std::lock_guard<std::recursive_mutex> const&)
{
return std::thread([&, this]() {
int cacheRemovals = 0;
int mapRemovals = 0;
// Keep references to all the stuff we sweep
// so that we can destroy them outside the lock.
stuffToSweep.first.reserve(partition.size());
stuffToSweep.second.reserve(partition.size());
{
auto cit = partition.begin();
while (cit != partition.end())
{
if (cit->second.isWeak())
{
// weak
if (cit->second.isExpired())
{
stuffToSweep.second.push_back(
std::move(cit->second.weak_ptr));
++mapRemovals;
cit = partition.erase(cit);
}
else
{
++cit;
}
}
else if (cit->second.last_access <= when_expire)
{
// strong, expired
++cacheRemovals;
if (cit->second.ptr.use_count() == 1)
{
stuffToSweep.first.push_back(
std::move(cit->second.ptr));
++mapRemovals;
cit = partition.erase(cit);
}
else
{
// remains weakly cached
cit->second.ptr.reset();
++cit;
}
}
else
{
// strong, not expired
++cit;
}
}
}
if (mapRemovals || cacheRemovals)
{
JLOG(m_journal.debug())
<< "TaggedCache partition sweep " << m_name
<< ": cache = " << partition.size() << "-" << cacheRemovals
<< ", map-=" << mapRemovals;
}
allRemovals += cacheRemovals;
});
}
[[nodiscard]] std::thread [[nodiscard]] std::thread
sweepHelper( sweepHelper(
@@ -310,7 +732,45 @@ private:
typename KeyOnlyCacheType::map_type& partition, typename KeyOnlyCacheType::map_type& partition,
SweptPointersVector&, SweptPointersVector&,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
std::lock_guard<std::recursive_mutex> const&); std::lock_guard<std::recursive_mutex> const&)
{
return std::thread([&, this]() {
int cacheRemovals = 0;
int mapRemovals = 0;
// Keep references to all the stuff we sweep
// so that we can destroy them outside the lock.
{
auto cit = partition.begin();
while (cit != partition.end())
{
if (cit->second.last_access > now)
{
cit->second.last_access = now;
++cit;
}
else if (cit->second.last_access <= when_expire)
{
cit = partition.erase(cit);
}
else
{
++cit;
}
}
}
if (mapRemovals || cacheRemovals)
{
JLOG(m_journal.debug())
<< "TaggedCache partition sweep " << m_name
<< ": cache = " << partition.size() << "-" << cacheRemovals
<< ", map-=" << mapRemovals;
}
allRemovals += cacheRemovals;
});
};
beast::Journal m_journal; beast::Journal m_journal;
clock_type& m_clock; clock_type& m_clock;
@@ -322,10 +782,10 @@ private:
std::string m_name; std::string m_name;
// Desired number of cache entries (0 = ignore) // Desired number of cache entries (0 = ignore)
int const m_target_size; int m_target_size;
// Desired maximum cache age // Desired maximum cache age
clock_type::duration const m_target_age; clock_type::duration m_target_age;
// Number of items cached // Number of items cached
int m_cache_count; int m_cache_count;

File diff suppressed because it is too large Load Diff

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

@@ -374,7 +374,7 @@ public:
} }
base_uint& base_uint&
operator^=(base_uint const& b) operator^=(const base_uint& b)
{ {
for (int i = 0; i < WIDTH; i++) for (int i = 0; i < WIDTH; i++)
data_[i] ^= b.data_[i]; data_[i] ^= b.data_[i];
@@ -383,7 +383,7 @@ public:
} }
base_uint& base_uint&
operator&=(base_uint const& b) operator&=(const base_uint& b)
{ {
for (int i = 0; i < WIDTH; i++) for (int i = 0; i < WIDTH; i++)
data_[i] &= b.data_[i]; data_[i] &= b.data_[i];
@@ -392,7 +392,7 @@ public:
} }
base_uint& base_uint&
operator|=(base_uint const& b) operator|=(const base_uint& b)
{ {
for (int i = 0; i < WIDTH; i++) for (int i = 0; i < WIDTH; i++)
data_[i] |= b.data_[i]; data_[i] |= b.data_[i];
@@ -415,11 +415,11 @@ public:
return *this; return *this;
} }
base_uint const const base_uint
operator++(int) operator++(int)
{ {
// postfix operator // postfix operator
base_uint const ret = *this; const base_uint ret = *this;
++(*this); ++(*this);
return ret; return ret;
@@ -441,11 +441,11 @@ public:
return *this; return *this;
} }
base_uint const const base_uint
operator--(int) operator--(int)
{ {
// postfix operator // postfix operator
base_uint const ret = *this; const base_uint ret = *this;
--(*this); --(*this);
return ret; return ret;
@@ -466,7 +466,7 @@ public:
} }
base_uint& base_uint&
operator+=(base_uint const& b) operator+=(const base_uint& b)
{ {
std::uint64_t carry = 0; std::uint64_t carry = 0;
@@ -511,7 +511,7 @@ public:
} }
[[nodiscard]] constexpr bool [[nodiscard]] constexpr bool
parseHex(char const* str) parseHex(const char* str)
{ {
return parseHex(std::string_view{str}); return parseHex(std::string_view{str});
} }

View File

@@ -43,7 +43,7 @@ struct less
using result_type = bool; using result_type = bool;
constexpr bool constexpr bool
operator()(T const& left, T const& right) const operator()(const T& left, const T& right) const
{ {
return std::less<T>()(left, right); return std::less<T>()(left, right);
} }
@@ -55,7 +55,7 @@ struct equal_to
using result_type = bool; using result_type = bool;
constexpr bool constexpr bool
operator()(T const& left, T const& right) const operator()(const T& left, const T& right) const
{ {
return std::equal_to<T>()(left, right); return std::equal_to<T>()(left, right);
} }

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

@@ -52,7 +52,7 @@ template <
typename Value, typename Value,
typename Hash, typename Hash,
typename Pred = std::equal_to<Key>, typename Pred = std::equal_to<Key>,
typename Alloc = std::allocator<std::pair<Key const, Value>>> typename Alloc = std::allocator<std::pair<const Key, Value>>>
class partitioned_unordered_map class partitioned_unordered_map
{ {
std::size_t partitions_; std::size_t partitions_;

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 {
@@ -74,13 +76,13 @@ public:
} }
bool bool
operator<(tagged_integer const& rhs) const noexcept operator<(const tagged_integer& rhs) const noexcept
{ {
return m_value < rhs.m_value; return m_value < rhs.m_value;
} }
bool bool
operator==(tagged_integer const& rhs) const noexcept operator==(const tagged_integer& rhs) const noexcept
{ {
return m_value == rhs.m_value; return m_value == rhs.m_value;
} }
@@ -142,14 +144,14 @@ public:
} }
tagged_integer& tagged_integer&
operator<<=(tagged_integer const& rhs) noexcept operator<<=(const tagged_integer& rhs) noexcept
{ {
m_value <<= rhs.m_value; m_value <<= rhs.m_value;
return *this; return *this;
} }
tagged_integer& tagged_integer&
operator>>=(tagged_integer const& rhs) noexcept operator>>=(const tagged_integer& rhs) noexcept
{ {
m_value >>= rhs.m_value; m_value >>= rhs.m_value;
return *this; return *this;

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

@@ -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

@@ -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

@@ -48,10 +48,8 @@ rngfill(void* buffer, std::size_t bytes, Generator& g)
#ifdef __GNUC__ #ifdef __GNUC__
// gcc 11.1 (falsely) warns about an array-bounds overflow in release mode. // gcc 11.1 (falsely) warns about an array-bounds overflow in release mode.
// gcc 12.1 (also falsely) warns about an string overflow in release mode.
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds" #pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif #endif
if (bytes > 0) if (bytes > 0)

View File

@@ -37,9 +37,9 @@ class temp_dir
public: public:
#if !GENERATING_DOCS #if !GENERATING_DOCS
temp_dir(temp_dir const&) = delete; temp_dir(const temp_dir&) = delete;
temp_dir& temp_dir&
operator=(temp_dir const&) = delete; operator=(const temp_dir&) = delete;
#endif #endif
/// Construct a temporary directory. /// Construct a temporary directory.

View File

@@ -39,7 +39,7 @@ class Reader
{ {
public: public:
using Char = char; using Char = char;
using Location = Char const*; using Location = const Char*;
/** \brief Constructs a Reader allowing all features /** \brief Constructs a Reader allowing all features
* for parsing. * for parsing.
@@ -64,7 +64,7 @@ public:
* error occurred. * error occurred.
*/ */
bool bool
parse(char const* beginDoc, char const* endDoc, Value& root); parse(const char* beginDoc, const char* endDoc, Value& root);
/// \brief Parse from input stream. /// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&). /// \see Json::operator>>(std::istream&, Json::Value&).
@@ -133,7 +133,7 @@ private:
using Errors = std::deque<ErrorInfo>; using Errors = std::deque<ErrorInfo>;
bool bool
expectToken(TokenType type, Token& token, char const* message); expectToken(TokenType type, Token& token, const char* message);
bool bool
readToken(Token& token); readToken(Token& token);
void void

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>
@@ -62,24 +61,24 @@ enum ValueType {
class StaticString class StaticString
{ {
public: public:
constexpr explicit StaticString(char const* czstring) : str_(czstring) constexpr explicit StaticString(const char* czstring) : str_(czstring)
{ {
} }
constexpr constexpr
operator char const*() const operator const char*() const
{ {
return str_; return str_;
} }
constexpr char const* constexpr const char*
c_str() const c_str() const
{ {
return str_; return str_;
} }
private: private:
char const* str_; const char* str_;
}; };
inline bool inline bool
@@ -157,10 +156,10 @@ public:
using Int = Json::Int; using Int = Json::Int;
using ArrayIndex = UInt; using ArrayIndex = UInt;
static Value const null; static const Value null;
static Int const minInt; static const Int minInt;
static Int const maxInt; static const Int maxInt;
static UInt const maxUInt; static const UInt maxUInt;
private: private:
class CZString class CZString
@@ -172,24 +171,24 @@ private:
duplicateOnCopy duplicateOnCopy
}; };
CZString(int index); CZString(int index);
CZString(char const* cstr, DuplicationPolicy allocate); CZString(const char* cstr, DuplicationPolicy allocate);
CZString(CZString const& other); CZString(const CZString& other);
~CZString(); ~CZString();
CZString& CZString&
operator=(CZString const& other) = delete; operator=(const CZString& other) = delete;
bool bool
operator<(CZString const& other) const; operator<(const CZString& other) const;
bool bool
operator==(CZString const& other) const; operator==(const CZString& other) const;
int int
index() const; index() const;
char const* const char*
c_str() const; c_str() const;
bool bool
isStaticString() const; isStaticString() const;
private: private:
char const* cstr_; const char* cstr_;
int index_; int index_;
}; };
@@ -216,8 +215,7 @@ public:
Value(Int value); Value(Int value);
Value(UInt value); Value(UInt value);
Value(double value); Value(double value);
Value(char const* value); Value(const char* 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
@@ -229,10 +227,10 @@ public:
* Json::Value aValue( StaticString("some text") ); * Json::Value aValue( StaticString("some text") );
* \endcode * \endcode
*/ */
Value(StaticString const& value); Value(const StaticString& value);
Value(std::string const& value); Value(std::string const& value);
Value(bool value); Value(bool value);
Value(Value const& other); Value(const Value& other);
~Value(); ~Value();
Value& Value&
@@ -249,7 +247,7 @@ public:
ValueType ValueType
type() const; type() const;
char const* const char*
asCString() const; asCString() const;
/** Returns the unquoted string value. */ /** Returns the unquoted string value. */
std::string std::string
@@ -319,12 +317,12 @@ public:
/// Access an array element (zero based index ) /// Access an array element (zero based index )
/// (You may need to say 'value[0u]' to get your compiler to distinguish /// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.) /// this from the operator[] which takes a string.)
Value const& const Value&
operator[](UInt index) const; operator[](UInt index) const;
/// If the array contains at least index+1 elements, returns the element /// If the array contains at least index+1 elements, returns the element
/// value, otherwise returns defaultValue. /// value, otherwise returns defaultValue.
Value Value
get(UInt index, Value const& defaultValue) const; get(UInt index, const Value& defaultValue) const;
/// Return true if index < size(). /// Return true if index < size().
bool bool
isValidIndex(UInt index) const; isValidIndex(UInt index) const;
@@ -332,25 +330,25 @@ public:
/// ///
/// Equivalent to jsonvalue[jsonvalue.size()] = value; /// Equivalent to jsonvalue[jsonvalue.size()] = value;
Value& Value&
append(Value const& value); append(const Value& value);
Value& Value&
append(Value&& value); append(Value&& value);
/// Access an object value by name, create a null member if it does not /// Access an object value by name, create a null member if it does not
/// exist. /// exist.
Value& Value&
operator[](char const* key); operator[](const char* key);
/// Access an object value by name, returns null if there is no member with /// Access an object value by name, returns null if there is no member with
/// that name. /// that name.
Value const& const Value&
operator[](char const* key) const; operator[](const char* key) const;
/// Access an object value by name, create a null member if it does not /// Access an object value by name, create a null member if it does not
/// exist. /// exist.
Value& Value&
operator[](std::string const& key); operator[](std::string const& key);
/// Access an object value by name, returns null if there is no member with /// Access an object value by name, returns null if there is no member with
/// that name. /// that name.
Value const& const Value&
operator[](std::string const& key) const; operator[](std::string const& key) const;
/** \brief Access an object value by name, create a null member if it does /** \brief Access an object value by name, create a null member if it does
not exist. not exist.
@@ -366,16 +364,14 @@ public:
* \endcode * \endcode
*/ */
Value& Value&
operator[](StaticString const& key); operator[](const StaticString& 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
get(char const* key, Value const& defaultValue) const; get(const char* key, const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise. /// Return the member named key if it exist, defaultValue otherwise.
Value Value
get(std::string const& key, Value const& defaultValue) const; get(std::string const& key, const Value& defaultValue) const;
/// \brief Remove and return the named member. /// \brief Remove and return the named member.
/// ///
@@ -384,14 +380,14 @@ public:
/// \pre type() is objectValue or nullValue /// \pre type() is objectValue or nullValue
/// \post type() is unchanged /// \post type() is unchanged
Value Value
removeMember(char const* key); removeMember(const char* key);
/// Same as removeMember(const char*) /// Same as removeMember(const char*)
Value Value
removeMember(std::string const& key); removeMember(std::string const& key);
/// Return true if the object has a member named key. /// Return true if the object has a member named key.
bool bool
isMember(char const* key) const; isMember(const char* key) const;
/// Return true if the object has a member named key. /// Return true if the object has a member named key.
bool bool
isMember(std::string const& key) const; isMember(std::string const& key) const;
@@ -418,13 +414,13 @@ public:
end(); end();
friend bool friend bool
operator==(Value const&, Value const&); operator==(const Value&, const Value&);
friend bool friend bool
operator<(Value const&, Value const&); operator<(const Value&, const Value&);
private: private:
Value& Value&
resolveReference(char const* key, bool isStatic); resolveReference(const char* key, bool isStatic);
private: private:
union ValueHolder union ValueHolder
@@ -440,38 +436,32 @@ 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==(const Value&, const Value&);
inline bool inline bool
operator!=(Value const& x, Value const& y) operator!=(const Value& x, const Value& y)
{ {
return !(x == y); return !(x == y);
} }
bool bool
operator<(Value const&, Value const&); operator<(const Value&, const Value&);
inline bool inline bool
operator<=(Value const& x, Value const& y) operator<=(const Value& x, const Value& y)
{ {
return !(y < x); return !(y < x);
} }
inline bool inline bool
operator>(Value const& x, Value const& y) operator>(const Value& x, const Value& y)
{ {
return y < x; return y < x;
} }
inline bool inline bool
operator>=(Value const& x, Value const& y) operator>=(const Value& x, const Value& y)
{ {
return !(x < y); return !(x < y);
} }
@@ -492,11 +482,11 @@ public:
virtual ~ValueAllocator() = default; virtual ~ValueAllocator() = default;
virtual char* virtual char*
makeMemberName(char const* memberName) = 0; makeMemberName(const char* memberName) = 0;
virtual void virtual void
releaseMemberName(char* memberName) = 0; releaseMemberName(char* memberName) = 0;
virtual char* virtual char*
duplicateStringValue(char const* value, unsigned int length = unknown) = 0; duplicateStringValue(const char* value, unsigned int length = unknown) = 0;
virtual void virtual void
releaseStringValue(char* value) = 0; releaseStringValue(char* value) = 0;
}; };
@@ -513,16 +503,16 @@ public:
ValueIteratorBase(); ValueIteratorBase();
explicit ValueIteratorBase(Value::ObjectValues::iterator const& current); explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
bool bool
operator==(SelfType const& other) const operator==(const SelfType& other) const
{ {
return isEqual(other); return isEqual(other);
} }
bool bool
operator!=(SelfType const& other) const operator!=(const SelfType& other) const
{ {
return !isEqual(other); return !isEqual(other);
} }
@@ -538,7 +528,7 @@ public:
/// Return the member name of the referenced Value. "" if it is not an /// Return the member name of the referenced Value. "" if it is not an
/// objectValue. /// objectValue.
char const* const char*
memberName() const; memberName() const;
protected: protected:
@@ -552,13 +542,13 @@ protected:
decrement(); decrement();
difference_type difference_type
computeDistance(SelfType const& other) const; computeDistance(const SelfType& other) const;
bool bool
isEqual(SelfType const& other) const; isEqual(const SelfType& other) const;
void void
copy(SelfType const& other); copy(const SelfType& other);
private: private:
Value::ObjectValues::iterator current_; Value::ObjectValues::iterator current_;
@@ -576,8 +566,8 @@ class ValueConstIterator : public ValueIteratorBase
public: public:
using size_t = unsigned int; using size_t = unsigned int;
using difference_type = int; using difference_type = int;
using reference = Value const&; using reference = const Value&;
using pointer = Value const*; using pointer = const Value*;
using SelfType = ValueConstIterator; using SelfType = ValueConstIterator;
ValueConstIterator() = default; ValueConstIterator() = default;
@@ -585,11 +575,11 @@ public:
private: private:
/*! \internal Use by Value to create an iterator. /*! \internal Use by Value to create an iterator.
*/ */
explicit ValueConstIterator(Value::ObjectValues::iterator const& current); explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
public: public:
SelfType& SelfType&
operator=(ValueIteratorBase const& other); operator=(const ValueIteratorBase& other);
SelfType SelfType
operator++(int) operator++(int)
@@ -642,17 +632,17 @@ public:
using SelfType = ValueIterator; using SelfType = ValueIterator;
ValueIterator() = default; ValueIterator() = default;
ValueIterator(ValueConstIterator const& other); ValueIterator(const ValueConstIterator& other);
ValueIterator(ValueIterator const& other); ValueIterator(const ValueIterator& other);
private: private:
/*! \internal Use by Value to create an iterator. /*! \internal Use by Value to create an iterator.
*/ */
explicit ValueIterator(Value::ObjectValues::iterator const& current); explicit ValueIterator(const Value::ObjectValues::iterator& current);
public: public:
SelfType& SelfType&
operator=(SelfType const& other); operator=(const SelfType& other);
SelfType SelfType
operator++(int) operator++(int)

View File

@@ -39,7 +39,7 @@ public:
{ {
} }
virtual std::string virtual std::string
write(Value const& root) = 0; write(const Value& root) = 0;
}; };
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
@@ -60,11 +60,11 @@ public:
public: // overridden from Writer public: // overridden from Writer
std::string std::string
write(Value const& root) override; write(const Value& root) override;
private: private:
void void
writeValue(Value const& value); writeValue(const Value& value);
std::string document_; std::string document_;
}; };
@@ -101,15 +101,15 @@ public: // overridden from Writer
* JSON document that represents the root value. * JSON document that represents the root value.
*/ */
std::string std::string
write(Value const& root) override; write(const Value& root) override;
private: private:
void void
writeValue(Value const& value); writeValue(const Value& value);
void void
writeArrayValue(Value const& value); writeArrayValue(const Value& value);
bool bool
isMultineArray(Value const& value); isMultineArray(const Value& value);
void void
pushValue(std::string const& value); pushValue(std::string const& value);
void void
@@ -168,15 +168,15 @@ public:
* return a value. * return a value.
*/ */
void void
write(std::ostream& out, Value const& root); write(std::ostream& out, const Value& root);
private: private:
void void
writeValue(Value const& value); writeValue(const Value& value);
void void
writeArrayValue(Value const& value); writeArrayValue(const Value& value);
bool bool
isMultineArray(Value const& value); isMultineArray(const Value& value);
void void
pushValue(std::string const& value); pushValue(std::string const& value);
void void
@@ -207,12 +207,12 @@ valueToString(double value);
std::string std::string
valueToString(bool value); valueToString(bool value);
std::string std::string
valueToQuotedString(char const* value); valueToQuotedString(const char* value);
/// \brief Output using the StyledStreamWriter. /// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>() /// \see Json::operator>>()
std::ostream& std::ostream&
operator<<(std::ostream&, Value const& root); operator<<(std::ostream&, const Value& root);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@@ -37,7 +37,7 @@ pretty(Value const&);
/** Output using the StyledStreamWriter. @see Json::operator>>(). */ /** Output using the StyledStreamWriter. @see Json::operator>>(). */
std::ostream& std::ostream&
operator<<(std::ostream&, Value const& root); operator<<(std::ostream&, const Value& root);
} // namespace Json } // namespace Json

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

@@ -120,7 +120,7 @@ enum error_code_i {
rpcSRC_ACT_MALFORMED = 65, rpcSRC_ACT_MALFORMED = 65,
rpcSRC_ACT_MISSING = 66, rpcSRC_ACT_MISSING = 66,
rpcSRC_ACT_NOT_FOUND = 67, rpcSRC_ACT_NOT_FOUND = 67,
rpcDELEGATE_ACT_NOT_FOUND = 68, // unused 68,
rpcSRC_CUR_MALFORMED = 69, rpcSRC_CUR_MALFORMED = 69,
rpcSRC_ISR_MALFORMED = 70, rpcSRC_ISR_MALFORMED = 70,
rpcSTREAM_MALFORMED = 71, rpcSTREAM_MALFORMED = 71,
@@ -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>
@@ -54,18 +55,6 @@
* `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) A feature marked as Obsolete can mean either:
* 1) It is in the ledger (marked as Supported::yes) and it is on its way to
* become Retired
* 2) The feature is not in the ledger (has always been marked as
* Supported::no) and the code to support it has been removed
*
* If we want to discontinue a feature that we've never fully supported and
* the feature has never been enabled, we should remove all the related
* code, and mark the feature as "abandoned". To do this:
*
* 1) Open features.macro, move the feature to the abandoned section and
* change the macro to XRPL_ABANDON
* *
* When a feature has been enabled for several years, the conditional code * When a feature has been enabled for several years, the conditional code
* may be removed, and the feature "retired". To retire a feature: * may be removed, and the feature "retired". To retire a feature:
@@ -99,13 +88,10 @@ namespace detail {
#undef XRPL_FIX #undef XRPL_FIX
#pragma push_macro("XRPL_RETIRE") #pragma push_macro("XRPL_RETIRE")
#undef XRPL_RETIRE #undef XRPL_RETIRE
#pragma push_macro("XRPL_ABANDON")
#undef XRPL_ABANDON
#define XRPL_FEATURE(name, supported, vote) +1 #define XRPL_FEATURE(name, supported, vote) +1
#define XRPL_FIX(name, supported, vote) +1 #define XRPL_FIX(name, supported, vote) +1
#define XRPL_RETIRE(name) +1 #define XRPL_RETIRE(name) +1
#define XRPL_ABANDON(name) +1
// This value SHOULD be equal to the number of amendments registered in // This value SHOULD be equal to the number of amendments registered in
// Feature.cpp. Because it's only used to reserve storage, and determine how // Feature.cpp. Because it's only used to reserve storage, and determine how
@@ -122,8 +108,6 @@ static constexpr std::size_t numFeatures =
#pragma pop_macro("XRPL_FIX") #pragma pop_macro("XRPL_FIX")
#undef XRPL_FEATURE #undef XRPL_FEATURE
#pragma pop_macro("XRPL_FEATURE") #pragma pop_macro("XRPL_FEATURE")
#undef XRPL_ABANDON
#pragma pop_macro("XRPL_ABANDON")
/** Amendments that this server supports and the default voting behavior. /** Amendments that this server supports and the default voting behavior.
Whether they are enabled depends on the Rules defined in the validated Whether they are enabled depends on the Rules defined in the validated
@@ -365,13 +349,10 @@ foreachFeature(FeatureBitset bs, F&& f)
#undef XRPL_FIX #undef XRPL_FIX
#pragma push_macro("XRPL_RETIRE") #pragma push_macro("XRPL_RETIRE")
#undef XRPL_RETIRE #undef XRPL_RETIRE
#pragma push_macro("XRPL_ABANDON")
#undef XRPL_ABANDON
#define XRPL_FEATURE(name, supported, vote) extern uint256 const feature##name; #define XRPL_FEATURE(name, supported, vote) extern uint256 const feature##name;
#define XRPL_FIX(name, supported, vote) extern uint256 const fix##name; #define XRPL_FIX(name, supported, vote) extern uint256 const fix##name;
#define XRPL_RETIRE(name) #define XRPL_RETIRE(name)
#define XRPL_ABANDON(name)
#include <xrpl/protocol/detail/features.macro> #include <xrpl/protocol/detail/features.macro>
@@ -381,8 +362,6 @@ foreachFeature(FeatureBitset bs, F&& f)
#pragma pop_macro("XRPL_FIX") #pragma pop_macro("XRPL_FIX")
#undef XRPL_FEATURE #undef XRPL_FEATURE
#pragma pop_macro("XRPL_FEATURE") #pragma pop_macro("XRPL_FEATURE")
#undef XRPL_ABANDON
#pragma pop_macro("XRPL_ABANDON")
} // namespace ripple } // namespace ripple

View File

@@ -27,9 +27,14 @@
#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 {
@@ -331,7 +336,7 @@ public:
// Output Fees 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, TaggedFee<UnitTag, T> const& q) operator<<(std::basic_ostream<Char, Traits>& os, const TaggedFee<UnitTag, T>& q)
{ {
return os << q.value(); return os << q.value();
} }

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 {
@@ -280,10 +279,6 @@ amm(Asset const& issue1, Asset const& issue2) noexcept;
Keylet Keylet
amm(uint256 const& amm) noexcept; amm(uint256 const& amm) noexcept;
/** A keylet for Delegate object */
Keylet
delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept;
Keylet Keylet
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType); bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType);
@@ -335,15 +330,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 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

@@ -132,7 +132,7 @@ enum LedgerSpecificFlags {
lsfNoFreeze = 0x00200000, // True, cannot freeze ripple states lsfNoFreeze = 0x00200000, // True, cannot freeze ripple states
lsfGlobalFreeze = 0x00400000, // True, all assets frozen lsfGlobalFreeze = 0x00400000, // True, all assets frozen
lsfDefaultRipple = lsfDefaultRipple =
0x00800000, // True, incoming trust lines allow rippling by default 0x00800000, // True, trust lines allow rippling by default
lsfDepositAuth = 0x01000000, // True, all deposits require authorization lsfDepositAuth = 0x01000000, // True, all deposits require authorization
/* // reserved for Hooks amendment /* // reserved for Hooks amendment
lsfTshCollect = 0x02000000, // True, allow TSH collect-calls to acc hooks lsfTshCollect = 0x02000000, // True, allow TSH collect-calls to acc hooks
@@ -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,9 +191,6 @@ enum LedgerSpecificFlags {
// ltCREDENTIAL // ltCREDENTIAL
lsfAccepted = 0x00010000, lsfAccepted = 0x00010000,
// ltVAULT
lsfVaultPrivate = 0x00010000,
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

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>
@@ -79,7 +80,7 @@ struct MultiApiJson
} }
void void
set(char const* key, auto const& v) set(const char* key, auto const& v)
requires std::constructible_from<Json::Value, decltype(v)> requires std::constructible_from<Json::Value, decltype(v)>
{ {
for (auto& a : this->val) for (auto& a : this->val)
@@ -90,7 +91,7 @@ struct MultiApiJson
enum IsMemberResult : int { none = 0, some, all }; enum IsMemberResult : int { none = 0, some, all };
[[nodiscard]] IsMemberResult [[nodiscard]] IsMemberResult
isMember(char const* key) const isMember(const char* key) const
{ {
int count = 0; int count = 0;
for (auto& a : this->val) for (auto& a : this->val)

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

@@ -1,96 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2025 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED
#define RIPPLE_PROTOCOL_PERMISSION_H_INCLUDED
#include <xrpl/protocol/TxFormats.h>
#include <optional>
#include <string>
#include <unordered_map>
namespace ripple {
/**
* We have both transaction type permissions and granular type permissions.
* Since we will reuse the TransactionFormats to parse the Transaction
* Permissions, only the GranularPermissionType is defined here. To prevent
* conflicts with TxType, the GranularPermissionType is always set to a value
* greater than the maximum value of uint16.
*/
enum GranularPermissionType : std::uint32_t {
#pragma push_macro("PERMISSION")
#undef PERMISSION
#define PERMISSION(type, txType, value) type = value,
#include <xrpl/protocol/detail/permissions.macro>
#undef PERMISSION
#pragma pop_macro("PERMISSION")
};
enum Delegation { delegatable, notDelegatable };
class Permission
{
private:
Permission();
std::unordered_map<std::uint16_t, Delegation> delegatableTx_;
std::unordered_map<std::string, GranularPermissionType>
granularPermissionMap_;
std::unordered_map<GranularPermissionType, std::string> granularNameMap_;
std::unordered_map<GranularPermissionType, TxType> granularTxTypeMap_;
public:
static Permission const&
getInstance();
Permission(Permission const&) = delete;
Permission&
operator=(Permission const&) = delete;
std::optional<std::uint32_t>
getGranularValue(std::string const& name) const;
std::optional<std::string>
getGranularName(GranularPermissionType const& value) const;
std::optional<TxType>
getGranularTxType(GranularPermissionType const& gpType) const;
bool
isDelegatable(std::uint32_t const& permissionValue) const;
// for tx level permission, permission value is equal to tx type plus one
uint32_t
txToPermissionType(TxType const& type) const;
// tx type value is permission value minus one
TxType
permissionToTxType(uint32_t const& value) const;
};
} // namespace ripple
#endif

View File

@@ -116,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;
@@ -165,13 +155,6 @@ std::size_t constexpr maxPriceScale = 20;
*/ */
std::size_t constexpr maxTrim = 25; std::size_t constexpr maxTrim = 25;
/** The maximum number of delegate permissions an account can grant
*/
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 {

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