mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-18 18:15:50 +00:00
Compare commits
243 Commits
vlntb/RIPD
...
ximinez/le
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5656f83290 | ||
|
|
dc7033805b | ||
|
|
2d767f2733 | ||
|
|
784b3ae64d | ||
|
|
d8cb1a00d5 | ||
|
|
dfb3d970be | ||
|
|
12524bea35 | ||
|
|
bd014e270a | ||
|
|
368e496d5f | ||
|
|
6d49b42497 | ||
|
|
f91a737184 | ||
|
|
8483115637 | ||
|
|
024b016d83 | ||
|
|
c6c7c84355 | ||
|
|
28f50cb7cf | ||
|
|
20f6f8958f | ||
|
|
3e152fec74 | ||
|
|
2db2791805 | ||
|
|
fc9197837c | ||
|
|
65fe44a449 | ||
|
|
ac0e4dec96 | ||
|
|
aead1bfb3d | ||
|
|
e6b9108d26 | ||
|
|
8eaa9e7b96 | ||
|
|
283331b3bd | ||
|
|
4189aa8713 | ||
|
|
bbe49132a6 | ||
|
|
84abcba497 | ||
|
|
9ec2d7f8ff | ||
|
|
a87f58eb22 | ||
|
|
1925ceace6 | ||
|
|
140fd829a0 | ||
|
|
4a084ce34c | ||
|
|
b3657220de | ||
|
|
117bfcc4a1 | ||
|
|
4c6c8a08c9 | ||
|
|
7b680ed47b | ||
|
|
6c97d2ec7e | ||
|
|
3c386bee4e | ||
|
|
5472d7e1ff | ||
|
|
01cc089b0c | ||
|
|
ffb1959be5 | ||
|
|
efe9f99b50 | ||
|
|
b03cd57a92 | ||
|
|
071beca306 | ||
|
|
3502df2174 | ||
|
|
298aaac456 | ||
|
|
a205906e54 | ||
|
|
d46a2d8a71 | ||
|
|
5bfbb09970 | ||
|
|
7e5845f209 | ||
|
|
22901af25d | ||
|
|
e9491669a7 | ||
|
|
fa1e25abef | ||
|
|
77c70d8a64 | ||
|
|
afeb6287f5 | ||
|
|
b2abfc0bd2 | ||
|
|
6a25ac9481 | ||
|
|
fb2eb3522d | ||
|
|
217ba8dd4d | ||
|
|
270355f77a | ||
|
|
5cd3b1fb59 | ||
|
|
7eadb88d0d | ||
|
|
0ab792263a | ||
|
|
20ce0e79ab | ||
|
|
d6d07e6fcf | ||
|
|
51f1764e50 | ||
|
|
b1bf115536 | ||
|
|
405f4613d8 | ||
|
|
457877118e | ||
|
|
cba512068b | ||
|
|
1c99ea23d1 | ||
|
|
5fea68eb41 | ||
|
|
2abbb25bc3 | ||
|
|
c4308b216f | ||
|
|
aafd2d8525 | ||
|
|
75375905a4 | ||
|
|
cd726f96d4 | ||
|
|
a574ec6023 | ||
|
|
e429455f4d | ||
|
|
870f42e5f7 | ||
|
|
780d05ec97 | ||
|
|
7692eeb9a0 | ||
|
|
a099f5a804 | ||
|
|
f839049de7 | ||
|
|
5f051c53f1 | ||
|
|
db19760ee8 | ||
|
|
9c967f83be | ||
|
|
442795bfeb | ||
|
|
ca0bc767fe | ||
|
|
4ba9288935 | ||
|
|
e923ec6d36 | ||
|
|
e1e8859137 | ||
|
|
851d99d99e | ||
|
|
1494ae38e1 | ||
|
|
8f9524b5af | ||
|
|
676ed9ad04 | ||
|
|
f6a9b4f5b1 | ||
|
|
2737249500 | ||
|
|
591437b914 | ||
|
|
af8ea3fb40 | ||
|
|
6f4e7e8e44 | ||
|
|
392e3846ed | ||
|
|
85e7d293ca | ||
|
|
dbbf6829b9 | ||
|
|
5f53e4d1f8 | ||
|
|
fa0b021fb8 | ||
|
|
09833abd46 | ||
|
|
dc249b8b6d | ||
|
|
f608e653ca | ||
|
|
ad6e048ab2 | ||
|
|
2b86a1a557 | ||
|
|
93bd26547f | ||
|
|
b6c74303c1 | ||
|
|
a1c21a06bc | ||
|
|
b67d8e676b | ||
|
|
83582b6731 | ||
|
|
124512eba9 | ||
|
|
1807b441ee | ||
|
|
d3c1d02c72 | ||
|
|
f77ad36283 | ||
|
|
aff08b7543 | ||
|
|
696cf2b563 | ||
|
|
72e076b694 | ||
|
|
abaf213336 | ||
|
|
6cf37c4abe | ||
|
|
0f99955ae9 | ||
|
|
7686c3d88d | ||
|
|
33660eadc6 | ||
|
|
0636d4695d | ||
|
|
b6d7ef6c02 | ||
|
|
2e13dc1e85 | ||
|
|
dee06df012 | ||
|
|
f5042df72b | ||
|
|
d16e0518fd | ||
|
|
3883bafd52 | ||
|
|
275e02f190 | ||
|
|
afaa6aec8b | ||
|
|
fc204773d6 | ||
|
|
05ebd0d8a6 | ||
|
|
372555bda8 | ||
|
|
2bc5cb240f | ||
|
|
2f06b344a7 | ||
|
|
fbe28f6536 | ||
|
|
ae68a09b06 | ||
|
|
dd3edbd5b0 | ||
|
|
a173dd20e2 | ||
|
|
cc4f87729f | ||
|
|
1e565e8488 | ||
|
|
9c1a0aad7d | ||
|
|
d8880ddb48 | ||
|
|
1f005d2370 | ||
|
|
0959bf82b7 | ||
|
|
58f15307ba | ||
|
|
3d2102106c | ||
|
|
4c7119b92f | ||
|
|
6b1cf7cee7 | ||
|
|
9a7def38b5 | ||
|
|
b1fc3b7c41 | ||
|
|
4e862e0afd | ||
|
|
403ef0d6c2 | ||
|
|
6db2144912 | ||
|
|
d77fc57c6a | ||
|
|
1df3ff8d76 | ||
|
|
8e68838543 | ||
|
|
2a8861d1c5 | ||
|
|
df8761d9f3 | ||
|
|
7b5680f536 | ||
|
|
b397524d85 | ||
|
|
e0932635ed | ||
|
|
238db87b7d | ||
|
|
840a4644c2 | ||
|
|
4c586eb4b0 | ||
|
|
3715d7e2e4 | ||
|
|
90fef02164 | ||
|
|
7b4e901dd7 | ||
|
|
8ca6a62b84 | ||
|
|
65fdac09b3 | ||
|
|
1441c919ad | ||
|
|
b0c2b97663 | ||
|
|
1589498ae1 | ||
|
|
4dc2025378 | ||
|
|
fc2e1a2b5a | ||
|
|
1756fa7d08 | ||
|
|
ac6d26a8b3 | ||
|
|
152da6e078 | ||
|
|
6370448299 | ||
|
|
04503c9fa4 | ||
|
|
a0632a0cb3 | ||
|
|
3f5df80b47 | ||
|
|
9d619b9dc5 | ||
|
|
e9ed80026e | ||
|
|
c1d8bc4928 | ||
|
|
87d8881c81 | ||
|
|
b7c9577230 | ||
|
|
ffaa8bd24b | ||
|
|
acaed58d85 | ||
|
|
1884ec5e60 | ||
|
|
6765c101a8 | ||
|
|
9decc053e3 | ||
|
|
8baadd5ec3 | ||
|
|
d1c7d1ae0f | ||
|
|
c3f9a4c6ff | ||
|
|
eed18d16ce | ||
|
|
21e0e7e97b | ||
|
|
a98e59a29a | ||
|
|
06a8a61b23 | ||
|
|
ad68074d72 | ||
|
|
3eebdae3f0 | ||
|
|
02dec4f797 | ||
|
|
65d6c48b4a | ||
|
|
86d249a5bb | ||
|
|
9bf9a1ef12 | ||
|
|
2c4a2244e9 | ||
|
|
25a20adf39 | ||
|
|
c08f86d473 | ||
|
|
580a85f2c8 | ||
|
|
dbaa12aa1c | ||
|
|
c325b6c7f5 | ||
|
|
375614d7ec | ||
|
|
bf8bbffab1 | ||
|
|
8d5cfb910a | ||
|
|
241429ba32 | ||
|
|
b9f1200652 | ||
|
|
526f715f16 | ||
|
|
eae2cd3328 | ||
|
|
ecec6e5d33 | ||
|
|
ad581661e3 | ||
|
|
b5619fbcd6 | ||
|
|
54d511b0db | ||
|
|
12646cb89e | ||
|
|
ea30f44247 | ||
|
|
ea6c040f10 | ||
|
|
1ff1274ee5 | ||
|
|
12552162c9 | ||
|
|
6046fa239c | ||
|
|
286612cf19 | ||
|
|
ebc97aee25 | ||
|
|
1680477e39 | ||
|
|
d09e74e548 | ||
|
|
a8ec8e7eaa | ||
|
|
ff8c6491d7 | ||
|
|
1a032f04e3 |
@@ -94,3 +94,4 @@ SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
QualifierAlignment: Right
|
||||
8
.github/CODEOWNERS
vendored
Normal file
8
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Allow anyone to review any change by default.
|
||||
*
|
||||
|
||||
# Require the rpc-reviewers team to review changes to the rpc code.
|
||||
include/libxrpl/protocol/ @xrplf/rpc-reviewers
|
||||
src/libxrpl/protocol/ @xrplf/rpc-reviewers
|
||||
src/xrpld/rpc/ @xrplf/rpc-reviewers
|
||||
src/xrpld/app/misc/ @xrplf/rpc-reviewers
|
||||
8
.github/workflows/clang-format.yml
vendored
8
.github/workflows/clang-format.yml
vendored
@@ -1,9 +1,13 @@
|
||||
name: clang-format
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
|
||||
jobs:
|
||||
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
|
||||
env:
|
||||
CLANG_VERSION: 18
|
||||
@@ -20,7 +24,7 @@ jobs:
|
||||
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 {} +
|
||||
run: find include src tests -type f \( -name '*.cpp' -o -name '*.hpp' -o -name '*.h' -o -name '*.ipp' \) -exec clang-format-${CLANG_VERSION} -i {} +
|
||||
- name: Check for differences
|
||||
id: assert
|
||||
run: |
|
||||
|
||||
2
.github/workflows/doxygen.yml
vendored
2
.github/workflows/doxygen.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
container: rippleci/rippled-build-ubuntu:aaf5e3e
|
||||
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
6
.github/workflows/levelization.yml
vendored
6
.github/workflows/levelization.yml
vendored
@@ -1,9 +1,13 @@
|
||||
name: levelization
|
||||
|
||||
on: [push, pull_request]
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
|
||||
jobs:
|
||||
check:
|
||||
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CLANG_VERSION: 10
|
||||
|
||||
4
.github/workflows/libxrpl.yml
vendored
4
.github/workflows/libxrpl.yml
vendored
@@ -8,19 +8,21 @@ on:
|
||||
paths:
|
||||
- 'src/libxrpl/protocol/BuildInfo.cpp'
|
||||
- '.github/workflows/libxrpl.yml'
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
|
||||
name: Publish libXRPL
|
||||
outputs:
|
||||
outcome: ${{ steps.upload.outputs.outcome }}
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
channel: ${{ steps.channel.outputs.channel }}
|
||||
runs-on: [self-hosted, heavy]
|
||||
container: rippleci/rippled-build-ubuntu:aaf5e3e
|
||||
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
|
||||
steps:
|
||||
- name: Wait for essential checks to succeed
|
||||
uses: lewagon/wait-on-check-action@v1.3.4
|
||||
|
||||
13
.github/workflows/macos.yml
vendored
13
.github/workflows/macos.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: macos
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
push:
|
||||
# If the branches list is ever changed, be sure to change it on all
|
||||
# build/test jobs (nix, macos, windows, instrumentation)
|
||||
@@ -18,6 +19,7 @@ concurrency:
|
||||
jobs:
|
||||
|
||||
test:
|
||||
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
|
||||
strategy:
|
||||
matrix:
|
||||
platform:
|
||||
@@ -87,8 +89,9 @@ jobs:
|
||||
generator: ${{ matrix.generator }}
|
||||
configuration: ${{ matrix.configuration }}
|
||||
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
|
||||
- name: test
|
||||
run: |
|
||||
n=$(nproc)
|
||||
echo "Using $n test jobs"
|
||||
${build_dir}/rippled --unittest --unittest-jobs $n
|
||||
# TODO: Temporary disabled tests
|
||||
# - name: test
|
||||
# run: |
|
||||
# n=$(nproc)
|
||||
# echo "Using $n test jobs"
|
||||
# ${build_dir}/rippled --unittest --unittest-jobs $n
|
||||
|
||||
67
.github/workflows/nix.yml
vendored
67
.github/workflows/nix.yml
vendored
@@ -1,6 +1,7 @@
|
||||
name: nix
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
push:
|
||||
# If the branches list is ever changed, be sure to change it on all
|
||||
# build/test jobs (nix, macos, windows)
|
||||
@@ -39,6 +40,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
dependencies:
|
||||
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -62,7 +64,7 @@ jobs:
|
||||
cc: /usr/bin/clang-14
|
||||
cxx: /usr/bin/clang++-14
|
||||
runs-on: [self-hosted, heavy]
|
||||
container: rippleci/rippled-build-ubuntu:aaf5e3e
|
||||
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
|
||||
env:
|
||||
build_dir: .build
|
||||
steps:
|
||||
@@ -124,7 +126,61 @@ jobs:
|
||||
- "-Dunity=ON"
|
||||
needs: dependencies
|
||||
runs-on: [self-hosted, heavy]
|
||||
container: rippleci/rippled-build-ubuntu:aaf5e3e
|
||||
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
|
||||
env:
|
||||
build_dir: .build
|
||||
steps:
|
||||
- name: upgrade conan
|
||||
run: |
|
||||
pip install --upgrade "conan<2"
|
||||
- name: download cache
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.platform }}-${{ matrix.compiler }}-${{ matrix.configuration }}
|
||||
- name: extract cache
|
||||
run: |
|
||||
mkdir -p ~/.conan
|
||||
tar -xzf conan.tar -C ~/.conan
|
||||
- name: check environment
|
||||
run: |
|
||||
env | sort
|
||||
echo ${PATH} | tr ':' '\n'
|
||||
conan --version
|
||||
cmake --version
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: dependencies
|
||||
uses: ./.github/actions/dependencies
|
||||
env:
|
||||
CONAN_URL: http://18.143.149.228:8081/artifactory/api/conan/conan-non-prod
|
||||
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: |
|
||||
${build_dir}/rippled --unittest --unittest-jobs $(nproc)
|
||||
|
||||
reference-fee-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
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/rippled-build-ubuntu:aaf5e3e
|
||||
env:
|
||||
build_dir: .build
|
||||
steps:
|
||||
@@ -175,7 +231,7 @@ jobs:
|
||||
- Debug
|
||||
needs: dependencies
|
||||
runs-on: [self-hosted, heavy]
|
||||
container: rippleci/rippled-build-ubuntu:aaf5e3e
|
||||
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
|
||||
env:
|
||||
build_dir: .build
|
||||
steps:
|
||||
@@ -249,7 +305,7 @@ jobs:
|
||||
conan:
|
||||
needs: dependencies
|
||||
runs-on: [self-hosted, heavy]
|
||||
container: rippleci/rippled-build-ubuntu:aaf5e3e
|
||||
container: ghcr.io/xrplf/rippled-build-ubuntu:aaf5e3e
|
||||
env:
|
||||
build_dir: .build
|
||||
configuration: Release
|
||||
@@ -288,7 +344,7 @@ jobs:
|
||||
echo "reference=${reference}" >> "${GITHUB_ENV}"
|
||||
- name: build
|
||||
run: |
|
||||
cd examples/example
|
||||
cd tests/conan
|
||||
mkdir ${build_dir}
|
||||
cd ${build_dir}
|
||||
conan install .. --output-folder . \
|
||||
@@ -304,6 +360,7 @@ jobs:
|
||||
# later
|
||||
|
||||
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:
|
||||
|
||||
2
.github/workflows/windows.yml
vendored
2
.github/workflows/windows.yml
vendored
@@ -2,6 +2,7 @@ name: windows
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review]
|
||||
push:
|
||||
# If the branches list is ever changed, be sure to change it on all
|
||||
# build/test jobs (nix, macos, windows, instrumentation)
|
||||
@@ -21,6 +22,7 @@ concurrency:
|
||||
jobs:
|
||||
|
||||
test:
|
||||
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
|
||||
@@ -83,9 +83,17 @@ The [commandline](https://xrpl.org/docs/references/http-websocket-apis/api-conve
|
||||
|
||||
The `network_id` field was added in the `server_info` response in version 1.5.0 (2019), but it is not returned in [reporting mode](https://xrpl.org/rippled-server-modes.html#reporting-mode). However, use of reporting mode is now discouraged, in favor of using [Clio](https://github.com/XRPLF/clio) instead.
|
||||
|
||||
## XRP Ledger server version 2.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
|
||||
|
||||
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).
|
||||
[Version 2.4.0](https://github.com/XRPLF/rippled/releases/tag/2.4.0) was released on March 4, 2025.
|
||||
|
||||
### Additions and bugfixes in 2.4.0
|
||||
|
||||
|
||||
@@ -16,6 +16,18 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
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
|
||||
find_package(Git)
|
||||
if(Git_FOUND)
|
||||
|
||||
@@ -136,6 +136,9 @@ if(xrpld)
|
||||
add_executable(rippled)
|
||||
if(tests)
|
||||
target_compile_definitions(rippled PUBLIC ENABLE_TESTS)
|
||||
target_compile_definitions(rippled PRIVATE
|
||||
UNIT_TEST_REFERENCE_FEE=${UNIT_TEST_REFERENCE_FEE}
|
||||
)
|
||||
endif()
|
||||
target_include_directories(rippled
|
||||
PRIVATE
|
||||
|
||||
@@ -11,6 +11,12 @@ option(assert "Enables asserts, even in release builds" OFF)
|
||||
option(xrpld "Build xrpld" 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. This is the default" ON)
|
||||
if(unity)
|
||||
|
||||
@@ -367,7 +367,7 @@ get(Section const& section,
|
||||
}
|
||||
|
||||
inline std::string
|
||||
get(Section const& section, std::string const& name, const char* defaultValue)
|
||||
get(Section const& section, std::string const& name, char const* defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
|
||||
auto compressed = bf(outCapacity);
|
||||
|
||||
auto compressedSize = LZ4_compress_default(
|
||||
reinterpret_cast<const char*>(in),
|
||||
reinterpret_cast<char const*>(in),
|
||||
reinterpret_cast<char*>(compressed),
|
||||
inSize,
|
||||
outCapacity);
|
||||
@@ -89,7 +89,7 @@ lz4Decompress(
|
||||
Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
|
||||
|
||||
if (LZ4_decompress_safe(
|
||||
reinterpret_cast<const char*>(in),
|
||||
reinterpret_cast<char const*>(in),
|
||||
reinterpret_cast<char*>(decompressed),
|
||||
inSize,
|
||||
decompressedSize) != decompressedSize)
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
constexpr const E&
|
||||
constexpr E const&
|
||||
value() const&
|
||||
{
|
||||
return val_;
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
return std::move(val_);
|
||||
}
|
||||
|
||||
constexpr const E&&
|
||||
constexpr E const&&
|
||||
value() const&&
|
||||
{
|
||||
return std::move(val_);
|
||||
|
||||
515
include/xrpl/basics/IntrusivePointer.h
Normal file
515
include/xrpl/basics/IntrusivePointer.h
Normal file
@@ -0,0 +1,515 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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
|
||||
740
include/xrpl/basics/IntrusivePointer.ipp
Normal file
740
include/xrpl/basics/IntrusivePointer.ipp
Normal file
@@ -0,0 +1,740 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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
|
||||
502
include/xrpl/basics/IntrusiveRefCounts.h
Normal file
502
include/xrpl/basics/IntrusiveRefCounts.h
Normal file
@@ -0,0 +1,502 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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
|
||||
135
include/xrpl/basics/SharedWeakCachePointer.h
Normal file
135
include/xrpl/basics/SharedWeakCachePointer.h
Normal file
@@ -0,0 +1,135 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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
|
||||
192
include/xrpl/basics/SharedWeakCachePointer.ipp
Normal file
192
include/xrpl/basics/SharedWeakCachePointer.ipp
Normal file
@@ -0,0 +1,192 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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
|
||||
@@ -20,7 +20,9 @@
|
||||
#ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
|
||||
#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/SharedWeakCachePointer.ipp>
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/basics/hardened_hash.h>
|
||||
#include <xrpl/beast/clock/abstract_clock.h>
|
||||
@@ -51,6 +53,8 @@ template <
|
||||
class Key,
|
||||
class T,
|
||||
bool IsKeyCache = false,
|
||||
class SharedWeakUnionPointerType = SharedWeakCachePointer<T>,
|
||||
class SharedPointerType = std::shared_ptr<T>,
|
||||
class Hash = hardened_hash<>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Mutex = std::recursive_mutex>
|
||||
@@ -61,6 +65,8 @@ public:
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
using shared_weak_combo_pointer_type = SharedWeakUnionPointerType;
|
||||
using shared_pointer_type = SharedPointerType;
|
||||
|
||||
public:
|
||||
TaggedCache(
|
||||
@@ -70,231 +76,48 @@ public:
|
||||
clock_type& clock,
|
||||
beast::Journal journal,
|
||||
beast::insight::Collector::ptr const& collector =
|
||||
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)
|
||||
{
|
||||
}
|
||||
beast::insight::NullCollector::New());
|
||||
|
||||
public:
|
||||
/** Return the clock associated with the cache. */
|
||||
clock_type&
|
||||
clock()
|
||||
{
|
||||
return m_clock;
|
||||
}
|
||||
clock();
|
||||
|
||||
/** Returns the number of items in the container. */
|
||||
std::size_t
|
||||
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();
|
||||
}
|
||||
size() const;
|
||||
|
||||
int
|
||||
getCacheSize() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache_count;
|
||||
}
|
||||
getCacheSize() const;
|
||||
|
||||
int
|
||||
getTrackSize() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache.size();
|
||||
}
|
||||
getTrackSize() const;
|
||||
|
||||
float
|
||||
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));
|
||||
}
|
||||
getHitRate();
|
||||
|
||||
void
|
||||
clear()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.clear();
|
||||
m_cache_count = 0;
|
||||
}
|
||||
clear();
|
||||
|
||||
void
|
||||
reset()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.clear();
|
||||
m_cache_count = 0;
|
||||
m_hits = 0;
|
||||
m_misses = 0;
|
||||
}
|
||||
reset();
|
||||
|
||||
/** Refresh the last access time on a key if present.
|
||||
@return `true` If the key was found.
|
||||
*/
|
||||
template <class KeyComparable>
|
||||
bool
|
||||
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;
|
||||
}
|
||||
touch_if_exists(KeyComparable const& key);
|
||||
|
||||
using SweptPointersVector = std::pair<
|
||||
std::vector<std::shared_ptr<mapped_type>>,
|
||||
std::vector<std::weak_ptr<mapped_type>>>;
|
||||
using SweptPointersVector = std::vector<SharedWeakUnionPointerType>;
|
||||
|
||||
void
|
||||
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";
|
||||
}
|
||||
sweep();
|
||||
|
||||
bool
|
||||
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;
|
||||
}
|
||||
del(key_type const& key, bool valid);
|
||||
|
||||
public:
|
||||
/** Replace aliased objects with originals.
|
||||
|
||||
Due to concurrency it is possible for two separate objects with
|
||||
@@ -308,100 +131,23 @@ public:
|
||||
|
||||
@return `true` If the key already existed.
|
||||
*/
|
||||
public:
|
||||
template <class R>
|
||||
bool
|
||||
canonicalize(
|
||||
const key_type& key,
|
||||
std::shared_ptr<T>& data,
|
||||
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;
|
||||
}
|
||||
key_type const& key,
|
||||
SharedPointerType& data,
|
||||
R&& replaceCallback);
|
||||
|
||||
bool
|
||||
canonicalize_replace_cache(
|
||||
const key_type& key,
|
||||
std::shared_ptr<T> const& data)
|
||||
{
|
||||
return canonicalize(
|
||||
key,
|
||||
const_cast<std::shared_ptr<T>&>(data),
|
||||
[](std::shared_ptr<T> const&) { return true; });
|
||||
}
|
||||
key_type const& key,
|
||||
SharedPointerType const& data);
|
||||
|
||||
bool
|
||||
canonicalize_replace_client(const key_type& key, std::shared_ptr<T>& data)
|
||||
{
|
||||
return canonicalize(
|
||||
key, data, [](std::shared_ptr<T> const&) { return false; });
|
||||
}
|
||||
canonicalize_replace_client(key_type const& key, SharedPointerType& data);
|
||||
|
||||
std::shared_ptr<T>
|
||||
fetch(const key_type& key)
|
||||
{
|
||||
std::lock_guard<mutex_type> l(m_mutex);
|
||||
auto ret = initialFetch(key, l);
|
||||
if (!ret)
|
||||
++m_misses;
|
||||
return ret;
|
||||
}
|
||||
SharedPointerType
|
||||
fetch(key_type const& key);
|
||||
|
||||
/** Insert the element into the container.
|
||||
If the key already exists, nothing happens.
|
||||
@@ -410,26 +156,11 @@ public:
|
||||
template <class ReturnType = bool>
|
||||
auto
|
||||
insert(key_type const& key, T const& value)
|
||||
-> std::enable_if_t<!IsKeyCache, ReturnType>
|
||||
{
|
||||
auto p = std::make_shared<T>(std::cref(value));
|
||||
return canonicalize_replace_client(key, p);
|
||||
}
|
||||
-> std::enable_if_t<!IsKeyCache, ReturnType>;
|
||||
|
||||
template <class ReturnType = bool>
|
||||
auto
|
||||
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;
|
||||
}
|
||||
insert(key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>;
|
||||
|
||||
// VFALCO NOTE It looks like this returns a copy of the data in
|
||||
// the output parameter 'data'. This could be expensive.
|
||||
@@ -437,50 +168,18 @@ public:
|
||||
// simply return an iterator.
|
||||
//
|
||||
bool
|
||||
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;
|
||||
}
|
||||
retrieve(key_type const& key, T& data);
|
||||
|
||||
mutex_type&
|
||||
peekMutex()
|
||||
{
|
||||
return m_mutex;
|
||||
}
|
||||
peekMutex();
|
||||
|
||||
std::vector<key_type>
|
||||
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;
|
||||
}
|
||||
getKeys() const;
|
||||
|
||||
// CachedSLEs functions.
|
||||
/** Returns the fraction of cache hits. */
|
||||
double
|
||||
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;
|
||||
}
|
||||
rate() const;
|
||||
|
||||
/** Fetch an item from the cache.
|
||||
If the digest was not found, Handler
|
||||
@@ -488,73 +187,16 @@ public:
|
||||
std::shared_ptr<SLE const>(void)
|
||||
*/
|
||||
template <class Handler>
|
||||
std::shared_ptr<T>
|
||||
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;
|
||||
}
|
||||
SharedPointerType
|
||||
fetch(key_type const& digest, Handler const& h);
|
||||
// End CachedSLEs functions.
|
||||
|
||||
private:
|
||||
std::shared_ptr<T>
|
||||
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 {};
|
||||
}
|
||||
SharedPointerType
|
||||
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l);
|
||||
|
||||
void
|
||||
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);
|
||||
}
|
||||
}
|
||||
collect_metrics();
|
||||
|
||||
private:
|
||||
struct Stats
|
||||
@@ -600,36 +242,37 @@ private:
|
||||
class ValueEntry
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<mapped_type> ptr;
|
||||
std::weak_ptr<mapped_type> weak_ptr;
|
||||
shared_weak_combo_pointer_type ptr;
|
||||
clock_type::time_point last_access;
|
||||
|
||||
ValueEntry(
|
||||
clock_type::time_point const& last_access_,
|
||||
std::shared_ptr<mapped_type> const& ptr_)
|
||||
: ptr(ptr_), weak_ptr(ptr_), last_access(last_access_)
|
||||
shared_pointer_type const& ptr_)
|
||||
: ptr(ptr_), last_access(last_access_)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
isWeak() const
|
||||
{
|
||||
return ptr == nullptr;
|
||||
if (!ptr)
|
||||
return true;
|
||||
return ptr.isWeak();
|
||||
}
|
||||
bool
|
||||
isCached() const
|
||||
{
|
||||
return ptr != nullptr;
|
||||
return ptr && ptr.isStrong();
|
||||
}
|
||||
bool
|
||||
isExpired() const
|
||||
{
|
||||
return weak_ptr.expired();
|
||||
return ptr.expired();
|
||||
}
|
||||
std::shared_ptr<mapped_type>
|
||||
SharedPointerType
|
||||
lock()
|
||||
{
|
||||
return weak_ptr.lock();
|
||||
return ptr.lock();
|
||||
}
|
||||
void
|
||||
touch(clock_type::time_point const& now)
|
||||
@@ -658,72 +301,7 @@ private:
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
std::atomic<int>& allRemovals,
|
||||
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;
|
||||
});
|
||||
}
|
||||
std::lock_guard<std::recursive_mutex> const&);
|
||||
|
||||
[[nodiscard]] std::thread
|
||||
sweepHelper(
|
||||
@@ -732,45 +310,7 @@ private:
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
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;
|
||||
});
|
||||
};
|
||||
std::lock_guard<std::recursive_mutex> const&);
|
||||
|
||||
beast::Journal m_journal;
|
||||
clock_type& m_clock;
|
||||
@@ -782,10 +322,10 @@ private:
|
||||
std::string m_name;
|
||||
|
||||
// Desired number of cache entries (0 = ignore)
|
||||
int m_target_size;
|
||||
int const m_target_size;
|
||||
|
||||
// Desired maximum cache age
|
||||
clock_type::duration m_target_age;
|
||||
clock_type::duration const m_target_age;
|
||||
|
||||
// Number of items cached
|
||||
int m_cache_count;
|
||||
|
||||
1029
include/xrpl/basics/TaggedCache.ipp
Normal file
1029
include/xrpl/basics/TaggedCache.ipp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -374,7 +374,7 @@ public:
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator^=(const base_uint& b)
|
||||
operator^=(base_uint const& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] ^= b.data_[i];
|
||||
@@ -383,7 +383,7 @@ public:
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator&=(const base_uint& b)
|
||||
operator&=(base_uint const& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] &= b.data_[i];
|
||||
@@ -392,7 +392,7 @@ public:
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator|=(const base_uint& b)
|
||||
operator|=(base_uint const& b)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] |= b.data_[i];
|
||||
@@ -415,11 +415,11 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
const base_uint
|
||||
base_uint const
|
||||
operator++(int)
|
||||
{
|
||||
// postfix operator
|
||||
const base_uint ret = *this;
|
||||
base_uint const ret = *this;
|
||||
++(*this);
|
||||
|
||||
return ret;
|
||||
@@ -441,11 +441,11 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
const base_uint
|
||||
base_uint const
|
||||
operator--(int)
|
||||
{
|
||||
// postfix operator
|
||||
const base_uint ret = *this;
|
||||
base_uint const ret = *this;
|
||||
--(*this);
|
||||
|
||||
return ret;
|
||||
@@ -466,7 +466,7 @@ public:
|
||||
}
|
||||
|
||||
base_uint&
|
||||
operator+=(const base_uint& b)
|
||||
operator+=(base_uint const& b)
|
||||
{
|
||||
std::uint64_t carry = 0;
|
||||
|
||||
@@ -511,7 +511,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
parseHex(const char* str)
|
||||
parseHex(char const* str)
|
||||
{
|
||||
return parseHex(std::string_view{str});
|
||||
}
|
||||
@@ -632,6 +632,13 @@ to_string(base_uint<Bits, Tag> const& a)
|
||||
return strHex(a.cbegin(), a.cend());
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline std::string
|
||||
to_short_string(base_uint<Bits, Tag> const& a)
|
||||
{
|
||||
return to_string(a).substr(0, 8) + "...";
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& out, base_uint<Bits, Tag> const& u)
|
||||
|
||||
@@ -43,7 +43,7 @@ struct less
|
||||
using result_type = bool;
|
||||
|
||||
constexpr bool
|
||||
operator()(const T& left, const T& right) const
|
||||
operator()(T const& left, T const& right) const
|
||||
{
|
||||
return std::less<T>()(left, right);
|
||||
}
|
||||
@@ -55,7 +55,7 @@ struct equal_to
|
||||
using result_type = bool;
|
||||
|
||||
constexpr bool
|
||||
operator()(const T& left, const T& right) const
|
||||
operator()(T const& left, T const& right) const
|
||||
{
|
||||
return std::equal_to<T>()(left, right);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ template <
|
||||
typename Value,
|
||||
typename Hash,
|
||||
typename Pred = std::equal_to<Key>,
|
||||
typename Alloc = std::allocator<std::pair<const Key, Value>>>
|
||||
typename Alloc = std::allocator<std::pair<Key const, Value>>>
|
||||
class partitioned_unordered_map
|
||||
{
|
||||
std::size_t partitions_;
|
||||
|
||||
@@ -76,13 +76,13 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const tagged_integer& rhs) const noexcept
|
||||
operator<(tagged_integer const& rhs) const noexcept
|
||||
{
|
||||
return m_value < rhs.m_value;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const tagged_integer& rhs) const noexcept
|
||||
operator==(tagged_integer const& rhs) const noexcept
|
||||
{
|
||||
return m_value == rhs.m_value;
|
||||
}
|
||||
@@ -144,14 +144,14 @@ public:
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator<<=(const tagged_integer& rhs) noexcept
|
||||
operator<<=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value <<= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
tagged_integer&
|
||||
operator>>=(const tagged_integer& rhs) noexcept
|
||||
operator>>=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
m_value >>= rhs.m_value;
|
||||
return *this;
|
||||
|
||||
@@ -39,11 +39,16 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
#endif
|
||||
|
||||
#define XRPL_ASSERT ALWAYS_OR_UNREACHABLE
|
||||
#define XRPL_ASSERT_PARTS(cond, function, description, ...) \
|
||||
XRPL_ASSERT(cond, function " : " description)
|
||||
|
||||
// How to use the instrumentation macros:
|
||||
//
|
||||
// * XRPL_ASSERT if cond must be true but the line might not be reached during
|
||||
// fuzzing. Same like `assert` in normal use.
|
||||
// * XRPL_ASSERT_PARTS is for convenience, and works like XRPL_ASSERT, but
|
||||
// splits the message param into "function" and "description", then joins
|
||||
// them with " : " before passing to XRPL_ASSERT.
|
||||
// * ALWAYS if cond must be true _and_ the line must be reached during fuzzing.
|
||||
// Same like `assert` in normal use.
|
||||
// * REACHABLE if the line must be reached during fuzzing
|
||||
|
||||
@@ -37,9 +37,9 @@ class temp_dir
|
||||
|
||||
public:
|
||||
#if !GENERATING_DOCS
|
||||
temp_dir(const temp_dir&) = delete;
|
||||
temp_dir(temp_dir const&) = delete;
|
||||
temp_dir&
|
||||
operator=(const temp_dir&) = delete;
|
||||
operator=(temp_dir const&) = delete;
|
||||
#endif
|
||||
|
||||
/// Construct a temporary directory.
|
||||
|
||||
@@ -39,7 +39,7 @@ class Reader
|
||||
{
|
||||
public:
|
||||
using Char = char;
|
||||
using Location = const Char*;
|
||||
using Location = Char const*;
|
||||
|
||||
/** \brief Constructs a Reader allowing all features
|
||||
* for parsing.
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
* error occurred.
|
||||
*/
|
||||
bool
|
||||
parse(const char* beginDoc, const char* endDoc, Value& root);
|
||||
parse(char const* beginDoc, char const* endDoc, Value& root);
|
||||
|
||||
/// \brief Parse from input stream.
|
||||
/// \see Json::operator>>(std::istream&, Json::Value&).
|
||||
@@ -133,7 +133,7 @@ private:
|
||||
using Errors = std::deque<ErrorInfo>;
|
||||
|
||||
bool
|
||||
expectToken(TokenType type, Token& token, const char* message);
|
||||
expectToken(TokenType type, Token& token, char const* message);
|
||||
bool
|
||||
readToken(Token& token);
|
||||
void
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
#ifndef 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 <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
/** \brief JSON (JavaScript Object Notation).
|
||||
@@ -61,24 +63,24 @@ enum ValueType {
|
||||
class StaticString
|
||||
{
|
||||
public:
|
||||
constexpr explicit StaticString(const char* czstring) : str_(czstring)
|
||||
constexpr explicit StaticString(char const* czstring) : str_(czstring)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr
|
||||
operator const char*() const
|
||||
operator char const*() const
|
||||
{
|
||||
return str_;
|
||||
}
|
||||
|
||||
constexpr const char*
|
||||
constexpr char const*
|
||||
c_str() const
|
||||
{
|
||||
return str_;
|
||||
}
|
||||
|
||||
private:
|
||||
const char* str_;
|
||||
char const* str_;
|
||||
};
|
||||
|
||||
inline bool
|
||||
@@ -156,10 +158,10 @@ public:
|
||||
using Int = Json::Int;
|
||||
using ArrayIndex = UInt;
|
||||
|
||||
static const Value null;
|
||||
static const Int minInt;
|
||||
static const Int maxInt;
|
||||
static const UInt maxUInt;
|
||||
static Value const null;
|
||||
static Int const minInt;
|
||||
static Int const maxInt;
|
||||
static UInt const maxUInt;
|
||||
|
||||
private:
|
||||
class CZString
|
||||
@@ -171,24 +173,24 @@ private:
|
||||
duplicateOnCopy
|
||||
};
|
||||
CZString(int index);
|
||||
CZString(const char* cstr, DuplicationPolicy allocate);
|
||||
CZString(const CZString& other);
|
||||
CZString(char const* cstr, DuplicationPolicy allocate);
|
||||
CZString(CZString const& other);
|
||||
~CZString();
|
||||
CZString&
|
||||
operator=(const CZString& other) = delete;
|
||||
operator=(CZString const& other) = delete;
|
||||
bool
|
||||
operator<(const CZString& other) const;
|
||||
operator<(CZString const& other) const;
|
||||
bool
|
||||
operator==(const CZString& other) const;
|
||||
operator==(CZString const& other) const;
|
||||
int
|
||||
index() const;
|
||||
const char*
|
||||
char const*
|
||||
c_str() const;
|
||||
bool
|
||||
isStaticString() const;
|
||||
|
||||
private:
|
||||
const char* cstr_;
|
||||
char const* cstr_;
|
||||
int index_;
|
||||
};
|
||||
|
||||
@@ -215,7 +217,8 @@ public:
|
||||
Value(Int value);
|
||||
Value(UInt value);
|
||||
Value(double value);
|
||||
Value(const char* value);
|
||||
Value(char const* value);
|
||||
Value(ripple::Number const& value);
|
||||
/** \brief Constructs a value from a static string.
|
||||
|
||||
* Like other value string constructor but do not duplicate the string for
|
||||
@@ -227,10 +230,10 @@ public:
|
||||
* Json::Value aValue( StaticString("some text") );
|
||||
* \endcode
|
||||
*/
|
||||
Value(const StaticString& value);
|
||||
Value(StaticString const& value);
|
||||
Value(std::string const& value);
|
||||
Value(bool value);
|
||||
Value(const Value& other);
|
||||
Value(Value const& other);
|
||||
~Value();
|
||||
|
||||
Value&
|
||||
@@ -247,7 +250,7 @@ public:
|
||||
ValueType
|
||||
type() const;
|
||||
|
||||
const char*
|
||||
char const*
|
||||
asCString() const;
|
||||
/** Returns the unquoted string value. */
|
||||
std::string
|
||||
@@ -317,12 +320,12 @@ public:
|
||||
/// Access an array element (zero based index )
|
||||
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
||||
/// this from the operator[] which takes a string.)
|
||||
const Value&
|
||||
Value const&
|
||||
operator[](UInt index) const;
|
||||
/// If the array contains at least index+1 elements, returns the element
|
||||
/// value, otherwise returns defaultValue.
|
||||
Value
|
||||
get(UInt index, const Value& defaultValue) const;
|
||||
get(UInt index, Value const& defaultValue) const;
|
||||
/// Return true if index < size().
|
||||
bool
|
||||
isValidIndex(UInt index) const;
|
||||
@@ -330,25 +333,25 @@ public:
|
||||
///
|
||||
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
|
||||
Value&
|
||||
append(const Value& value);
|
||||
append(Value const& value);
|
||||
Value&
|
||||
append(Value&& value);
|
||||
|
||||
/// Access an object value by name, create a null member if it does not
|
||||
/// exist.
|
||||
Value&
|
||||
operator[](const char* key);
|
||||
operator[](char const* key);
|
||||
/// Access an object value by name, returns null if there is no member with
|
||||
/// that name.
|
||||
const Value&
|
||||
operator[](const char* key) const;
|
||||
Value const&
|
||||
operator[](char const* key) const;
|
||||
/// Access an object value by name, create a null member if it does not
|
||||
/// exist.
|
||||
Value&
|
||||
operator[](std::string const& key);
|
||||
/// Access an object value by name, returns null if there is no member with
|
||||
/// that name.
|
||||
const Value&
|
||||
Value const&
|
||||
operator[](std::string const& key) const;
|
||||
/** \brief Access an object value by name, create a null member if it does
|
||||
not exist.
|
||||
@@ -364,14 +367,16 @@ public:
|
||||
* \endcode
|
||||
*/
|
||||
Value&
|
||||
operator[](const StaticString& key);
|
||||
operator[](StaticString const& key);
|
||||
Value const&
|
||||
operator[](StaticString const& key) const;
|
||||
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
Value
|
||||
get(const char* key, const Value& defaultValue) const;
|
||||
get(char const* key, Value const& defaultValue) const;
|
||||
/// Return the member named key if it exist, defaultValue otherwise.
|
||||
Value
|
||||
get(std::string const& key, const Value& defaultValue) const;
|
||||
get(std::string const& key, Value const& defaultValue) const;
|
||||
|
||||
/// \brief Remove and return the named member.
|
||||
///
|
||||
@@ -380,14 +385,14 @@ public:
|
||||
/// \pre type() is objectValue or nullValue
|
||||
/// \post type() is unchanged
|
||||
Value
|
||||
removeMember(const char* key);
|
||||
removeMember(char const* key);
|
||||
/// Same as removeMember(const char*)
|
||||
Value
|
||||
removeMember(std::string const& key);
|
||||
|
||||
/// Return true if the object has a member named key.
|
||||
bool
|
||||
isMember(const char* key) const;
|
||||
isMember(char const* key) const;
|
||||
/// Return true if the object has a member named key.
|
||||
bool
|
||||
isMember(std::string const& key) const;
|
||||
@@ -414,13 +419,13 @@ public:
|
||||
end();
|
||||
|
||||
friend bool
|
||||
operator==(const Value&, const Value&);
|
||||
operator==(Value const&, Value const&);
|
||||
friend bool
|
||||
operator<(const Value&, const Value&);
|
||||
operator<(Value const&, Value const&);
|
||||
|
||||
private:
|
||||
Value&
|
||||
resolveReference(const char* key, bool isStatic);
|
||||
resolveReference(char const* key, bool isStatic);
|
||||
|
||||
private:
|
||||
union ValueHolder
|
||||
@@ -436,32 +441,38 @@ private:
|
||||
int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
|
||||
};
|
||||
|
||||
inline Value
|
||||
to_json(ripple::Number const& number)
|
||||
{
|
||||
return to_string(number);
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const Value&, const Value&);
|
||||
operator==(Value const&, Value const&);
|
||||
|
||||
inline bool
|
||||
operator!=(const Value& x, const Value& y)
|
||||
operator!=(Value const& x, Value const& y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const Value&, const Value&);
|
||||
operator<(Value const&, Value const&);
|
||||
|
||||
inline bool
|
||||
operator<=(const Value& x, const Value& y)
|
||||
operator<=(Value const& x, Value const& y)
|
||||
{
|
||||
return !(y < x);
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator>(const Value& x, const Value& y)
|
||||
operator>(Value const& x, Value const& y)
|
||||
{
|
||||
return y < x;
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator>=(const Value& x, const Value& y)
|
||||
operator>=(Value const& x, Value const& y)
|
||||
{
|
||||
return !(x < y);
|
||||
}
|
||||
@@ -482,11 +493,11 @@ public:
|
||||
virtual ~ValueAllocator() = default;
|
||||
|
||||
virtual char*
|
||||
makeMemberName(const char* memberName) = 0;
|
||||
makeMemberName(char const* memberName) = 0;
|
||||
virtual void
|
||||
releaseMemberName(char* memberName) = 0;
|
||||
virtual char*
|
||||
duplicateStringValue(const char* value, unsigned int length = unknown) = 0;
|
||||
duplicateStringValue(char const* value, unsigned int length = unknown) = 0;
|
||||
virtual void
|
||||
releaseStringValue(char* value) = 0;
|
||||
};
|
||||
@@ -503,16 +514,16 @@ public:
|
||||
|
||||
ValueIteratorBase();
|
||||
|
||||
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
|
||||
explicit ValueIteratorBase(Value::ObjectValues::iterator const& current);
|
||||
|
||||
bool
|
||||
operator==(const SelfType& other) const
|
||||
operator==(SelfType const& other) const
|
||||
{
|
||||
return isEqual(other);
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const SelfType& other) const
|
||||
operator!=(SelfType const& other) const
|
||||
{
|
||||
return !isEqual(other);
|
||||
}
|
||||
@@ -528,7 +539,7 @@ public:
|
||||
|
||||
/// Return the member name of the referenced Value. "" if it is not an
|
||||
/// objectValue.
|
||||
const char*
|
||||
char const*
|
||||
memberName() const;
|
||||
|
||||
protected:
|
||||
@@ -542,13 +553,13 @@ protected:
|
||||
decrement();
|
||||
|
||||
difference_type
|
||||
computeDistance(const SelfType& other) const;
|
||||
computeDistance(SelfType const& other) const;
|
||||
|
||||
bool
|
||||
isEqual(const SelfType& other) const;
|
||||
isEqual(SelfType const& other) const;
|
||||
|
||||
void
|
||||
copy(const SelfType& other);
|
||||
copy(SelfType const& other);
|
||||
|
||||
private:
|
||||
Value::ObjectValues::iterator current_;
|
||||
@@ -566,8 +577,8 @@ class ValueConstIterator : public ValueIteratorBase
|
||||
public:
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
using reference = const Value&;
|
||||
using pointer = const Value*;
|
||||
using reference = Value const&;
|
||||
using pointer = Value const*;
|
||||
using SelfType = ValueConstIterator;
|
||||
|
||||
ValueConstIterator() = default;
|
||||
@@ -575,11 +586,11 @@ public:
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
*/
|
||||
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
|
||||
explicit ValueConstIterator(Value::ObjectValues::iterator const& current);
|
||||
|
||||
public:
|
||||
SelfType&
|
||||
operator=(const ValueIteratorBase& other);
|
||||
operator=(ValueIteratorBase const& other);
|
||||
|
||||
SelfType
|
||||
operator++(int)
|
||||
@@ -632,17 +643,17 @@ public:
|
||||
using SelfType = ValueIterator;
|
||||
|
||||
ValueIterator() = default;
|
||||
ValueIterator(const ValueConstIterator& other);
|
||||
ValueIterator(const ValueIterator& other);
|
||||
ValueIterator(ValueConstIterator const& other);
|
||||
ValueIterator(ValueIterator const& other);
|
||||
|
||||
private:
|
||||
/*! \internal Use by Value to create an iterator.
|
||||
*/
|
||||
explicit ValueIterator(const Value::ObjectValues::iterator& current);
|
||||
explicit ValueIterator(Value::ObjectValues::iterator const& current);
|
||||
|
||||
public:
|
||||
SelfType&
|
||||
operator=(const SelfType& other);
|
||||
operator=(SelfType const& other);
|
||||
|
||||
SelfType
|
||||
operator++(int)
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
{
|
||||
}
|
||||
virtual std::string
|
||||
write(const Value& root) = 0;
|
||||
write(Value const& root) = 0;
|
||||
};
|
||||
|
||||
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
|
||||
@@ -60,11 +60,11 @@ public:
|
||||
|
||||
public: // overridden from Writer
|
||||
std::string
|
||||
write(const Value& root) override;
|
||||
write(Value const& root) override;
|
||||
|
||||
private:
|
||||
void
|
||||
writeValue(const Value& value);
|
||||
writeValue(Value const& value);
|
||||
|
||||
std::string document_;
|
||||
};
|
||||
@@ -101,15 +101,15 @@ public: // overridden from Writer
|
||||
* JSON document that represents the root value.
|
||||
*/
|
||||
std::string
|
||||
write(const Value& root) override;
|
||||
write(Value const& root) override;
|
||||
|
||||
private:
|
||||
void
|
||||
writeValue(const Value& value);
|
||||
writeValue(Value const& value);
|
||||
void
|
||||
writeArrayValue(const Value& value);
|
||||
writeArrayValue(Value const& value);
|
||||
bool
|
||||
isMultineArray(const Value& value);
|
||||
isMultineArray(Value const& value);
|
||||
void
|
||||
pushValue(std::string const& value);
|
||||
void
|
||||
@@ -168,15 +168,15 @@ public:
|
||||
* return a value.
|
||||
*/
|
||||
void
|
||||
write(std::ostream& out, const Value& root);
|
||||
write(std::ostream& out, Value const& root);
|
||||
|
||||
private:
|
||||
void
|
||||
writeValue(const Value& value);
|
||||
writeValue(Value const& value);
|
||||
void
|
||||
writeArrayValue(const Value& value);
|
||||
writeArrayValue(Value const& value);
|
||||
bool
|
||||
isMultineArray(const Value& value);
|
||||
isMultineArray(Value const& value);
|
||||
void
|
||||
pushValue(std::string const& value);
|
||||
void
|
||||
@@ -207,12 +207,12 @@ valueToString(double value);
|
||||
std::string
|
||||
valueToString(bool value);
|
||||
std::string
|
||||
valueToQuotedString(const char* value);
|
||||
valueToQuotedString(char const* value);
|
||||
|
||||
/// \brief Output using the StyledStreamWriter.
|
||||
/// \see Json::operator>>()
|
||||
std::ostream&
|
||||
operator<<(std::ostream&, const Value& root);
|
||||
operator<<(std::ostream&, Value const& root);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ pretty(Value const&);
|
||||
|
||||
/** Output using the StyledStreamWriter. @see Json::operator>>(). */
|
||||
std::ostream&
|
||||
operator<<(std::ostream&, const Value& root);
|
||||
operator<<(std::ostream&, Value const& root);
|
||||
|
||||
} // namespace Json
|
||||
|
||||
|
||||
@@ -48,14 +48,6 @@ class STObject;
|
||||
class STAmount;
|
||||
class Rules;
|
||||
|
||||
/** Calculate AMM account ID.
|
||||
*/
|
||||
AccountID
|
||||
ammAccountID(
|
||||
std::uint16_t prefix,
|
||||
uint256 const& parentHash,
|
||||
uint256 const& ammID);
|
||||
|
||||
/** Calculate Liquidity Provider Token (LPT) Currency.
|
||||
*/
|
||||
Currency
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#ifndef RIPPLE_PROTOCOL_ASSET_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_ASSET_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
@@ -27,6 +28,7 @@
|
||||
namespace ripple {
|
||||
|
||||
class Asset;
|
||||
class STAmount;
|
||||
|
||||
template <typename TIss>
|
||||
concept ValidIssueType =
|
||||
@@ -92,6 +94,9 @@ public:
|
||||
void
|
||||
setJson(Json::Value& jv) const;
|
||||
|
||||
STAmount
|
||||
operator()(Number const&) const;
|
||||
|
||||
bool
|
||||
native() const
|
||||
{
|
||||
@@ -114,6 +119,14 @@ public:
|
||||
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>
|
||||
constexpr bool
|
||||
Asset::holds() const
|
||||
@@ -219,9 +232,6 @@ validJSONAsset(Json::Value const& jv);
|
||||
Asset
|
||||
assetFromJson(Json::Value const& jv);
|
||||
|
||||
Json::Value
|
||||
to_json(Asset const& asset);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_PROTOCOL_ASSET_H_INCLUDED
|
||||
|
||||
@@ -120,7 +120,7 @@ enum error_code_i {
|
||||
rpcSRC_ACT_MALFORMED = 65,
|
||||
rpcSRC_ACT_MISSING = 66,
|
||||
rpcSRC_ACT_NOT_FOUND = 67,
|
||||
// unused 68,
|
||||
rpcDELEGATE_ACT_NOT_FOUND = 68,
|
||||
rpcSRC_CUR_MALFORMED = 69,
|
||||
rpcSRC_ISR_MALFORMED = 70,
|
||||
rpcSTREAM_MALFORMED = 71,
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
|
||||
@@ -279,6 +279,10 @@ amm(Asset const& issue1, Asset const& issue2) noexcept;
|
||||
Keylet
|
||||
amm(uint256 const& amm) noexcept;
|
||||
|
||||
/** A keylet for Delegate object */
|
||||
Keylet
|
||||
delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept;
|
||||
|
||||
Keylet
|
||||
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType);
|
||||
|
||||
@@ -330,6 +334,33 @@ mptoken(uint256 const& mptokenKey)
|
||||
Keylet
|
||||
mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept;
|
||||
|
||||
Keylet
|
||||
vault(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
vault(uint256 const& vaultKey)
|
||||
{
|
||||
return {ltVAULT, vaultKey};
|
||||
}
|
||||
|
||||
Keylet
|
||||
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
loanbroker(uint256 const& vaultKey)
|
||||
{
|
||||
return {ltLOAN_BROKER, vaultKey};
|
||||
}
|
||||
|
||||
Keylet
|
||||
loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
loan(uint256 const& vaultKey)
|
||||
{
|
||||
return {ltLOAN, vaultKey};
|
||||
}
|
||||
|
||||
Keylet
|
||||
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept;
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ enum LedgerSpecificFlags {
|
||||
lsfNoFreeze = 0x00200000, // True, cannot freeze ripple states
|
||||
lsfGlobalFreeze = 0x00400000, // True, all assets frozen
|
||||
lsfDefaultRipple =
|
||||
0x00800000, // True, trust lines allow rippling by default
|
||||
0x00800000, // True, incoming trust lines allow rippling by default
|
||||
lsfDepositAuth = 0x01000000, // True, all deposits require authorization
|
||||
/* // reserved for Hooks amendment
|
||||
lsfTshCollect = 0x02000000, // True, allow TSH collect-calls to acc hooks
|
||||
@@ -191,6 +191,14 @@ enum LedgerSpecificFlags {
|
||||
|
||||
// ltCREDENTIAL
|
||||
lsfAccepted = 0x00010000,
|
||||
|
||||
// ltVAULT
|
||||
lsfVaultPrivate = 0x00010000,
|
||||
|
||||
// ltLOAN
|
||||
lsfLoanDefault = 0x00010000,
|
||||
lsfLoanImpaired = 0x00020000,
|
||||
lsfLoanOverpayment = 0x00040000, // True, loan allows overpayments
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -24,15 +24,12 @@
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
|
||||
@@ -42,8 +42,11 @@ public:
|
||||
AccountID const&
|
||||
getIssuer() const;
|
||||
|
||||
MPTID const&
|
||||
getMptID() const;
|
||||
constexpr MPTID const&
|
||||
getMptID() const
|
||||
{
|
||||
return mptID_;
|
||||
}
|
||||
|
||||
std::string
|
||||
getText() const;
|
||||
|
||||
@@ -80,7 +80,7 @@ struct MultiApiJson
|
||||
}
|
||||
|
||||
void
|
||||
set(const char* key, auto const& v)
|
||||
set(char const* key, auto const& v)
|
||||
requires std::constructible_from<Json::Value, decltype(v)>
|
||||
{
|
||||
for (auto& a : this->val)
|
||||
@@ -91,7 +91,7 @@ struct MultiApiJson
|
||||
enum IsMemberResult : int { none = 0, some, all };
|
||||
|
||||
[[nodiscard]] IsMemberResult
|
||||
isMember(const char* key) const
|
||||
isMember(char const* key) const
|
||||
{
|
||||
int count = 0;
|
||||
for (auto& a : this->val)
|
||||
|
||||
97
include/xrpl/protocol/Permissions.h
Normal file
97
include/xrpl/protocol/Permissions.h
Normal file
@@ -0,0 +1,97 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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>
|
||||
#include <unordered_set>
|
||||
|
||||
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
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/partitioned_unordered_map.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -82,6 +84,90 @@ std::size_t constexpr maxDeletableTokenOfferEntries = 500;
|
||||
*/
|
||||
std::uint16_t constexpr maxTransferFee = 50000;
|
||||
|
||||
/** There are 10,000 basis points (bips) in 100%.
|
||||
*
|
||||
* Basis points represent 0.01%.
|
||||
*
|
||||
* Given a value X, to find the amount for B bps,
|
||||
* use X * B / bipsPerUnity
|
||||
*
|
||||
* Example: If a loan broker has 999 XRP of debt, and must maintain 1,000 bps of
|
||||
* that debt as cover (10%), then the minimum cover amount is 999,000,000 drops
|
||||
* * 1000 / bipsPerUnity = 99,900,00 drops or 99.9 XRP.
|
||||
*
|
||||
* Given a percentage P, to find the number of bps that percentage represents,
|
||||
* use P * bipsPerUnity.
|
||||
*
|
||||
* Example: 50% is 0.50 * bipsPerUnity = 5,000 bps.
|
||||
*/
|
||||
Bips32 constexpr bipsPerUnity(100 * 100);
|
||||
TenthBips32 constexpr tenthBipsPerUnity(bipsPerUnity.value() * 10);
|
||||
|
||||
constexpr Bips32
|
||||
percentageToBips(std::uint32_t percentage)
|
||||
{
|
||||
return Bips32(percentage * bipsPerUnity.value() / 100);
|
||||
}
|
||||
constexpr TenthBips32
|
||||
percentageToTenthBips(std::uint32_t percentage)
|
||||
{
|
||||
return TenthBips32(percentage * tenthBipsPerUnity.value() / 100);
|
||||
}
|
||||
template <typename T, class TBips>
|
||||
constexpr T
|
||||
bipsOfValue(T value, Bips<TBips> bips)
|
||||
{
|
||||
return value * bips.value() / bipsPerUnity.value();
|
||||
}
|
||||
template <typename T, class TBips>
|
||||
constexpr T
|
||||
tenthBipsOfValue(T value, TenthBips<TBips> bips)
|
||||
{
|
||||
return value * bips.value() / tenthBipsPerUnity.value();
|
||||
}
|
||||
|
||||
/** The maximum management fee rate allowed by a loan broker in 1/10 bips.
|
||||
|
||||
Valid values are between 0 and 10% inclusive.
|
||||
*/
|
||||
TenthBips16 constexpr maxManagementFeeRate(
|
||||
unsafe_cast<std::uint16_t>(percentageToTenthBips(10).value()));
|
||||
static_assert(maxManagementFeeRate == TenthBips16(std::uint16_t(10'000u)));
|
||||
|
||||
/** The maximum coverage rate required of a loan broker in 1/10 bips.
|
||||
|
||||
Valid values are between 0 and 100% inclusive.
|
||||
*/
|
||||
TenthBips32 constexpr maxCoverRate = percentageToTenthBips(100);
|
||||
static_assert(maxCoverRate == TenthBips32(100'000u));
|
||||
|
||||
/** The maximum overpayment fee on a loan in 1/10 bips.
|
||||
*
|
||||
Valid values are between 0 and 100% inclusive.
|
||||
*/
|
||||
TenthBips32 constexpr maxOverpaymentFee = percentageToTenthBips(100);
|
||||
|
||||
/** The maximum premium added to the interest rate for late payments on a loan
|
||||
* in 1/10 bips.
|
||||
*
|
||||
* Valid values are between 0 and 100% inclusive.
|
||||
*/
|
||||
TenthBips32 constexpr maxLateInterestRate = percentageToTenthBips(100);
|
||||
|
||||
/** The maximum close interest rate charged for repaying a loan early in 1/10
|
||||
* bips.
|
||||
*
|
||||
* Valid values are between 0 and 100% inclusive.
|
||||
*/
|
||||
TenthBips32 constexpr maxCloseInterestRate = percentageToTenthBips(100);
|
||||
|
||||
/** The maximum overpayment interest rate charged on loan overpayments in 1/10
|
||||
* bips.
|
||||
*
|
||||
* Valid values are between 0 and 100% inclusive.
|
||||
*/
|
||||
TenthBips32 constexpr maxOverpaymentInterestRate = percentageToTenthBips(100);
|
||||
|
||||
/** The maximum length of a URI inside an NFT */
|
||||
std::size_t constexpr maxTokenURILength = 256;
|
||||
|
||||
@@ -116,6 +202,16 @@ std::size_t constexpr maxMPTokenMetadataLength = 1024;
|
||||
/** The maximum amount of MPTokenIssuance */
|
||||
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. */
|
||||
using LedgerIndex = std::uint32_t;
|
||||
|
||||
@@ -155,6 +251,10 @@ std::size_t constexpr maxPriceScale = 20;
|
||||
*/
|
||||
std::size_t constexpr maxTrim = 25;
|
||||
|
||||
/** The maximum number of delegate permissions an account can grant
|
||||
*/
|
||||
std::size_t constexpr permissionMaxSize = 10;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -113,8 +113,8 @@ public:
|
||||
// have lower unsigned integer representations.
|
||||
using value_type = std::uint64_t;
|
||||
|
||||
static const int minTickSize = 3;
|
||||
static const int maxTickSize = 16;
|
||||
static int const minTickSize = 3;
|
||||
static int const maxTickSize = 16;
|
||||
|
||||
private:
|
||||
// This has the same representation as STAmount, see the comment on the
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -54,6 +54,9 @@ class STXChainBridge;
|
||||
class STVector256;
|
||||
class STCurrency;
|
||||
|
||||
template <class Integer>
|
||||
concept HasValue = requires(Integer i) { i.value(); };
|
||||
|
||||
#pragma push_macro("XMACRO")
|
||||
#undef XMACRO
|
||||
|
||||
@@ -136,9 +139,9 @@ field_code(int id, int index)
|
||||
the binary format of the transaction can be canonicalized. All
|
||||
SFields are created at compile time.
|
||||
|
||||
Each SField, once constructed, lives until program termination, and there
|
||||
is only one instance per fieldType/fieldValue pair which serves the entire
|
||||
application.
|
||||
Each SField, once constructed, lives until program termination, and
|
||||
there is only one instance per fieldType/fieldValue pair which serves the
|
||||
entire application.
|
||||
*/
|
||||
class SField
|
||||
{
|
||||
@@ -149,8 +152,11 @@ public:
|
||||
sMD_ChangeNew = 0x02, // new value when it changes
|
||||
sMD_DeleteFinal = 0x04, // final value when it is deleted
|
||||
sMD_Create = 0x08, // value when it's created
|
||||
sMD_Always = 0x10, // value when node containing it is affected at all
|
||||
sMD_BaseTen = 0x20,
|
||||
sMD_Always = 0x10, // value when node containing it is affected at all
|
||||
sMD_BaseTen = 0x20, // value is treated as base 10, overriding
|
||||
// default behavior
|
||||
sMD_PseudoAccount = 0x40, // if this field is set in an ACCOUNT_ROOT
|
||||
// _only_, then it is a pseudo-account
|
||||
sMD_Default =
|
||||
sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create
|
||||
};
|
||||
@@ -175,29 +181,30 @@ public:
|
||||
operator=(SField&&) = delete;
|
||||
|
||||
public:
|
||||
struct private_access_tag_t; // public, but still an implementation detail
|
||||
struct private_access_tag_t; // public, but still an implementation
|
||||
// detail
|
||||
|
||||
// These constructors can only be called from SField.cpp
|
||||
SField(
|
||||
private_access_tag_t,
|
||||
SerializedTypeID tid,
|
||||
int fv,
|
||||
const char* fn,
|
||||
char const* fn,
|
||||
int meta = sMD_Default,
|
||||
IsSigning signing = IsSigning::yes);
|
||||
explicit SField(private_access_tag_t, int fc);
|
||||
|
||||
static const SField&
|
||||
static SField const&
|
||||
getField(int fieldCode);
|
||||
static const SField&
|
||||
static SField const&
|
||||
getField(std::string const& fieldName);
|
||||
static const SField&
|
||||
static SField const&
|
||||
getField(int type, int value)
|
||||
{
|
||||
return getField(field_code(type, value));
|
||||
}
|
||||
|
||||
static const SField&
|
||||
static SField const&
|
||||
getField(SerializedTypeID type, int value)
|
||||
{
|
||||
return getField(field_code(type, value));
|
||||
@@ -284,19 +291,19 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const SField& f) const
|
||||
operator==(SField const& f) const
|
||||
{
|
||||
return fieldCode == f.fieldCode;
|
||||
}
|
||||
|
||||
bool
|
||||
operator!=(const SField& f) const
|
||||
operator!=(SField const& f) const
|
||||
{
|
||||
return fieldCode != f.fieldCode;
|
||||
}
|
||||
|
||||
static int
|
||||
compare(const SField& f1, const SField& f2);
|
||||
compare(SField const& f1, SField const& f2);
|
||||
|
||||
static std::map<int, SField const*> const&
|
||||
getKnownCodeToField()
|
||||
@@ -307,6 +314,7 @@ public:
|
||||
private:
|
||||
static int num;
|
||||
static std::map<int, SField const*> knownCodeToField;
|
||||
static std::map<std::string, SField const*> knownNameToField;
|
||||
};
|
||||
|
||||
/** A field with a type known at compile time. */
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
add(Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
@@ -62,20 +62,20 @@ private:
|
||||
public:
|
||||
using value_type = STAmount;
|
||||
|
||||
static const int cMinOffset = -96;
|
||||
static const int cMaxOffset = 80;
|
||||
static int const cMinOffset = -96;
|
||||
static int const cMaxOffset = 80;
|
||||
|
||||
// Maximum native value supported by the code
|
||||
static const std::uint64_t cMinValue = 1000000000000000ull;
|
||||
static const std::uint64_t cMaxValue = 9999999999999999ull;
|
||||
static const std::uint64_t cMaxNative = 9000000000000000000ull;
|
||||
static std::uint64_t const cMinValue = 1000000000000000ull;
|
||||
static std::uint64_t const cMaxValue = 9999999999999999ull;
|
||||
static std::uint64_t const cMaxNative = 9000000000000000000ull;
|
||||
|
||||
// Max native value on network.
|
||||
static const std::uint64_t cMaxNativeN = 100000000000000000ull;
|
||||
static const std::uint64_t cIssuedCurrency = 0x8000000000000000ull;
|
||||
static const std::uint64_t cPositive = 0x4000000000000000ull;
|
||||
static const std::uint64_t cMPToken = 0x2000000000000000ull;
|
||||
static const std::uint64_t cValueMask = ~(cPositive | cMPToken);
|
||||
static std::uint64_t const cMaxNativeN = 100000000000000000ull;
|
||||
static std::uint64_t const cIssuedCurrency = 0x8000000000000000ull;
|
||||
static std::uint64_t const cPositive = 0x4000000000000000ull;
|
||||
static std::uint64_t const cMPToken = 0x2000000000000000ull;
|
||||
static std::uint64_t const cValueMask = ~(cPositive | cMPToken);
|
||||
|
||||
static std::uint64_t const uRateOne;
|
||||
|
||||
@@ -153,6 +153,12 @@ public:
|
||||
template <AssetType A>
|
||||
STAmount(A const& asset, int mantissa, int exponent = 0);
|
||||
|
||||
template <AssetType A>
|
||||
STAmount(A const& asset, Number const& number)
|
||||
: STAmount(asset, number.mantissa(), number.exponent())
|
||||
{
|
||||
}
|
||||
|
||||
// Legacy support for new-style amounts
|
||||
STAmount(IOUAmount const& amount, Issue const& issue);
|
||||
STAmount(XRPAmount const& amount);
|
||||
@@ -230,6 +236,9 @@ public:
|
||||
STAmount&
|
||||
operator=(XRPAmount const& amount);
|
||||
|
||||
STAmount&
|
||||
operator=(Number const&);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Modification
|
||||
@@ -268,13 +277,13 @@ public:
|
||||
std::string
|
||||
getText() const override;
|
||||
|
||||
Json::Value getJson(JsonOptions) const override;
|
||||
Json::Value getJson(JsonOptions = JsonOptions::none) const override;
|
||||
|
||||
void
|
||||
add(Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
@@ -417,7 +426,7 @@ STAmount
|
||||
amountFromQuality(std::uint64_t rate);
|
||||
|
||||
STAmount
|
||||
amountFromString(Asset const& issue, std::string const& amount);
|
||||
amountFromString(Asset const& asset, std::string const& amount);
|
||||
|
||||
STAmount
|
||||
amountFromJson(SField const& name, Json::Value const& v);
|
||||
@@ -541,6 +550,16 @@ STAmount::operator=(XRPAmount const& amount)
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline STAmount&
|
||||
STAmount::operator=(Number const& number)
|
||||
{
|
||||
mIsNegative = number.mantissa() < 0;
|
||||
mValue = mIsNegative ? -number.mantissa() : number.mantissa();
|
||||
mOffset = number.exponent();
|
||||
canonicalize();
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void
|
||||
STAmount::negate()
|
||||
{
|
||||
@@ -676,6 +695,36 @@ divRoundStrict(
|
||||
std::uint64_t
|
||||
getRate(STAmount const& offerOut, STAmount const& offerIn);
|
||||
|
||||
STAmount
|
||||
roundToReference(
|
||||
STAmount const value,
|
||||
STAmount referenceValue,
|
||||
Number::rounding_mode rounding = Number::getround());
|
||||
|
||||
/** Round an arbitrary precision Number to the precision of a given Asset.
|
||||
*
|
||||
* @param asset The relevant asset
|
||||
* @param value The value to be rounded
|
||||
* @param referenceValue Only relevant to IOU assets. A reference value to
|
||||
* establish the precision limit of `value`. Should be larger than
|
||||
* `value`.
|
||||
* @param rounding Optional Number rounding mode
|
||||
*/
|
||||
template <AssetType A>
|
||||
Number
|
||||
roundToAsset(
|
||||
A const& asset,
|
||||
Number const& value,
|
||||
Number const& referenceValue,
|
||||
Number::rounding_mode rounding = Number::getround())
|
||||
{
|
||||
NumberRoundModeGuard mg(rounding);
|
||||
STAmount const ret{asset, value};
|
||||
if (ret.asset().native() || !ret.asset().holds<Issue>())
|
||||
return ret;
|
||||
return roundToReference(ret, STAmount{asset, referenceValue});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline bool
|
||||
@@ -684,10 +733,10 @@ isXRP(STAmount const& amount)
|
||||
return amount.native();
|
||||
}
|
||||
|
||||
// Since `canonicalize` does not have access to a ledger, this is needed to put
|
||||
// the low-level routine stAmountCanonicalize on an amendment switch. Only
|
||||
// transactions need to use this switchover. Outside of a transaction it's safe
|
||||
// to unconditionally use the new behavior.
|
||||
// Since `canonicalize` does not have access to a ledger, this is needed to
|
||||
// put the low-level routine stAmountCanonicalize on an amendment switch.
|
||||
// Only transactions need to use this switchover. Outside of a transaction
|
||||
// it's safe to unconditionally use the new behavior.
|
||||
|
||||
bool
|
||||
getSTAmountCanonicalizeSwitchover();
|
||||
|
||||
@@ -128,13 +128,13 @@ public:
|
||||
add(Serializer& s) const override;
|
||||
|
||||
void
|
||||
sort(bool (*compare)(const STObject& o1, const STObject& o2));
|
||||
sort(bool (*compare)(STObject const& o1, STObject const& o2));
|
||||
|
||||
bool
|
||||
operator==(const STArray& s) const;
|
||||
operator==(STArray const& s) const;
|
||||
|
||||
bool
|
||||
operator!=(const STArray& s) const;
|
||||
operator!=(STArray const& s) const;
|
||||
|
||||
iterator
|
||||
erase(iterator pos);
|
||||
@@ -152,7 +152,7 @@ public:
|
||||
getSType() const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
@@ -275,13 +275,13 @@ STArray::swap(STArray& a) noexcept
|
||||
}
|
||||
|
||||
inline bool
|
||||
STArray::operator==(const STArray& s) const
|
||||
STArray::operator==(STArray const& s) const
|
||||
{
|
||||
return v_ == s.v_;
|
||||
}
|
||||
|
||||
inline bool
|
||||
STArray::operator!=(const STArray& s) const
|
||||
STArray::operator!=(STArray const& s) const
|
||||
{
|
||||
return v_ != s.v_;
|
||||
}
|
||||
|
||||
@@ -92,6 +92,16 @@ struct JsonOptions
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
requires requires(T const& t) {
|
||||
{ t.getJson(JsonOptions::none) } -> std::convertible_to<Json::Value>;
|
||||
}
|
||||
Json::Value
|
||||
to_json(T const& t)
|
||||
{
|
||||
return t.getJson(JsonOptions::none);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
class STVar;
|
||||
}
|
||||
@@ -129,16 +139,16 @@ class STBase
|
||||
public:
|
||||
virtual ~STBase() = default;
|
||||
STBase();
|
||||
STBase(const STBase&) = default;
|
||||
STBase(STBase const&) = default;
|
||||
STBase&
|
||||
operator=(const STBase& t);
|
||||
operator=(STBase const& t);
|
||||
|
||||
explicit STBase(SField const& n);
|
||||
|
||||
bool
|
||||
operator==(const STBase& t) const;
|
||||
operator==(STBase const& t) const;
|
||||
bool
|
||||
operator!=(const STBase& t) const;
|
||||
operator!=(STBase const& t) const;
|
||||
|
||||
template <class D>
|
||||
D&
|
||||
@@ -157,7 +167,7 @@ public:
|
||||
virtual std::string
|
||||
getText() const;
|
||||
|
||||
virtual Json::Value getJson(JsonOptions /*options*/) const;
|
||||
virtual Json::Value getJson(JsonOptions = JsonOptions::none) const;
|
||||
|
||||
virtual void
|
||||
add(Serializer& s) const;
|
||||
@@ -197,7 +207,7 @@ private:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& out, const STBase& t);
|
||||
operator<<(std::ostream& out, STBase const& t);
|
||||
|
||||
template <class D>
|
||||
D&
|
||||
|
||||
@@ -45,8 +45,8 @@ public:
|
||||
STBitString() = default;
|
||||
|
||||
STBitString(SField const& n);
|
||||
STBitString(const value_type& v);
|
||||
STBitString(SField const& n, const value_type& v);
|
||||
STBitString(value_type const& v);
|
||||
STBitString(SField const& n, value_type const& v);
|
||||
STBitString(SerialIter& sit, SField const& name);
|
||||
|
||||
SerializedTypeID
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
getText() const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
void
|
||||
add(Serializer& s) const override;
|
||||
@@ -93,12 +93,12 @@ inline STBitString<Bits>::STBitString(SField const& n) : STBase(n)
|
||||
}
|
||||
|
||||
template <int Bits>
|
||||
inline STBitString<Bits>::STBitString(const value_type& v) : value_(v)
|
||||
inline STBitString<Bits>::STBitString(value_type const& v) : value_(v)
|
||||
{
|
||||
}
|
||||
|
||||
template <int Bits>
|
||||
inline STBitString<Bits>::STBitString(SField const& n, const value_type& v)
|
||||
inline STBitString<Bits>::STBitString(SField const& n, value_type const& v)
|
||||
: STBase(n), value_(v)
|
||||
{
|
||||
}
|
||||
@@ -160,9 +160,9 @@ STBitString<Bits>::getText() const
|
||||
|
||||
template <int Bits>
|
||||
bool
|
||||
STBitString<Bits>::isEquivalent(const STBase& t) const
|
||||
STBitString<Bits>::isEquivalent(STBase const& t) const
|
||||
{
|
||||
const STBitString* v = dynamic_cast<const STBitString*>(&t);
|
||||
STBitString const* v = dynamic_cast<STBitString const*>(&t);
|
||||
return v && (value_ == v->value_);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
add(Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
add(Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define RIPPLE_PROTOCOL_STINTEGER_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -36,7 +37,7 @@ private:
|
||||
|
||||
public:
|
||||
explicit STInteger(Integer v);
|
||||
STInteger(SField const& n, Integer v = 0);
|
||||
STInteger(SField const& n, Integer v = {});
|
||||
STInteger(SerialIter& sit, SField const& name);
|
||||
|
||||
SerializedTypeID
|
||||
@@ -54,7 +55,7 @@ public:
|
||||
isDefault() const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
STInteger&
|
||||
operator=(value_type const& v);
|
||||
@@ -122,14 +123,14 @@ template <typename Integer>
|
||||
inline bool
|
||||
STInteger<Integer>::isDefault() const
|
||||
{
|
||||
return value_ == 0;
|
||||
return value_ == Integer{};
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
inline bool
|
||||
STInteger<Integer>::isEquivalent(const STBase& t) const
|
||||
STInteger<Integer>::isEquivalent(STBase const& t) const
|
||||
{
|
||||
const STInteger* v = dynamic_cast<const STInteger*>(&t);
|
||||
STInteger const* v = dynamic_cast<STInteger const*>(&t);
|
||||
return v && (value_ == v->value_);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
using value_type = Asset;
|
||||
|
||||
STIssue() = default;
|
||||
STIssue(STIssue const& rhs) = default;
|
||||
|
||||
explicit STIssue(SerialIter& sit, SField const& name);
|
||||
|
||||
@@ -45,6 +46,15 @@ public:
|
||||
|
||||
explicit STIssue(SField const& name);
|
||||
|
||||
STIssue&
|
||||
operator=(STIssue const& rhs) = default;
|
||||
STIssue&
|
||||
operator=(Asset const& rhs)
|
||||
{
|
||||
asset_ = rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <ValidIssueType TIss>
|
||||
TIss const&
|
||||
get() const;
|
||||
@@ -71,7 +81,7 @@ public:
|
||||
add(Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
namespace ripple {
|
||||
|
||||
class Rules;
|
||||
namespace test {
|
||||
class Invariants_test;
|
||||
}
|
||||
|
||||
class STLedgerEntry final : public STObject, public CountedObject<STLedgerEntry>
|
||||
{
|
||||
@@ -35,7 +37,9 @@ class STLedgerEntry final : public STObject, public CountedObject<STLedgerEntry>
|
||||
|
||||
public:
|
||||
using pointer = std::shared_ptr<STLedgerEntry>;
|
||||
using ref = const std::shared_ptr<STLedgerEntry>&;
|
||||
using ref = std::shared_ptr<STLedgerEntry> const&;
|
||||
using const_pointer = std::shared_ptr<STLedgerEntry const>;
|
||||
using const_ref = std::shared_ptr<STLedgerEntry const> const&;
|
||||
|
||||
/** Create an empty object with the given key and type. */
|
||||
explicit STLedgerEntry(Keylet const& k);
|
||||
@@ -54,7 +58,7 @@ public:
|
||||
getText() const override;
|
||||
|
||||
Json::Value
|
||||
getJson(JsonOptions options) const override;
|
||||
getJson(JsonOptions options = JsonOptions::none) const override;
|
||||
|
||||
/** Returns the 'key' (or 'index') of this item.
|
||||
The key identifies this entry's position in
|
||||
@@ -84,7 +88,8 @@ private:
|
||||
void
|
||||
setSLEType();
|
||||
|
||||
friend Invariants_test; // this test wants access to the private type_
|
||||
friend test::Invariants_test; // this test wants access to the private
|
||||
// type_
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
|
||||
@@ -63,6 +63,13 @@ public:
|
||||
void
|
||||
setValue(Number const& v);
|
||||
|
||||
STNumber&
|
||||
operator=(Number const& rhs)
|
||||
{
|
||||
setValue(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
isEquivalent(STBase const& t) const override;
|
||||
bool
|
||||
@@ -83,6 +90,19 @@ private:
|
||||
std::ostream&
|
||||
operator<<(std::ostream& out, STNumber const& rhs);
|
||||
|
||||
struct NumberParts
|
||||
{
|
||||
std::uint64_t mantissa = 0;
|
||||
int exponent = 0;
|
||||
bool negative = false;
|
||||
};
|
||||
|
||||
NumberParts
|
||||
partsFromString(std::string const& number);
|
||||
|
||||
STNumber
|
||||
numberFromJson(SField const& field, Json::Value const& value);
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/FeeUnits.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/SOTemplate.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
@@ -34,6 +33,7 @@
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
#include <xrpl/protocol/detail/STVar.h>
|
||||
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
@@ -99,8 +99,8 @@ public:
|
||||
STObject&
|
||||
operator=(STObject&& other);
|
||||
|
||||
STObject(const SOTemplate& type, SField const& name);
|
||||
STObject(const SOTemplate& type, SerialIter& sit, SField const& name);
|
||||
STObject(SOTemplate const& type, SField const& name);
|
||||
STObject(SOTemplate const& type, SerialIter& sit, SField const& name);
|
||||
STObject(SerialIter& sit, SField const& name, int depth = 0);
|
||||
STObject(SerialIter&& sit, SField const& name);
|
||||
explicit STObject(SField const& name);
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
reserve(std::size_t n);
|
||||
|
||||
void
|
||||
applyTemplate(const SOTemplate& type);
|
||||
applyTemplate(SOTemplate const& type);
|
||||
|
||||
void
|
||||
applyTemplateFromSField(SField const&);
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
isFree() const;
|
||||
|
||||
void
|
||||
set(const SOTemplate&);
|
||||
set(SOTemplate const&);
|
||||
|
||||
bool
|
||||
set(SerialIter& u, int depth = 0);
|
||||
@@ -139,7 +139,7 @@ public:
|
||||
getSType() const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
@@ -154,8 +154,7 @@ public:
|
||||
getText() const override;
|
||||
|
||||
// TODO(tom): options should be an enum.
|
||||
Json::Value
|
||||
getJson(JsonOptions options) const override;
|
||||
Json::Value getJson(JsonOptions = JsonOptions::none) const override;
|
||||
|
||||
void
|
||||
addWithoutSigningFields(Serializer& s) const;
|
||||
@@ -183,13 +182,13 @@ public:
|
||||
uint256
|
||||
getSigningHash(HashPrefix prefix) const;
|
||||
|
||||
const STBase&
|
||||
STBase const&
|
||||
peekAtIndex(int offset) const;
|
||||
|
||||
STBase&
|
||||
getIndex(int offset);
|
||||
|
||||
const STBase*
|
||||
STBase const*
|
||||
peekAtPIndex(int offset) const;
|
||||
|
||||
STBase*
|
||||
@@ -201,13 +200,13 @@ public:
|
||||
SField const&
|
||||
getFieldSType(int index) const;
|
||||
|
||||
const STBase&
|
||||
STBase const&
|
||||
peekAtField(SField const& field) const;
|
||||
|
||||
STBase&
|
||||
getField(SField const& field);
|
||||
|
||||
const STBase*
|
||||
STBase const*
|
||||
peekAtPField(SField const& field) const;
|
||||
|
||||
STBase*
|
||||
@@ -241,11 +240,14 @@ public:
|
||||
getFieldAmount(SField const& field) const;
|
||||
STPathSet const&
|
||||
getFieldPathSet(SField const& field) const;
|
||||
const STVector256&
|
||||
STVector256 const&
|
||||
getFieldV256(SField const& field) const;
|
||||
const STArray&
|
||||
// If not found, returns an object constructed with the given field
|
||||
STObject
|
||||
getFieldObject(SField const& field) const;
|
||||
STArray const&
|
||||
getFieldArray(SField const& field) const;
|
||||
const STCurrency&
|
||||
STCurrency const&
|
||||
getFieldCurrency(SField const& field) const;
|
||||
STNumber const&
|
||||
getFieldNumber(SField const& field) const;
|
||||
@@ -409,12 +411,12 @@ public:
|
||||
delField(int index);
|
||||
|
||||
bool
|
||||
hasMatchingEntry(const STBase&);
|
||||
hasMatchingEntry(STBase const&);
|
||||
|
||||
bool
|
||||
operator==(const STObject& o) const;
|
||||
operator==(STObject const& o) const;
|
||||
bool
|
||||
operator!=(const STObject& o) const;
|
||||
operator!=(STObject const& o) const;
|
||||
|
||||
class FieldErr;
|
||||
|
||||
@@ -484,9 +486,19 @@ private:
|
||||
template <class T>
|
||||
class STObject::Proxy
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
using value_type = typename T::value_type;
|
||||
|
||||
value_type
|
||||
value() const;
|
||||
|
||||
value_type
|
||||
operator*() const;
|
||||
|
||||
T const*
|
||||
operator->() const;
|
||||
|
||||
protected:
|
||||
STObject* st_;
|
||||
SOEStyle style_;
|
||||
TypedField<T> const* f_;
|
||||
@@ -495,9 +507,6 @@ protected:
|
||||
|
||||
Proxy(STObject* st, TypedField<T> const* f);
|
||||
|
||||
value_type
|
||||
value() const;
|
||||
|
||||
T const*
|
||||
find() const;
|
||||
|
||||
@@ -509,10 +518,29 @@ protected:
|
||||
// Constraint += and -= ValueProxy operators
|
||||
// to value types that support arithmetic operations
|
||||
template <typename U>
|
||||
concept IsArithmetic = std::is_arithmetic_v<U> || std::is_same_v<U, STAmount>;
|
||||
concept IsArithmeticNumber = std::is_arithmetic_v<U> ||
|
||||
std::is_same_v<U, Number> || std::is_same_v<U, STAmount>;
|
||||
template <
|
||||
typename U,
|
||||
typename Value = typename U::value_type,
|
||||
typename Unit = typename U::unit_type>
|
||||
concept IsArithmeticValueUnit =
|
||||
std::is_same_v<U, unit::ValueUnit<Unit, Value>> &&
|
||||
IsArithmeticNumber<Value> && std::is_class_v<Unit>;
|
||||
template <typename U, typename Value = typename U::value_type>
|
||||
concept IsArithmeticST = !IsArithmeticValueUnit<U> && IsArithmeticNumber<Value>;
|
||||
template <typename U>
|
||||
concept IsArithmetic =
|
||||
IsArithmeticNumber<U> || IsArithmeticST<U> || IsArithmeticValueUnit<U>;
|
||||
|
||||
template <class T, class U>
|
||||
concept Addable = requires(T t, U u) { t = t + u; };
|
||||
template <typename T, typename U>
|
||||
concept IsArithmeticCompatible =
|
||||
IsArithmetic<typename T::value_type> && Addable<typename T::value_type, U>;
|
||||
|
||||
template <class T>
|
||||
class STObject::ValueProxy : private Proxy<T>
|
||||
class STObject::ValueProxy : public Proxy<T>
|
||||
{
|
||||
private:
|
||||
using value_type = typename T::value_type;
|
||||
@@ -529,15 +557,24 @@ public:
|
||||
// Convenience operators for value types supporting
|
||||
// arithmetic operations
|
||||
template <IsArithmetic U>
|
||||
requires IsArithmeticCompatible<T, U>
|
||||
ValueProxy&
|
||||
operator+=(U const& u);
|
||||
|
||||
template <IsArithmetic U>
|
||||
requires IsArithmeticCompatible<T, U>
|
||||
ValueProxy&
|
||||
operator-=(U const& u);
|
||||
|
||||
operator value_type() const;
|
||||
|
||||
template <typename U>
|
||||
friend bool
|
||||
operator==(U const& lhs, STObject::ValueProxy<T> const& rhs)
|
||||
{
|
||||
return rhs.value() == lhs;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class STObject;
|
||||
|
||||
@@ -545,7 +582,7 @@ private:
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class STObject::OptionalProxy : private Proxy<T>
|
||||
class STObject::OptionalProxy : public Proxy<T>
|
||||
{
|
||||
private:
|
||||
using value_type = typename T::value_type;
|
||||
@@ -565,15 +602,6 @@ public:
|
||||
explicit
|
||||
operator bool() const noexcept;
|
||||
|
||||
/** Return the contained value
|
||||
|
||||
Throws:
|
||||
|
||||
STObject::FieldErr if !engaged()
|
||||
*/
|
||||
value_type
|
||||
operator*() const;
|
||||
|
||||
operator optional_type() const;
|
||||
|
||||
/** Explicit conversion to std::optional */
|
||||
@@ -717,6 +745,20 @@ STObject::Proxy<T>::value() const -> value_type
|
||||
return value_type{};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto
|
||||
STObject::Proxy<T>::operator*() const -> value_type
|
||||
{
|
||||
return this->value();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T const*
|
||||
STObject::Proxy<T>::operator->() const
|
||||
{
|
||||
return this->find();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T const*
|
||||
STObject::Proxy<T>::find() const
|
||||
@@ -756,6 +798,7 @@ STObject::ValueProxy<T>::operator=(U&& u)
|
||||
|
||||
template <typename T>
|
||||
template <IsArithmetic U>
|
||||
requires IsArithmeticCompatible<T, U>
|
||||
STObject::ValueProxy<T>&
|
||||
STObject::ValueProxy<T>::operator+=(U const& u)
|
||||
{
|
||||
@@ -765,6 +808,7 @@ STObject::ValueProxy<T>::operator+=(U const& u)
|
||||
|
||||
template <class T>
|
||||
template <IsArithmetic U>
|
||||
requires IsArithmeticCompatible<T, U>
|
||||
STObject::ValueProxy<T>&
|
||||
STObject::ValueProxy<T>::operator-=(U const& u)
|
||||
{
|
||||
@@ -792,13 +836,6 @@ STObject::OptionalProxy<T>::operator bool() const noexcept
|
||||
return engaged();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
auto
|
||||
STObject::OptionalProxy<T>::operator*() const -> value_type
|
||||
{
|
||||
return this->value();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
STObject::OptionalProxy<T>::operator typename STObject::OptionalProxy<
|
||||
T>::optional_type() const
|
||||
@@ -970,7 +1007,7 @@ STObject::getCount() const
|
||||
return v_.size();
|
||||
}
|
||||
|
||||
inline const STBase&
|
||||
inline STBase const&
|
||||
STObject::peekAtIndex(int offset) const
|
||||
{
|
||||
return v_[offset].get();
|
||||
@@ -982,7 +1019,7 @@ STObject::getIndex(int offset)
|
||||
return v_[offset].get();
|
||||
}
|
||||
|
||||
inline const STBase*
|
||||
inline STBase const*
|
||||
STObject::peekAtPIndex(int offset) const
|
||||
{
|
||||
return &v_[offset].get();
|
||||
@@ -1117,7 +1154,7 @@ STObject::setFieldH160(SField const& field, base_uint<160, Tag> const& v)
|
||||
}
|
||||
|
||||
inline bool
|
||||
STObject::operator!=(const STObject& o) const
|
||||
STObject::operator!=(STObject const& o) const
|
||||
{
|
||||
return !(*this == o);
|
||||
}
|
||||
@@ -1126,7 +1163,7 @@ template <typename T, typename V>
|
||||
V
|
||||
STObject::getFieldByValue(SField const& field) const
|
||||
{
|
||||
const STBase* rf = peekAtPField(field);
|
||||
STBase const* rf = peekAtPField(field);
|
||||
|
||||
if (!rf)
|
||||
throwFieldNotFound(field);
|
||||
@@ -1136,7 +1173,7 @@ STObject::getFieldByValue(SField const& field) const
|
||||
if (id == STI_NOTPRESENT)
|
||||
return V(); // optional field not present
|
||||
|
||||
const T* cf = dynamic_cast<const T*>(rf);
|
||||
T const* cf = dynamic_cast<T const*>(rf);
|
||||
|
||||
if (!cf)
|
||||
Throw<std::runtime_error>("Wrong field type");
|
||||
@@ -1153,7 +1190,7 @@ template <typename T, typename V>
|
||||
V const&
|
||||
STObject::getFieldByConstRef(SField const& field, V const& empty) const
|
||||
{
|
||||
const STBase* rf = peekAtPField(field);
|
||||
STBase const* rf = peekAtPField(field);
|
||||
|
||||
if (!rf)
|
||||
throwFieldNotFound(field);
|
||||
@@ -1163,7 +1200,7 @@ STObject::getFieldByConstRef(SField const& field, V const& empty) const
|
||||
if (id == STI_NOTPRESENT)
|
||||
return empty; // optional field not present
|
||||
|
||||
const T* cf = dynamic_cast<const T*>(rf);
|
||||
T const* cf = dynamic_cast<T const*>(rf);
|
||||
|
||||
if (!cf)
|
||||
Throw<std::runtime_error>("Wrong field type");
|
||||
|
||||
@@ -106,10 +106,10 @@ public:
|
||||
getIssuerID() const;
|
||||
|
||||
bool
|
||||
operator==(const STPathElement& t) const;
|
||||
operator==(STPathElement const& t) const;
|
||||
|
||||
bool
|
||||
operator!=(const STPathElement& t) const;
|
||||
operator!=(STPathElement const& t) const;
|
||||
|
||||
private:
|
||||
static std::size_t
|
||||
@@ -164,7 +164,7 @@ public:
|
||||
STPathElement&
|
||||
operator[](int i);
|
||||
|
||||
const STPathElement&
|
||||
STPathElement const&
|
||||
operator[](int i) const;
|
||||
|
||||
void
|
||||
@@ -196,7 +196,7 @@ public:
|
||||
assembleAdd(STPath const& base, STPathElement const& tail);
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
@@ -375,7 +375,7 @@ STPathElement::getIssuerID() const
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::operator==(const STPathElement& t) const
|
||||
STPathElement::operator==(STPathElement const& t) const
|
||||
{
|
||||
return (mType & typeAccount) == (t.mType & typeAccount) &&
|
||||
hash_value_ == t.hash_value_ && mAccountID == t.mAccountID &&
|
||||
@@ -383,7 +383,7 @@ STPathElement::operator==(const STPathElement& t) const
|
||||
}
|
||||
|
||||
inline bool
|
||||
STPathElement::operator!=(const STPathElement& t) const
|
||||
STPathElement::operator!=(STPathElement const& t) const
|
||||
{
|
||||
return !operator==(t);
|
||||
}
|
||||
@@ -455,7 +455,7 @@ STPath::operator[](int i)
|
||||
return mPath[i];
|
||||
}
|
||||
|
||||
inline const STPathElement&
|
||||
inline STPathElement const&
|
||||
STPath::operator[](int i) const
|
||||
{
|
||||
return mPath[i];
|
||||
|
||||
@@ -88,7 +88,13 @@ public:
|
||||
|
||||
// Outer transaction functions / signature functions.
|
||||
Blob
|
||||
getSignature() const;
|
||||
getSignature(STObject const& sigObject) const;
|
||||
|
||||
Blob
|
||||
getSignature() const
|
||||
{
|
||||
return getSignature(*this);
|
||||
}
|
||||
|
||||
uint256
|
||||
getSigningHash() const;
|
||||
@@ -102,6 +108,10 @@ public:
|
||||
SeqProxy
|
||||
getSeqProxy() const;
|
||||
|
||||
/** Returns the first non-zero value of (Sequence, TicketSequence). */
|
||||
std::uint32_t
|
||||
getSeqValue() const;
|
||||
|
||||
boost::container::flat_set<AccountID>
|
||||
getMentionedAccounts() const;
|
||||
|
||||
@@ -117,10 +127,28 @@ public:
|
||||
void
|
||||
sign(PublicKey const& publicKey, SecretKey const& secretKey);
|
||||
|
||||
enum class RequireFullyCanonicalSig : bool { no, yes };
|
||||
|
||||
/** Check the signature.
|
||||
@param requireCanonicalSig If `true`, check that the signature is fully
|
||||
canonical. If `false`, only check that the signature is valid.
|
||||
@param rules The current ledger rules.
|
||||
@param pSig Pointer to object that contains the signature fields, if not
|
||||
using "this". Will most often be null
|
||||
@return `true` if valid signature. If invalid, the error message string.
|
||||
*/
|
||||
Expected<void, std::string>
|
||||
checkSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules,
|
||||
STObject const* pSig) const;
|
||||
|
||||
/** Check the signature.
|
||||
@param requireCanonicalSig If `true`, check that the signature is fully
|
||||
canonical. If `false`, only check that the signature is valid.
|
||||
@param rules The current ledger rules.
|
||||
@return `true` if valid signature. If invalid, the error message string.
|
||||
*/
|
||||
enum class RequireFullyCanonicalSig : bool { no, yes };
|
||||
Expected<void, std::string>
|
||||
checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const& rules)
|
||||
const;
|
||||
@@ -142,12 +170,15 @@ public:
|
||||
|
||||
private:
|
||||
Expected<void, std::string>
|
||||
checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig) const;
|
||||
checkSingleSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
STObject const* pSig) const;
|
||||
|
||||
Expected<void, std::string>
|
||||
checkMultiSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules) const;
|
||||
Rules const& rules,
|
||||
STObject const* pSig) const;
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/FeeUnits.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
Json::Value getJson(JsonOptions) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
operator=(std::vector<uint256>&& v);
|
||||
|
||||
void
|
||||
setValue(const STVector256& v);
|
||||
setValue(STVector256 const& v);
|
||||
|
||||
/** Retrieve a copy of the vector we contain */
|
||||
explicit
|
||||
@@ -153,7 +153,7 @@ STVector256::operator=(std::vector<uint256>&& v)
|
||||
}
|
||||
|
||||
inline void
|
||||
STVector256::setValue(const STVector256& v)
|
||||
STVector256::setValue(STVector256 const& v)
|
||||
{
|
||||
mValue = v.mValue;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
add(Serializer& s) const override;
|
||||
|
||||
bool
|
||||
isEquivalent(const STBase& t) const override;
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
bool
|
||||
isDefault() const override;
|
||||
|
||||
@@ -125,8 +125,17 @@ public:
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
requires(!HasValue<Integer>)
|
||||
int addInteger(Integer);
|
||||
|
||||
template <typename Integer>
|
||||
requires HasValue<Integer>
|
||||
int
|
||||
addInteger(Integer i)
|
||||
{
|
||||
return addInteger(i.value());
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
int
|
||||
addBitString(base_uint<Bits, Tag> const& v)
|
||||
@@ -139,9 +148,9 @@ public:
|
||||
int
|
||||
addRaw(Slice slice);
|
||||
int
|
||||
addRaw(const void* ptr, int len);
|
||||
addRaw(void const* ptr, int len);
|
||||
int
|
||||
addRaw(const Serializer& s);
|
||||
addRaw(Serializer const& s);
|
||||
|
||||
int
|
||||
addVL(Blob const& vector);
|
||||
@@ -151,7 +160,7 @@ public:
|
||||
int
|
||||
addVL(Iter begin, Iter end, int len);
|
||||
int
|
||||
addVL(const void* ptr, int len);
|
||||
addVL(void const* ptr, int len);
|
||||
|
||||
// disassemble functions
|
||||
bool
|
||||
@@ -161,7 +170,7 @@ public:
|
||||
bool
|
||||
getInteger(Integer& number, int offset)
|
||||
{
|
||||
static const auto bytes = sizeof(Integer);
|
||||
static auto const bytes = sizeof(Integer);
|
||||
if ((offset + bytes) > mData.size())
|
||||
return false;
|
||||
number = 0;
|
||||
@@ -220,7 +229,7 @@ public:
|
||||
{
|
||||
return mData.size();
|
||||
}
|
||||
const void*
|
||||
void const*
|
||||
getDataPtr() const
|
||||
{
|
||||
return mData.data();
|
||||
@@ -238,7 +247,7 @@ public:
|
||||
std::string
|
||||
getString() const
|
||||
{
|
||||
return std::string(static_cast<const char*>(getDataPtr()), size());
|
||||
return std::string(static_cast<char const*>(getDataPtr()), size());
|
||||
}
|
||||
void
|
||||
erase()
|
||||
@@ -296,12 +305,12 @@ public:
|
||||
return v != mData;
|
||||
}
|
||||
bool
|
||||
operator==(const Serializer& v) const
|
||||
operator==(Serializer const& v) const
|
||||
{
|
||||
return v.mData == mData;
|
||||
}
|
||||
bool
|
||||
operator!=(const Serializer& v) const
|
||||
operator!=(Serializer const& v) const
|
||||
{
|
||||
return v.mData != mData;
|
||||
}
|
||||
|
||||
@@ -225,6 +225,8 @@ enum TERcodes : TERUnderlyingType {
|
||||
terQUEUED, // Transaction is being held in TxQ until fee drops
|
||||
terPRE_TICKET, // Ticket is not yet in ledger but might be on its way
|
||||
terNO_AMM, // AMM doesn't exist for the asset pair
|
||||
terADDRESS_COLLISION, // Failed to allocate AccountID when trying to
|
||||
// create a pseudo-account
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -265,6 +267,17 @@ enum TECcodes : TERUnderlyingType {
|
||||
// Otherwise, treated as terRETRY.
|
||||
//
|
||||
// DO NOT CHANGE THESE NUMBERS: They appear in ledger meta data.
|
||||
//
|
||||
// Note:
|
||||
// tecNO_ENTRY is often used interchangeably with tecOBJECT_NOT_FOUND.
|
||||
// While there does not seem to be a clear rule which to use when, the
|
||||
// following guidance will help to keep errors consistent with the
|
||||
// majority of (but not all) transaction types:
|
||||
// - tecNO_ENTRY : cannot find the primary ledger object on which the
|
||||
// transaction is being attempted
|
||||
// - tecOBJECT_NOT_FOUND : cannot find the additional object(s) needed to
|
||||
// complete the transaction
|
||||
|
||||
tecCLAIM = 100,
|
||||
tecPATH_PARTIAL = 101,
|
||||
tecUNFUNDED_ADD = 102, // Unused legacy code
|
||||
@@ -344,6 +357,9 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecARRAY_TOO_LARGE = 191,
|
||||
tecLOCKED = 192,
|
||||
tecBAD_CREDENTIALS = 193,
|
||||
tecWRONG_ASSET = 194,
|
||||
tecLIMIT_EXCEEDED = 195,
|
||||
tecPSEUDO_ACCOUNT = 196,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -120,9 +120,18 @@ constexpr std::uint32_t tfTrustSetMask =
|
||||
~(tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple | tfSetFreeze |
|
||||
tfClearFreeze | tfSetDeepFreeze | tfClearDeepFreeze);
|
||||
|
||||
// valid flags for granular permission
|
||||
constexpr std::uint32_t tfTrustSetGranularMask = tfSetfAuth | tfSetFreeze | tfClearFreeze;
|
||||
|
||||
// bits representing supportedGranularMask are set to 0 and the bits
|
||||
// representing other flags are set to 1 in tfPermissionMask.
|
||||
constexpr std::uint32_t tfTrustSetPermissionMask = (~tfTrustSetMask) & (~tfTrustSetGranularMask);
|
||||
|
||||
// EnableAmendment flags:
|
||||
constexpr std::uint32_t tfGotMajority = 0x00010000;
|
||||
constexpr std::uint32_t tfLostMajority = 0x00020000;
|
||||
constexpr std::uint32_t tfChangeMask =
|
||||
~( tfUniversal | tfGotMajority | tfLostMajority);
|
||||
|
||||
// PaymentChannelClaim flags:
|
||||
constexpr std::uint32_t tfRenew = 0x00010000;
|
||||
@@ -137,7 +146,7 @@ constexpr std::uint32_t const tfTransferable = 0x00000008;
|
||||
constexpr std::uint32_t const tfMutable = 0x00000010;
|
||||
|
||||
// MPTokenIssuanceCreate flags:
|
||||
// NOTE - there is intentionally no flag here for lsfMPTLocked, which this transaction cannot mutate.
|
||||
// NOTE - there is intentionally no flag here for lsfMPTLocked, which this transaction cannot mutate.
|
||||
constexpr std::uint32_t const tfMPTCanLock = lsfMPTCanLock;
|
||||
constexpr std::uint32_t const tfMPTRequireAuth = lsfMPTRequireAuth;
|
||||
constexpr std::uint32_t const tfMPTCanEscrow = lsfMPTCanEscrow;
|
||||
@@ -155,6 +164,8 @@ constexpr std::uint32_t const tfMPTokenAuthorizeMask = ~(tfUniversal | tfMPTUna
|
||||
constexpr std::uint32_t const tfMPTLock = 0x00000001;
|
||||
constexpr std::uint32_t const tfMPTUnlock = 0x00000002;
|
||||
constexpr std::uint32_t const tfMPTokenIssuanceSetMask = ~(tfUniversal | tfMPTLock | tfMPTUnlock);
|
||||
constexpr std::uint32_t const tfMPTokenIssuanceSetGranularMask = tfMPTLock | tfMPTUnlock;
|
||||
constexpr std::uint32_t const tfMPTokenIssuanceSetPermissionMask = (~tfMPTokenIssuanceSetMask) & (~tfMPTokenIssuanceSetGranularMask);
|
||||
|
||||
// MPTokenIssuanceDestroy flags:
|
||||
constexpr std::uint32_t const tfMPTokenIssuanceDestroyMask = ~tfUniversal;
|
||||
@@ -224,6 +235,24 @@ constexpr std::uint32_t tfAMMClawbackMask = ~(tfUniversal | tfClawTwoAssets);
|
||||
// BridgeModify flags:
|
||||
constexpr std::uint32_t tfClearAccountCreateAmount = 0x00010000;
|
||||
constexpr std::uint32_t tfBridgeModifyMask = ~(tfUniversal | tfClearAccountCreateAmount);
|
||||
|
||||
// VaultCreate flags:
|
||||
constexpr std::uint32_t const tfVaultPrivate = 0x00010000;
|
||||
static_assert(tfVaultPrivate == lsfVaultPrivate);
|
||||
constexpr std::uint32_t const tfVaultShareNonTransferable = 0x00020000;
|
||||
constexpr std::uint32_t const tfVaultCreateMask = ~(tfUniversal | tfVaultPrivate | tfVaultShareNonTransferable);
|
||||
|
||||
// LoanSet flags:
|
||||
// True, indicates the loan supports overpayments
|
||||
constexpr std::uint32_t const tfLoanOverpayment = 0x00010000;
|
||||
constexpr std::uint32_t const tfLoanSetMask = ~(tfUniversal | tfLoanOverpayment);
|
||||
|
||||
// LoanManage flags:
|
||||
constexpr std::uint32_t const tfLoanDefault = 0x00010000;
|
||||
constexpr std::uint32_t const tfLoanImpair = 0x00020000;
|
||||
constexpr std::uint32_t const tfLoanUnimpair = 0x00040000;
|
||||
constexpr std::uint32_t const tfLoanManageMask = ~(tfUniversal | tfLoanDefault | tfLoanImpair | tfLoanUnimpair);
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -59,7 +59,8 @@ enum TxType : std::uint16_t
|
||||
#pragma push_macro("TRANSACTION")
|
||||
#undef TRANSACTION
|
||||
|
||||
#define TRANSACTION(tag, value, name, fields) tag = value,
|
||||
#define TRANSACTION(tag, value, ...) \
|
||||
tag = value,
|
||||
|
||||
#include <xrpl/protocol/detail/transactions.macro>
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BASICS_FEES_H_INCLUDED
|
||||
#define BASICS_FEES_H_INCLUDED
|
||||
#ifndef PROTOCOL_UNITS_H_INCLUDED
|
||||
#define PROTOCOL_UNITS_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
@@ -38,23 +38,23 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace feeunit {
|
||||
namespace unit {
|
||||
|
||||
/** "drops" are the smallest divisible amount of XRP. This is what most
|
||||
of the code uses. */
|
||||
struct dropTag;
|
||||
/** "fee units" calculations are a not-really-unitless value that is used
|
||||
to express the cost of a given transaction vs. a reference transaction.
|
||||
They are primarily used by the Transactor classes. */
|
||||
struct feeunitTag;
|
||||
/** "fee levels" are used by the transaction queue to compare the relative
|
||||
cost of transactions that require different levels of effort to process.
|
||||
See also: src/ripple/app/misc/FeeEscalation.md#fee-level */
|
||||
struct feelevelTag;
|
||||
/** unitless values are plain scalars wrapped in a TaggedFee. They are
|
||||
/** unitless values are plain scalars wrapped in a ValueUnit. They are
|
||||
used for calculations in this header. */
|
||||
struct unitlessTag;
|
||||
|
||||
/** Units to represent basis points (bips) and 1/10 basis points */
|
||||
class BipsTag;
|
||||
class TenthBipsTag;
|
||||
|
||||
template <class T>
|
||||
using enable_if_unit_t = typename std::enable_if_t<
|
||||
std::is_class_v<T> && std::is_object_v<typename T::unit_type> &&
|
||||
@@ -62,32 +62,33 @@ using enable_if_unit_t = typename std::enable_if_t<
|
||||
|
||||
/** `is_usable_unit_v` is checked to ensure that only values with
|
||||
known valid type tags can be used (sometimes transparently) in
|
||||
non-fee contexts. At the time of implementation, this includes
|
||||
non-unit contexts. At the time of implementation, this includes
|
||||
all known tags, but more may be added in the future, and they
|
||||
should not be added automatically unless determined to be
|
||||
appropriate.
|
||||
*/
|
||||
template <class T, class = enable_if_unit_t<T>>
|
||||
constexpr bool is_usable_unit_v =
|
||||
std::is_same_v<typename T::unit_type, feeunitTag> ||
|
||||
std::is_same_v<typename T::unit_type, feelevelTag> ||
|
||||
std::is_same_v<typename T::unit_type, unitlessTag> ||
|
||||
std::is_same_v<typename T::unit_type, dropTag>;
|
||||
std::is_same_v<typename T::unit_type, dropTag> ||
|
||||
std::is_same_v<typename T::unit_type, BipsTag> ||
|
||||
std::is_same_v<typename T::unit_type, TenthBipsTag>;
|
||||
|
||||
template <class UnitTag, class T>
|
||||
class TaggedFee : private boost::totally_ordered<TaggedFee<UnitTag, T>>,
|
||||
private boost::additive<TaggedFee<UnitTag, T>>,
|
||||
private boost::equality_comparable<TaggedFee<UnitTag, T>, T>,
|
||||
private boost::dividable<TaggedFee<UnitTag, T>, T>,
|
||||
private boost::modable<TaggedFee<UnitTag, T>, T>,
|
||||
private boost::unit_steppable<TaggedFee<UnitTag, T>>
|
||||
class ValueUnit : private boost::totally_ordered<ValueUnit<UnitTag, T>>,
|
||||
private boost::additive<ValueUnit<UnitTag, T>>,
|
||||
private boost::equality_comparable<ValueUnit<UnitTag, T>, T>,
|
||||
private boost::dividable<ValueUnit<UnitTag, T>, T>,
|
||||
private boost::modable<ValueUnit<UnitTag, T>, T>,
|
||||
private boost::unit_steppable<ValueUnit<UnitTag, T>>
|
||||
{
|
||||
public:
|
||||
using unit_type = UnitTag;
|
||||
using value_type = T;
|
||||
|
||||
private:
|
||||
value_type fee_;
|
||||
value_type value_;
|
||||
|
||||
protected:
|
||||
template <class Other>
|
||||
@@ -95,44 +96,44 @@ protected:
|
||||
std::is_arithmetic_v<Other> && std::is_arithmetic_v<value_type> &&
|
||||
std::is_convertible_v<Other, value_type>;
|
||||
|
||||
template <class OtherFee, class = enable_if_unit_t<OtherFee>>
|
||||
static constexpr bool is_compatiblefee_v =
|
||||
is_compatible_v<typename OtherFee::value_type> &&
|
||||
std::is_same_v<UnitTag, typename OtherFee::unit_type>;
|
||||
template <class OtherValue, class = enable_if_unit_t<OtherValue>>
|
||||
static constexpr bool is_compatiblevalue_v =
|
||||
is_compatible_v<typename OtherValue::value_type> &&
|
||||
std::is_same_v<UnitTag, typename OtherValue::unit_type>;
|
||||
|
||||
template <class Other>
|
||||
using enable_if_compatible_t =
|
||||
typename std::enable_if_t<is_compatible_v<Other>>;
|
||||
|
||||
template <class OtherFee>
|
||||
using enable_if_compatiblefee_t =
|
||||
typename std::enable_if_t<is_compatiblefee_v<OtherFee>>;
|
||||
template <class OtherValue>
|
||||
using enable_if_compatiblevalue_t =
|
||||
typename std::enable_if_t<is_compatiblevalue_v<OtherValue>>;
|
||||
|
||||
public:
|
||||
TaggedFee() = default;
|
||||
constexpr TaggedFee(TaggedFee const& other) = default;
|
||||
constexpr TaggedFee&
|
||||
operator=(TaggedFee const& other) = default;
|
||||
ValueUnit() = default;
|
||||
constexpr ValueUnit(ValueUnit const& other) = default;
|
||||
constexpr ValueUnit&
|
||||
operator=(ValueUnit const& other) = default;
|
||||
|
||||
constexpr explicit TaggedFee(beast::Zero) : fee_(0)
|
||||
constexpr explicit ValueUnit(beast::Zero) : value_(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr TaggedFee&
|
||||
constexpr ValueUnit&
|
||||
operator=(beast::Zero)
|
||||
{
|
||||
fee_ = 0;
|
||||
value_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr explicit TaggedFee(value_type fee) : fee_(fee)
|
||||
constexpr explicit ValueUnit(value_type value) : value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator=(value_type fee)
|
||||
constexpr ValueUnit&
|
||||
operator=(value_type value)
|
||||
{
|
||||
fee_ = fee;
|
||||
value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -144,153 +145,181 @@ public:
|
||||
class = std::enable_if_t<
|
||||
is_compatible_v<Other> &&
|
||||
is_safetocasttovalue_v<value_type, Other>>>
|
||||
constexpr TaggedFee(TaggedFee<unit_type, Other> const& fee)
|
||||
: TaggedFee(safe_cast<value_type>(fee.fee()))
|
||||
constexpr ValueUnit(ValueUnit<unit_type, Other> const& value)
|
||||
: ValueUnit(safe_cast<value_type>(value.value()))
|
||||
{
|
||||
}
|
||||
|
||||
constexpr TaggedFee
|
||||
constexpr ValueUnit
|
||||
operator+(value_type const& rhs) const
|
||||
{
|
||||
return ValueUnit{value_ + rhs};
|
||||
}
|
||||
|
||||
friend constexpr ValueUnit
|
||||
operator+(value_type lhs, ValueUnit const& rhs)
|
||||
{
|
||||
// addition is commutative
|
||||
return rhs + lhs;
|
||||
}
|
||||
|
||||
constexpr ValueUnit
|
||||
operator-(value_type const& rhs) const
|
||||
{
|
||||
return ValueUnit{value_ - rhs};
|
||||
}
|
||||
|
||||
friend constexpr ValueUnit
|
||||
operator-(value_type lhs, ValueUnit const& rhs)
|
||||
{
|
||||
// subtraction is NOT commutative, but (lhs + (-rhs)) is addition, which
|
||||
// is
|
||||
return -rhs + lhs;
|
||||
}
|
||||
|
||||
constexpr ValueUnit
|
||||
operator*(value_type const& rhs) const
|
||||
{
|
||||
return TaggedFee{fee_ * rhs};
|
||||
return ValueUnit{value_ * rhs};
|
||||
}
|
||||
|
||||
friend constexpr TaggedFee
|
||||
operator*(value_type lhs, TaggedFee const& rhs)
|
||||
friend constexpr ValueUnit
|
||||
operator*(value_type lhs, ValueUnit const& rhs)
|
||||
{
|
||||
// multiplication is commutative
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
constexpr value_type
|
||||
operator/(TaggedFee const& rhs) const
|
||||
operator/(ValueUnit const& rhs) const
|
||||
{
|
||||
return fee_ / rhs.fee_;
|
||||
return value_ / rhs.value_;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator+=(TaggedFee const& other)
|
||||
ValueUnit&
|
||||
operator+=(ValueUnit const& other)
|
||||
{
|
||||
fee_ += other.fee();
|
||||
value_ += other.value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator-=(TaggedFee const& other)
|
||||
ValueUnit&
|
||||
operator-=(ValueUnit const& other)
|
||||
{
|
||||
fee_ -= other.fee();
|
||||
value_ -= other.value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
ValueUnit&
|
||||
operator++()
|
||||
{
|
||||
++fee_;
|
||||
++value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
ValueUnit&
|
||||
operator--()
|
||||
{
|
||||
--fee_;
|
||||
--value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
ValueUnit&
|
||||
operator*=(value_type const& rhs)
|
||||
{
|
||||
fee_ *= rhs;
|
||||
value_ *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
ValueUnit&
|
||||
operator/=(value_type const& rhs)
|
||||
{
|
||||
fee_ /= rhs;
|
||||
value_ /= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class transparent = value_type>
|
||||
std::enable_if_t<std::is_integral_v<transparent>, TaggedFee&>
|
||||
std::enable_if_t<std::is_integral_v<transparent>, ValueUnit&>
|
||||
operator%=(value_type const& rhs)
|
||||
{
|
||||
fee_ %= rhs;
|
||||
value_ %= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee
|
||||
ValueUnit
|
||||
operator-() const
|
||||
{
|
||||
static_assert(
|
||||
std::is_signed_v<T>, "- operator illegal on unsigned fee types");
|
||||
return TaggedFee{-fee_};
|
||||
std::is_signed_v<T>, "- operator illegal on unsigned value types");
|
||||
return ValueUnit{-value_};
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(TaggedFee const& other) const
|
||||
constexpr bool
|
||||
operator==(ValueUnit const& other) const
|
||||
{
|
||||
return fee_ == other.fee_;
|
||||
return value_ == other.value_;
|
||||
}
|
||||
|
||||
template <class Other, class = enable_if_compatible_t<Other>>
|
||||
bool
|
||||
operator==(TaggedFee<unit_type, Other> const& other) const
|
||||
constexpr bool
|
||||
operator==(ValueUnit<unit_type, Other> const& other) const
|
||||
{
|
||||
return fee_ == other.fee();
|
||||
return value_ == other.value();
|
||||
}
|
||||
|
||||
bool
|
||||
constexpr bool
|
||||
operator==(value_type other) const
|
||||
{
|
||||
return fee_ == other;
|
||||
return value_ == other;
|
||||
}
|
||||
|
||||
template <class Other, class = enable_if_compatible_t<Other>>
|
||||
bool
|
||||
operator!=(TaggedFee<unit_type, Other> const& other) const
|
||||
constexpr bool
|
||||
operator!=(ValueUnit<unit_type, Other> const& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(TaggedFee const& other) const
|
||||
constexpr bool
|
||||
operator<(ValueUnit const& other) const
|
||||
{
|
||||
return fee_ < other.fee_;
|
||||
return value_ < other.value_;
|
||||
}
|
||||
|
||||
/** Returns true if the amount is not zero */
|
||||
explicit constexpr
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return fee_ != 0;
|
||||
return value_ != 0;
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
constexpr int
|
||||
signum() const noexcept
|
||||
{
|
||||
return (fee_ < 0) ? -1 : (fee_ ? 1 : 0);
|
||||
return (value_ < 0) ? -1 : (value_ ? 1 : 0);
|
||||
}
|
||||
|
||||
/** Returns the number of drops */
|
||||
// TODO: Move this to a new class, maybe with the old "TaggedFee" name
|
||||
constexpr value_type
|
||||
fee() const
|
||||
{
|
||||
return fee_;
|
||||
return value_;
|
||||
}
|
||||
|
||||
template <class Other>
|
||||
constexpr double
|
||||
decimalFromReference(TaggedFee<unit_type, Other> reference) const
|
||||
decimalFromReference(ValueUnit<unit_type, Other> reference) const
|
||||
{
|
||||
return static_cast<double>(fee_) / reference.fee();
|
||||
return static_cast<double>(value_) / reference.value();
|
||||
}
|
||||
|
||||
// `is_usable_unit_v` is checked to ensure that only values with
|
||||
// known valid type tags can be converted to JSON. At the time
|
||||
// of implementation, that includes all known tags, but more may
|
||||
// be added in the future.
|
||||
std::enable_if_t<is_usable_unit_v<TaggedFee>, Json::Value>
|
||||
std::enable_if_t<is_usable_unit_v<ValueUnit>, Json::Value>
|
||||
jsonClipped() const
|
||||
{
|
||||
if constexpr (std::is_integral_v<value_type>)
|
||||
@@ -303,15 +332,15 @@ public:
|
||||
constexpr auto min = std::numeric_limits<jsontype>::min();
|
||||
constexpr auto max = std::numeric_limits<jsontype>::max();
|
||||
|
||||
if (fee_ < min)
|
||||
if (value_ < min)
|
||||
return min;
|
||||
if (fee_ > max)
|
||||
if (value_ > max)
|
||||
return max;
|
||||
return static_cast<jsontype>(fee_);
|
||||
return static_cast<jsontype>(value_);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fee_;
|
||||
return value_;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,30 +351,30 @@ public:
|
||||
constexpr value_type
|
||||
value() const
|
||||
{
|
||||
return fee_;
|
||||
return value_;
|
||||
}
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& s, TaggedFee& val)
|
||||
operator>>(std::istream& s, ValueUnit& val)
|
||||
{
|
||||
s >> val.fee_;
|
||||
s >> val.value_;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
// Output Fees as just their numeric value.
|
||||
// Output Values as just their numeric value.
|
||||
template <class Char, class Traits, class UnitTag, class T>
|
||||
std::basic_ostream<Char, Traits>&
|
||||
operator<<(std::basic_ostream<Char, Traits>& os, const TaggedFee<UnitTag, T>& q)
|
||||
operator<<(std::basic_ostream<Char, Traits>& os, ValueUnit<UnitTag, T> const& q)
|
||||
{
|
||||
return os << q.value();
|
||||
}
|
||||
|
||||
template <class UnitTag, class T>
|
||||
std::string
|
||||
to_string(TaggedFee<UnitTag, T> const& amount)
|
||||
to_string(ValueUnit<UnitTag, T> const& amount)
|
||||
{
|
||||
return std::to_string(amount.fee());
|
||||
return std::to_string(amount.value());
|
||||
}
|
||||
|
||||
template <class Source, class = enable_if_unit_t<Source>>
|
||||
@@ -408,10 +437,10 @@ using enable_muldiv_commute_t =
|
||||
typename std::enable_if_t<can_muldiv_commute_v<Source1, Source2, Dest>>;
|
||||
|
||||
template <class T>
|
||||
TaggedFee<unitlessTag, T>
|
||||
ValueUnit<unitlessTag, T>
|
||||
scalar(T value)
|
||||
{
|
||||
return TaggedFee<unitlessTag, T>{value};
|
||||
return ValueUnit<unitlessTag, T>{value};
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -422,18 +451,17 @@ template <
|
||||
std::optional<Dest>
|
||||
mulDivU(Source1 value, Dest mul, Source2 div)
|
||||
{
|
||||
// Fees can never be negative in any context.
|
||||
// values can never be negative in any context.
|
||||
if (value.value() < 0 || mul.value() < 0 || div.value() < 0)
|
||||
{
|
||||
// split the asserts so if one hits, the user can tell which
|
||||
// without a debugger.
|
||||
XRPL_ASSERT(
|
||||
value.value() >= 0,
|
||||
"ripple::feeunit::mulDivU : minimum value input");
|
||||
value.value() >= 0, "ripple::unit::mulDivU : minimum value input");
|
||||
XRPL_ASSERT(
|
||||
mul.value() >= 0, "ripple::feeunit::mulDivU : minimum mul input");
|
||||
mul.value() >= 0, "ripple::unit::mulDivU : minimum mul input");
|
||||
XRPL_ASSERT(
|
||||
div.value() >= 0, "ripple::feeunit::mulDivU : minimum div input");
|
||||
div.value() >= 0, "ripple::unit::mulDivU : minimum div input");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -466,46 +494,57 @@ mulDivU(Source1 value, Dest mul, Source2 div)
|
||||
return Dest{static_cast<desttype>(quotient)};
|
||||
}
|
||||
|
||||
} // namespace feeunit
|
||||
} // namespace unit
|
||||
|
||||
// Fee Levels
|
||||
template <class T>
|
||||
using FeeLevel = feeunit::TaggedFee<feeunit::feelevelTag, T>;
|
||||
using FeeLevel = unit::ValueUnit<unit::feelevelTag, T>;
|
||||
using FeeLevel64 = FeeLevel<std::uint64_t>;
|
||||
using FeeLevelDouble = FeeLevel<double>;
|
||||
|
||||
// Basis points (Bips)
|
||||
template <class T>
|
||||
using Bips = unit::ValueUnit<unit::BipsTag, T>;
|
||||
using Bips16 = Bips<std::uint16_t>;
|
||||
using Bips32 = Bips<std::uint32_t>;
|
||||
template <class T>
|
||||
using TenthBips = unit::ValueUnit<unit::TenthBipsTag, T>;
|
||||
using TenthBips16 = TenthBips<std::uint16_t>;
|
||||
using TenthBips32 = TenthBips<std::uint32_t>;
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = feeunit::enable_muldiv_t<Source1, Source2, Dest>>
|
||||
class = unit::enable_muldiv_t<Source1, Source2, Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(Source1 value, Dest mul, Source2 div)
|
||||
{
|
||||
return feeunit::mulDivU(value, mul, div);
|
||||
return unit::mulDivU(value, mul, div);
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = feeunit::enable_muldiv_commute_t<Source1, Source2, Dest>>
|
||||
class = unit::enable_muldiv_commute_t<Source1, Source2, Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(Dest value, Source1 mul, Source2 div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return feeunit::mulDivU(mul, value, div);
|
||||
return unit::mulDivU(mul, value, div);
|
||||
}
|
||||
|
||||
template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
|
||||
template <class Dest, class = unit::enable_muldiv_dest_t<Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(std::uint64_t value, Dest mul, std::uint64_t div)
|
||||
{
|
||||
// Give the scalars a non-tag so the
|
||||
// unit-handling version gets called.
|
||||
return feeunit::mulDivU(feeunit::scalar(value), mul, feeunit::scalar(div));
|
||||
return unit::mulDivU(unit::scalar(value), mul, unit::scalar(div));
|
||||
}
|
||||
|
||||
template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
|
||||
template <class Dest, class = unit::enable_muldiv_dest_t<Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
|
||||
{
|
||||
@@ -516,13 +555,13 @@ mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
|
||||
class = unit::enable_muldiv_sources_t<Source1, Source2>>
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(Source1 value, std::uint64_t mul, Source2 div)
|
||||
{
|
||||
// Give the scalars a dimensionless unit so the
|
||||
// unit-handling version gets called.
|
||||
auto unitresult = feeunit::mulDivU(value, feeunit::scalar(mul), div);
|
||||
auto unitresult = unit::mulDivU(value, unit::scalar(mul), div);
|
||||
|
||||
if (!unitresult)
|
||||
return std::nullopt;
|
||||
@@ -533,7 +572,7 @@ mulDiv(Source1 value, std::uint64_t mul, Source2 div)
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
|
||||
class = unit::enable_muldiv_sources_t<Source1, Source2>>
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(std::uint64_t value, Source1 mul, Source2 div)
|
||||
{
|
||||
@@ -553,6 +592,16 @@ safe_cast(Src s) noexcept
|
||||
return Dest{safe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_integral_v<typename Dest::value_type> && std::is_integral_v<Src>,
|
||||
Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{safe_cast<typename Dest::value_type>(s)};
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
|
||||
@@ -565,6 +614,16 @@ unsafe_cast(Src s) noexcept
|
||||
return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_integral_v<typename Dest::value_type> && std::is_integral_v<Src>,
|
||||
Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{unsafe_cast<typename Dest::value_type>(s)};
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // BASICS_FEES_H_INCLUDED
|
||||
#endif // PROTOCOL_UNITS_H_INCLUDED
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/FeeUnits.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
@@ -42,7 +42,7 @@ class XRPAmount : private boost::totally_ordered<XRPAmount>,
|
||||
private boost::additive<XRPAmount, std::int64_t>
|
||||
{
|
||||
public:
|
||||
using unit_type = feeunit::dropTag;
|
||||
using unit_type = unit::dropTag;
|
||||
using value_type = std::int64_t;
|
||||
|
||||
private:
|
||||
@@ -267,7 +267,7 @@ XRPAmount::decimalXRP() const
|
||||
// Output XRPAmount as just the drops value.
|
||||
template <class Char, class Traits>
|
||||
std::basic_ostream<Char, Traits>&
|
||||
operator<<(std::basic_ostream<Char, Traits>& os, const XRPAmount& q)
|
||||
operator<<(std::basic_ostream<Char, Traits>& os, XRPAmount const& q)
|
||||
{
|
||||
return os << q.drops();
|
||||
}
|
||||
|
||||
@@ -27,11 +27,15 @@
|
||||
#error "undefined macro: XRPL_RETIRE"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||
// in include/xrpl/protocol/Feature.h.
|
||||
|
||||
XRPL_FEATURE(LendingProtocol, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(SingleAssetVault, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PermissionDelegation, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo)
|
||||
// Check flags in Credential transactions
|
||||
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (FrozenLPTokenTransfer, Supported::yes, VoteBehavior::DefaultNo)
|
||||
@@ -143,3 +147,5 @@ XRPL_RETIRE(fix1201)
|
||||
XRPL_RETIRE(fix1512)
|
||||
XRPL_RETIRE(fix1523)
|
||||
XRPL_RETIRE(fix1528)
|
||||
|
||||
// clang-format on
|
||||
@@ -165,7 +165,9 @@ LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({
|
||||
{sfMintedNFTokens, soeDEFAULT},
|
||||
{sfBurnedNFTokens, soeDEFAULT},
|
||||
{sfFirstNFTokenSequence, soeOPTIONAL},
|
||||
{sfAMMID, soeOPTIONAL},
|
||||
{sfAMMID, soeOPTIONAL}, // pseudo-account designator
|
||||
{sfVaultID, soeOPTIONAL}, // pseudo-account designator
|
||||
{sfLoanBrokerID, soeOPTIONAL}, // pseudo-account designator
|
||||
}))
|
||||
|
||||
/** A ledger object which contains a list of object identifiers.
|
||||
@@ -390,21 +392,6 @@ LEDGER_ENTRY(ltAMM, 0x0079, AMM, amm, ({
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks Oracle
|
||||
\sa keylet::oracle
|
||||
*/
|
||||
LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, oracle, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfProvider, soeREQUIRED},
|
||||
{sfPriceDataSeries, soeREQUIRED},
|
||||
{sfAssetClass, soeREQUIRED},
|
||||
{sfLastUpdateTime, soeREQUIRED},
|
||||
{sfURI, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks MPTokenIssuance
|
||||
\sa keylet::mptIssuance
|
||||
*/
|
||||
@@ -419,6 +406,7 @@ LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
|
||||
{sfMPTokenMetadata, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfDomainID, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks MPToken
|
||||
@@ -433,6 +421,21 @@ LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks Oracle
|
||||
\sa keylet::oracle
|
||||
*/
|
||||
LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, oracle, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfProvider, soeREQUIRED},
|
||||
{sfPriceDataSeries, soeREQUIRED},
|
||||
{sfAssetClass, soeREQUIRED},
|
||||
{sfLastUpdateTime, soeREQUIRED},
|
||||
{sfURI, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks Credential
|
||||
\sa keylet::credential
|
||||
*/
|
||||
@@ -460,6 +463,101 @@ LEDGER_ENTRY(ltPERMISSIONED_DOMAIN, 0x0082, PermissionedDomain, permissioned_dom
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** A ledger object representing permissions an account has delegated to another account.
|
||||
\sa keylet::delegate
|
||||
*/
|
||||
LEDGER_ENTRY(ltDELEGATE, 0x0083, Delegate, delegate, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfAuthorize, soeREQUIRED},
|
||||
{sfPermissions, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** A ledger object representing a single asset vault.
|
||||
|
||||
\sa keylet::mptoken
|
||||
*/
|
||||
LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfSequence, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfData, soeOPTIONAL},
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAssetsTotal, soeREQUIRED},
|
||||
{sfAssetsAvailable, soeREQUIRED},
|
||||
{sfAssetsMaximum, soeDEFAULT},
|
||||
{sfLossUnrealized, soeREQUIRED},
|
||||
{sfShareMPTID, soeREQUIRED},
|
||||
{sfWithdrawalPolicy, soeREQUIRED},
|
||||
// no SharesTotal ever (use MPTIssuance.sfOutstandingAmount)
|
||||
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
|
||||
}))
|
||||
|
||||
/** Reserve 0x0084-0x0087 for future Vault-related objects. */
|
||||
|
||||
/** A ledger object representing a loan broker
|
||||
|
||||
\sa keylet::loanbroker
|
||||
*/
|
||||
LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfSequence, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfVaultNode, soeREQUIRED},
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfLoanSequence, soeREQUIRED},
|
||||
{sfData, soeDEFAULT},
|
||||
{sfManagementFeeRate, soeDEFAULT},
|
||||
{sfOwnerCount, soeDEFAULT},
|
||||
{sfDebtTotal, soeDEFAULT},
|
||||
{sfDebtMaximum, soeDEFAULT},
|
||||
{sfCoverAvailable, soeDEFAULT},
|
||||
{sfCoverRateMinimum, soeDEFAULT},
|
||||
{sfCoverRateLiquidation, soeDEFAULT},
|
||||
}))
|
||||
|
||||
/** A ledger object representing a loan between a Borrower and a Loan Broker
|
||||
|
||||
\sa keylet::loan
|
||||
*/
|
||||
LEDGER_ENTRY(ltLOAN, 0x0089, Loan, loan, ({
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfLoanBrokerNode, soeREQUIRED},
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
{sfLoanSequence, soeREQUIRED},
|
||||
{sfBorrower, soeREQUIRED},
|
||||
{sfLoanOriginationFee, soeREQUIRED},
|
||||
{sfLoanServiceFee, soeREQUIRED},
|
||||
{sfLatePaymentFee, soeREQUIRED},
|
||||
{sfClosePaymentFee, soeREQUIRED},
|
||||
{sfOverpaymentFee, soeREQUIRED},
|
||||
{sfInterestRate, soeREQUIRED},
|
||||
{sfLateInterestRate, soeREQUIRED},
|
||||
{sfCloseInterestRate, soeREQUIRED},
|
||||
{sfOverpaymentInterestRate, soeREQUIRED},
|
||||
{sfStartDate, soeREQUIRED},
|
||||
{sfPaymentInterval, soeREQUIRED},
|
||||
{sfGracePeriod, soeREQUIRED},
|
||||
{sfPreviousPaymentDate, soeREQUIRED},
|
||||
{sfNextPaymentDueDate, soeREQUIRED},
|
||||
{sfPaymentRemaining, soeREQUIRED},
|
||||
{sfAssetsAvailable, soeREQUIRED},
|
||||
{sfPrincipalOutstanding, soeREQUIRED},
|
||||
// Save the original request amount for rounding / scaling of
|
||||
// other computations, particularly for IOUs
|
||||
{sfPrincipalRequested, soeREQUIRED},
|
||||
}))
|
||||
|
||||
#undef EXPAND
|
||||
#undef LEDGER_ENTRY_DUPLICATE
|
||||
|
||||
|
||||
68
include/xrpl/protocol/detail/permissions.macro
Normal file
68
include/xrpl/protocol/detail/permissions.macro
Normal file
@@ -0,0 +1,68 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#if !defined(PERMISSION)
|
||||
#error "undefined macro: PERMISSION"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* PERMISSION(name, type, txType, value)
|
||||
*
|
||||
* This macro defines a permission:
|
||||
* name: the name of the permission.
|
||||
* type: the GranularPermissionType enum.
|
||||
* txType: the corresponding TxType for this permission.
|
||||
* value: the uint32 numeric value for the enum type.
|
||||
*/
|
||||
|
||||
/** This permission grants the delegated account the ability to authorize a trustline. */
|
||||
PERMISSION(TrustlineAuthorize, ttTRUST_SET, 65537)
|
||||
|
||||
/** This permission grants the delegated account the ability to freeze a trustline. */
|
||||
PERMISSION(TrustlineFreeze, ttTRUST_SET, 65538)
|
||||
|
||||
/** This permission grants the delegated account the ability to unfreeze a trustline. */
|
||||
PERMISSION(TrustlineUnfreeze, ttTRUST_SET, 65539)
|
||||
|
||||
/** This permission grants the delegated account the ability to set Domain. */
|
||||
PERMISSION(AccountDomainSet, ttACCOUNT_SET, 65540)
|
||||
|
||||
/** This permission grants the delegated account the ability to set EmailHashSet. */
|
||||
PERMISSION(AccountEmailHashSet, ttACCOUNT_SET, 65541)
|
||||
|
||||
/** This permission grants the delegated account the ability to set MessageKey. */
|
||||
PERMISSION(AccountMessageKeySet, ttACCOUNT_SET, 65542)
|
||||
|
||||
/** This permission grants the delegated account the ability to set TransferRate. */
|
||||
PERMISSION(AccountTransferRateSet, ttACCOUNT_SET, 65543)
|
||||
|
||||
/** This permission grants the delegated account the ability to set TickSize. */
|
||||
PERMISSION(AccountTickSizeSet, ttACCOUNT_SET, 65544)
|
||||
|
||||
/** This permission grants the delegated account the ability to mint payment, which means sending a payment for a currency where the sending account is the issuer. */
|
||||
PERMISSION(PaymentMint, ttPAYMENT, 65545)
|
||||
|
||||
/** This permission grants the delegated account the ability to burn payment, which means sending a payment for a currency where the destination account is the issuer */
|
||||
PERMISSION(PaymentBurn, ttPAYMENT, 65546)
|
||||
|
||||
/** This permission grants the delegated account the ability to lock MPToken. */
|
||||
PERMISSION(MPTokenIssuanceLock, ttMPTOKEN_ISSUANCE_SET, 65547)
|
||||
|
||||
/** This permission grants the delegated account the ability to unlock MPToken. */
|
||||
PERMISSION(MPTokenIssuanceUnlock, ttMPTOKEN_ISSUANCE_SET, 65548)
|
||||
@@ -24,6 +24,8 @@
|
||||
#error "undefined macro: TYPED_SFIELD"
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
|
||||
// untyped
|
||||
UNTYPED_SFIELD(sfLedgerEntry, LEDGERENTRY, 257)
|
||||
UNTYPED_SFIELD(sfTransaction, TRANSACTION, 257)
|
||||
@@ -42,6 +44,7 @@ TYPED_SFIELD(sfTickSize, UINT8, 16)
|
||||
TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
|
||||
TYPED_SFIELD(sfHookResult, UINT8, 18)
|
||||
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
|
||||
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
|
||||
|
||||
// 16-bit integers (common)
|
||||
TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::sMD_Never)
|
||||
@@ -58,6 +61,7 @@ TYPED_SFIELD(sfHookEmitCount, UINT16, 18)
|
||||
TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19)
|
||||
TYPED_SFIELD(sfHookApiVersion, UINT16, 20)
|
||||
TYPED_SFIELD(sfLedgerFixType, UINT16, 21)
|
||||
TYPED_SFIELD(sfManagementFeeRate, UINT16, 22) // 1/10 basis points (bips)
|
||||
|
||||
// 32-bit integers (common)
|
||||
TYPED_SFIELD(sfNetworkID, UINT32, 1)
|
||||
@@ -112,6 +116,22 @@ TYPED_SFIELD(sfEmitGeneration, UINT32, 46)
|
||||
TYPED_SFIELD(sfVoteWeight, UINT32, 48)
|
||||
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
|
||||
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
|
||||
TYPED_SFIELD(sfPermissionValue, UINT32, 52)
|
||||
TYPED_SFIELD(sfStartDate, UINT32, 53)
|
||||
TYPED_SFIELD(sfPaymentInterval, UINT32, 54)
|
||||
TYPED_SFIELD(sfGracePeriod, UINT32, 55)
|
||||
TYPED_SFIELD(sfPreviousPaymentDate, UINT32, 56)
|
||||
TYPED_SFIELD(sfNextPaymentDueDate, UINT32, 57)
|
||||
TYPED_SFIELD(sfPaymentRemaining, UINT32, 58)
|
||||
TYPED_SFIELD(sfPaymentTotal, UINT32, 59)
|
||||
TYPED_SFIELD(sfLoanSequence, UINT32, 60)
|
||||
TYPED_SFIELD(sfCoverRateMinimum, UINT32, 61) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfCoverRateLiquidation, UINT32, 62) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfOverpaymentFee, UINT32, 63) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfInterestRate, UINT32, 64) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfLateInterestRate, UINT32, 65) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfCloseInterestRate, UINT32, 66) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfOverpaymentInterestRate, UINT32, 67) // 1/10 basis points (bips)
|
||||
|
||||
// 64-bit integers (common)
|
||||
TYPED_SFIELD(sfIndexNext, UINT64, 1)
|
||||
@@ -142,6 +162,8 @@ TYPED_SFIELD(sfOutstandingAmount, UINT64, 25, SField::sMD_BaseTen|SFie
|
||||
TYPED_SFIELD(sfMPTAmount, UINT64, 26, SField::sMD_BaseTen|SField::sMD_Default)
|
||||
TYPED_SFIELD(sfIssuerNode, UINT64, 27)
|
||||
TYPED_SFIELD(sfSubjectNode, UINT64, 28)
|
||||
TYPED_SFIELD(sfVaultNode, UINT64, 29)
|
||||
TYPED_SFIELD(sfLoanBrokerNode, UINT64, 30)
|
||||
|
||||
// 128-bit
|
||||
TYPED_SFIELD(sfEmailHash, UINT128, 1)
|
||||
@@ -154,6 +176,7 @@ TYPED_SFIELD(sfTakerGetsIssuer, UINT160, 4)
|
||||
|
||||
// 192-bit (common)
|
||||
TYPED_SFIELD(sfMPTokenIssuanceID, UINT192, 1)
|
||||
TYPED_SFIELD(sfShareMPTID, UINT192, 2)
|
||||
|
||||
// 256-bit (common)
|
||||
TYPED_SFIELD(sfLedgerHash, UINT256, 1)
|
||||
@@ -169,7 +192,8 @@ TYPED_SFIELD(sfNFTokenID, UINT256, 10)
|
||||
TYPED_SFIELD(sfEmitParentTxnID, UINT256, 11)
|
||||
TYPED_SFIELD(sfEmitNonce, UINT256, 12)
|
||||
TYPED_SFIELD(sfEmitHookHash, UINT256, 13)
|
||||
TYPED_SFIELD(sfAMMID, UINT256, 14)
|
||||
TYPED_SFIELD(sfAMMID, UINT256, 14,
|
||||
SField::sMD_PseudoAccount |SField::sMD_Default)
|
||||
|
||||
// 256-bit (uncommon)
|
||||
TYPED_SFIELD(sfBookDirectory, UINT256, 16)
|
||||
@@ -191,9 +215,27 @@ TYPED_SFIELD(sfHookHash, UINT256, 31)
|
||||
TYPED_SFIELD(sfHookNamespace, UINT256, 32)
|
||||
TYPED_SFIELD(sfHookSetTxnID, UINT256, 33)
|
||||
TYPED_SFIELD(sfDomainID, UINT256, 34)
|
||||
TYPED_SFIELD(sfVaultID, UINT256, 35,
|
||||
SField::sMD_PseudoAccount | SField::sMD_Default)
|
||||
TYPED_SFIELD(sfLoanBrokerID, UINT256, 36,
|
||||
SField::sMD_PseudoAccount | SField::sMD_Default)
|
||||
TYPED_SFIELD(sfLoanID, UINT256, 37)
|
||||
|
||||
// number (common)
|
||||
TYPED_SFIELD(sfNumber, NUMBER, 1)
|
||||
TYPED_SFIELD(sfAssetsAvailable, NUMBER, 2)
|
||||
TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3)
|
||||
TYPED_SFIELD(sfAssetsTotal, NUMBER, 4)
|
||||
TYPED_SFIELD(sfLossUnrealized, NUMBER, 5)
|
||||
TYPED_SFIELD(sfDebtTotal, NUMBER, 6)
|
||||
TYPED_SFIELD(sfDebtMaximum, NUMBER, 7)
|
||||
TYPED_SFIELD(sfCoverAvailable, NUMBER, 8)
|
||||
TYPED_SFIELD(sfLoanOriginationFee, NUMBER, 9)
|
||||
TYPED_SFIELD(sfLoanServiceFee, NUMBER, 10)
|
||||
TYPED_SFIELD(sfLatePaymentFee, NUMBER, 11)
|
||||
TYPED_SFIELD(sfClosePaymentFee, NUMBER, 12)
|
||||
TYPED_SFIELD(sfPrincipalOutstanding, NUMBER, 13)
|
||||
TYPED_SFIELD(sfPrincipalRequested, NUMBER, 14)
|
||||
|
||||
// currency amount (common)
|
||||
TYPED_SFIELD(sfAmount, AMOUNT, 1)
|
||||
@@ -278,6 +320,7 @@ TYPED_SFIELD(sfRegularKey, ACCOUNT, 8)
|
||||
TYPED_SFIELD(sfNFTokenMinter, ACCOUNT, 9)
|
||||
TYPED_SFIELD(sfEmitCallback, ACCOUNT, 10)
|
||||
TYPED_SFIELD(sfHolder, ACCOUNT, 11)
|
||||
TYPED_SFIELD(sfDelegate, ACCOUNT, 12)
|
||||
|
||||
// account (uncommon)
|
||||
TYPED_SFIELD(sfHookAccount, ACCOUNT, 16)
|
||||
@@ -288,6 +331,8 @@ TYPED_SFIELD(sfAttestationRewardAccount, ACCOUNT, 21)
|
||||
TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22)
|
||||
TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23)
|
||||
TYPED_SFIELD(sfSubject, ACCOUNT, 24)
|
||||
TYPED_SFIELD(sfBorrower, ACCOUNT, 25)
|
||||
TYPED_SFIELD(sfCounterparty, ACCOUNT, 26)
|
||||
|
||||
// vector of 256-bit
|
||||
TYPED_SFIELD(sfIndexes, VECTOR256, 1, SField::sMD_Never)
|
||||
@@ -327,6 +372,7 @@ UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11)
|
||||
UNTYPED_SFIELD(sfNFToken, OBJECT, 12)
|
||||
UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13)
|
||||
UNTYPED_SFIELD(sfHook, OBJECT, 14)
|
||||
UNTYPED_SFIELD(sfPermission, OBJECT, 15)
|
||||
|
||||
// inner object (uncommon)
|
||||
UNTYPED_SFIELD(sfSigner, OBJECT, 16)
|
||||
@@ -347,6 +393,7 @@ UNTYPED_SFIELD(sfXChainClaimAttestationCollectionElement, OBJECT, 30)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountAttestationCollectionElement, OBJECT, 31)
|
||||
UNTYPED_SFIELD(sfPriceData, OBJECT, 32)
|
||||
UNTYPED_SFIELD(sfCredential, OBJECT, 33)
|
||||
UNTYPED_SFIELD(sfCounterpartySignature, OBJECT, 34, SField::sMD_Default, SField::notSigning)
|
||||
|
||||
// array of objects (common)
|
||||
// ARRAY/1 is reserved for end of array
|
||||
@@ -377,3 +424,6 @@ UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25)
|
||||
UNTYPED_SFIELD(sfAuthorizeCredentials, ARRAY, 26)
|
||||
UNTYPED_SFIELD(sfUnauthorizeCredentials, ARRAY, 27)
|
||||
UNTYPED_SFIELD(sfAcceptedCredentials, ARRAY, 28)
|
||||
UNTYPED_SFIELD(sfPermissions, ARRAY, 29)
|
||||
|
||||
// clang-format on
|
||||
|
||||
@@ -50,7 +50,7 @@ class TokenCodecErrcCategory : public std::error_category
|
||||
{
|
||||
public:
|
||||
// Return a short descriptive name for the category
|
||||
virtual const char*
|
||||
virtual char const*
|
||||
name() const noexcept override final
|
||||
{
|
||||
return "TokenCodecError";
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
inline const ripple::detail::TokenCodecErrcCategory&
|
||||
inline ripple::detail::TokenCodecErrcCategory const&
|
||||
TokenCodecErrcCategory()
|
||||
{
|
||||
static ripple::detail::TokenCodecErrcCategory c;
|
||||
|
||||
@@ -22,14 +22,47 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TRANSACTION(tag, value, name, fields)
|
||||
* TRANSACTION(tag, value, name, delegatable, privileges, fields)
|
||||
*
|
||||
* To ease maintenance, you may replace any unneeded values with "..."
|
||||
* e.g. #define TRANSACTION(tag, value, name, ...)
|
||||
*
|
||||
* You must define a transactor class in the `ripple` namespace named `name`,
|
||||
* and include its header in `src/xrpld/app/tx/detail/applySteps.cpp`.
|
||||
* and include its header alongside the TRANSACTOR definition using this
|
||||
* format:
|
||||
* #if TRANSACTION_INCLUDE
|
||||
* # include <xrpld/app/tx/detail/HEADER.h>
|
||||
* #endif
|
||||
*
|
||||
* The `privileges` parameter of the TRANSACTION macro is a bitfield
|
||||
* defining which operations the transaction can perform.
|
||||
*
|
||||
* The values are only used in InvariantCheck.cpp
|
||||
* Valid values are
|
||||
noPriv - The transaction can not do any of the enumerated operations
|
||||
createAcct - The transaction can create a new ACCOUNT_ROOT object.
|
||||
createPseudoAcct - The transaction can create a pseudo account,
|
||||
which implies createAcct
|
||||
mustDeleteAcct - The transaction must delete an ACCOUNT_ROOT object
|
||||
mayDeleteAcct - The transaction may delete an ACCOUNT_ROOT object,
|
||||
but does not have to
|
||||
overrideFreeze - The transaction can override some freeze rules
|
||||
changeNFTCounts - The transaction can mint or burn an NFT
|
||||
createMPTIssuance - The transaction can create a new MPT issuance
|
||||
destroyMPTIssuance - The transaction can destroy an MPT issuance
|
||||
mustAuthorizeMPT - The transaction MUST create or delete an MPT
|
||||
object (except by issuer)
|
||||
mayAuthorizeMPT - The transaction MAY create or delete an MPT
|
||||
object (except by issuer)
|
||||
*/
|
||||
|
||||
/** This transaction type executes a payment. */
|
||||
TRANSACTION(ttPAYMENT, 0, Payment, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Payment.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYMENT, 0, Payment,
|
||||
Delegation::delegatable,
|
||||
createAcct, ({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
{sfSendMax, soeOPTIONAL, soeMPTSupported},
|
||||
@@ -41,7 +74,12 @@ TRANSACTION(ttPAYMENT, 0, Payment, ({
|
||||
}))
|
||||
|
||||
/** This transaction type creates an escrow object. */
|
||||
TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Escrow.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfCondition, soeOPTIONAL},
|
||||
@@ -51,7 +89,9 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate, ({
|
||||
}))
|
||||
|
||||
/** This transaction type completes an existing escrow. */
|
||||
TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, ({
|
||||
TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
{sfFulfillment, soeOPTIONAL},
|
||||
@@ -61,7 +101,12 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish, ({
|
||||
|
||||
|
||||
/** This transaction type adjusts various account settings. */
|
||||
TRANSACTION(ttACCOUNT_SET, 3, AccountSet, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetAccount.h>
|
||||
#endif
|
||||
TRANSACTION(ttACCOUNT_SET, 3, AccountSet,
|
||||
Delegation::notDelegatable,
|
||||
noPriv, ({
|
||||
{sfEmailHash, soeOPTIONAL},
|
||||
{sfWalletLocator, soeOPTIONAL},
|
||||
{sfWalletSize, soeOPTIONAL},
|
||||
@@ -75,20 +120,35 @@ TRANSACTION(ttACCOUNT_SET, 3, AccountSet, ({
|
||||
}))
|
||||
|
||||
/** This transaction type cancels an existing escrow. */
|
||||
TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Escrow.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type sets or clears an account's "regular key". */
|
||||
TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetRegularKey.h>
|
||||
#endif
|
||||
TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey,
|
||||
Delegation::notDelegatable,
|
||||
noPriv, ({
|
||||
{sfRegularKey, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
// 6 deprecated
|
||||
|
||||
/** This transaction type creates an offer to trade one asset for another. */
|
||||
TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CreateOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttOFFER_CREATE, 7, OfferCreate,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfTakerPays, soeREQUIRED},
|
||||
{sfTakerGets, soeREQUIRED},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
@@ -96,14 +156,24 @@ TRANSACTION(ttOFFER_CREATE, 7, OfferCreate, ({
|
||||
}))
|
||||
|
||||
/** This transaction type cancels existing offers to trade one asset for another. */
|
||||
TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CancelOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
}))
|
||||
|
||||
// 9 deprecated
|
||||
|
||||
/** This transaction type creates a new set of tickets. */
|
||||
TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CreateTicket.h>
|
||||
#endif
|
||||
TRANSACTION(ttTICKET_CREATE, 10, TicketCreate,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfTicketCount, soeREQUIRED},
|
||||
}))
|
||||
|
||||
@@ -112,13 +182,23 @@ TRANSACTION(ttTICKET_CREATE, 10, TicketCreate, ({
|
||||
/** This transaction type modifies the signer list associated with an account. */
|
||||
// The SignerEntries are optional because a SignerList is deleted by
|
||||
// setting the SignerQuorum to zero and omitting SignerEntries.
|
||||
TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetSignerList.h>
|
||||
#endif
|
||||
TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet,
|
||||
Delegation::notDelegatable,
|
||||
noPriv, ({
|
||||
{sfSignerQuorum, soeREQUIRED},
|
||||
{sfSignerEntries, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type creates a new unidirectional XRP payment channel. */
|
||||
TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/PayChan.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfSettleDelay, soeREQUIRED},
|
||||
@@ -128,14 +208,18 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate, ({
|
||||
}))
|
||||
|
||||
/** This transaction type funds an existing unidirectional XRP payment channel. */
|
||||
TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund, ({
|
||||
TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfChannel, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type submits a claim against an existing unidirectional payment channel. */
|
||||
TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, ({
|
||||
TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfChannel, soeREQUIRED},
|
||||
{sfAmount, soeOPTIONAL},
|
||||
{sfBalance, soeOPTIONAL},
|
||||
@@ -145,7 +229,12 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim, ({
|
||||
}))
|
||||
|
||||
/** This transaction type creates a new check. */
|
||||
TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CreateCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfSendMax, soeREQUIRED},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
@@ -154,19 +243,34 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate, ({
|
||||
}))
|
||||
|
||||
/** This transaction type cashes an existing check. */
|
||||
TRANSACTION(ttCHECK_CASH, 17, CheckCash, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CashCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CASH, 17, CheckCash,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfCheckID, soeREQUIRED},
|
||||
{sfAmount, soeOPTIONAL},
|
||||
{sfDeliverMin, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type cancels an existing check. */
|
||||
TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CancelCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfCheckID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type grants or revokes authorization to transfer funds. */
|
||||
TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DepositPreauth.h>
|
||||
#endif
|
||||
TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfAuthorize, soeOPTIONAL},
|
||||
{sfUnauthorize, soeOPTIONAL},
|
||||
{sfAuthorizeCredentials, soeOPTIONAL},
|
||||
@@ -174,14 +278,24 @@ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth, ({
|
||||
}))
|
||||
|
||||
/** This transaction type modifies a trustline between two accounts. */
|
||||
TRANSACTION(ttTRUST_SET, 20, TrustSet, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetTrust.h>
|
||||
#endif
|
||||
TRANSACTION(ttTRUST_SET, 20, TrustSet,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLimitAmount, soeOPTIONAL},
|
||||
{sfQualityIn, soeOPTIONAL},
|
||||
{sfQualityOut, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type deletes an existing account. */
|
||||
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DeleteAccount.h>
|
||||
#endif
|
||||
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
|
||||
Delegation::notDelegatable,
|
||||
mustDeleteAcct, ({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfDestinationTag, soeOPTIONAL},
|
||||
{sfCredentialIDs, soeOPTIONAL},
|
||||
@@ -190,7 +304,12 @@ TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete, ({
|
||||
// 22 reserved
|
||||
|
||||
/** This transaction mints a new NFT. */
|
||||
TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenMint.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint,
|
||||
Delegation::delegatable,
|
||||
changeNFTCounts, ({
|
||||
{sfNFTokenTaxon, soeREQUIRED},
|
||||
{sfTransferFee, soeOPTIONAL},
|
||||
{sfIssuer, soeOPTIONAL},
|
||||
@@ -201,13 +320,23 @@ TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint, ({
|
||||
}))
|
||||
|
||||
/** This transaction burns (i.e. destroys) an existing NFT. */
|
||||
TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenBurn.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn,
|
||||
Delegation::delegatable,
|
||||
changeNFTCounts, ({
|
||||
{sfNFTokenID, soeREQUIRED},
|
||||
{sfOwner, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction creates a new offer to buy or sell an NFT. */
|
||||
TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenCreateOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfNFTokenID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfDestination, soeOPTIONAL},
|
||||
@@ -216,25 +345,45 @@ TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer, ({
|
||||
}))
|
||||
|
||||
/** This transaction cancels an existing offer to buy or sell an existing NFT. */
|
||||
TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenCancelOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfNFTokenOffers, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction accepts an existing offer to buy or sell an existing NFT. */
|
||||
TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenAcceptOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfNFTokenBuyOffer, soeOPTIONAL},
|
||||
{sfNFTokenSellOffer, soeOPTIONAL},
|
||||
{sfNFTokenBrokerFee, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction claws back issued tokens. */
|
||||
TRANSACTION(ttCLAWBACK, 30, Clawback, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Clawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttCLAWBACK, 30, Clawback,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
{sfHolder, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction claws back tokens from an AMM pool. */
|
||||
TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback,
|
||||
Delegation::delegatable,
|
||||
mayDeleteAcct | overrideFreeze, ({
|
||||
{sfHolder, soeREQUIRED},
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
@@ -242,14 +391,24 @@ TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback, ({
|
||||
}))
|
||||
|
||||
/** This transaction type creates an AMM instance */
|
||||
TRANSACTION(ttAMM_CREATE, 35, AMMCreate, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_CREATE, 35, AMMCreate,
|
||||
Delegation::delegatable,
|
||||
createPseudoAcct, ({
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfAmount2, soeREQUIRED},
|
||||
{sfTradingFee, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type deposits into an AMM instance */
|
||||
TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
{sfAmount, soeOPTIONAL},
|
||||
@@ -260,7 +419,12 @@ TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit, ({
|
||||
}))
|
||||
|
||||
/** This transaction type withdraws from an AMM instance */
|
||||
TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw,
|
||||
Delegation::delegatable,
|
||||
mayDeleteAcct, ({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
{sfAmount, soeOPTIONAL},
|
||||
@@ -270,14 +434,24 @@ TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw, ({
|
||||
}))
|
||||
|
||||
/** This transaction type votes for the trading fee */
|
||||
TRANSACTION(ttAMM_VOTE, 38, AMMVote, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMVote.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_VOTE, 38, AMMVote,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
{sfTradingFee, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type bids for the auction slot */
|
||||
TRANSACTION(ttAMM_BID, 39, AMMBid, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMBid.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_BID, 39, AMMBid,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
{sfBidMin, soeOPTIONAL},
|
||||
@@ -286,20 +460,32 @@ TRANSACTION(ttAMM_BID, 39, AMMBid, ({
|
||||
}))
|
||||
|
||||
/** This transaction type deletes AMM in the empty state */
|
||||
TRANSACTION(ttAMM_DELETE, 40, AMMDelete, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_DELETE, 40, AMMDelete,
|
||||
Delegation::delegatable,
|
||||
mustDeleteAcct, ({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transactions creates a crosschain sequence number */
|
||||
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/XChainBridge.h>
|
||||
#endif
|
||||
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfSignatureReward, soeREQUIRED},
|
||||
{sfOtherChainSource, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transactions initiates a crosschain transaction */
|
||||
TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit, ({
|
||||
TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfXChainClaimID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
@@ -307,7 +493,9 @@ TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit, ({
|
||||
}))
|
||||
|
||||
/** This transaction completes a crosschain transaction */
|
||||
TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim, ({
|
||||
TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfXChainClaimID, soeREQUIRED},
|
||||
{sfDestination, soeREQUIRED},
|
||||
@@ -316,7 +504,9 @@ TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim, ({
|
||||
}))
|
||||
|
||||
/** This transaction initiates a crosschain account create transaction */
|
||||
TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit, ({
|
||||
TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
@@ -324,7 +514,9 @@ TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit, ({
|
||||
}))
|
||||
|
||||
/** This transaction adds an attestation to a claim */
|
||||
TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation, ({
|
||||
TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation,
|
||||
Delegation::delegatable,
|
||||
createAcct, ({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
|
||||
{sfAttestationSignerAccount, soeREQUIRED},
|
||||
@@ -340,7 +532,10 @@ TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation, ({
|
||||
}))
|
||||
|
||||
/** This transaction adds an attestation to an account */
|
||||
TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, XChainAddAccountCreateAttestation, ({
|
||||
TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46,
|
||||
XChainAddAccountCreateAttestation,
|
||||
Delegation::delegatable,
|
||||
createAcct, ({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
|
||||
{sfAttestationSignerAccount, soeREQUIRED},
|
||||
@@ -357,31 +552,47 @@ TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, XChainAddAccountCreateA
|
||||
}))
|
||||
|
||||
/** This transaction modifies a sidechain */
|
||||
TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge, ({
|
||||
TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfSignatureReward, soeOPTIONAL},
|
||||
{sfMinAccountCreateAmount, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transactions creates a sidechain */
|
||||
TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge, ({
|
||||
TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfSignatureReward, soeREQUIRED},
|
||||
{sfMinAccountCreateAmount, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type creates or updates a DID */
|
||||
TRANSACTION(ttDID_SET, 49, DIDSet, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DID.h>
|
||||
#endif
|
||||
TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfDIDDocument, soeOPTIONAL},
|
||||
{sfURI, soeOPTIONAL},
|
||||
{sfData, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type deletes a DID */
|
||||
TRANSACTION(ttDID_DELETE, 50, DIDDelete, ({}))
|
||||
TRANSACTION(ttDID_DELETE, 50, DIDDelete,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({}))
|
||||
|
||||
/** This transaction type creates an Oracle instance */
|
||||
TRANSACTION(ttORACLE_SET, 51, OracleSet, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetOracle.h>
|
||||
#endif
|
||||
TRANSACTION(ttORACLE_SET, 51, OracleSet,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfOracleDocumentID, soeREQUIRED},
|
||||
{sfProvider, soeOPTIONAL},
|
||||
{sfURI, soeOPTIONAL},
|
||||
@@ -391,18 +602,33 @@ TRANSACTION(ttORACLE_SET, 51, OracleSet, ({
|
||||
}))
|
||||
|
||||
/** This transaction type deletes an Oracle instance */
|
||||
TRANSACTION(ttORACLE_DELETE, 52, OracleDelete, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DeleteOracle.h>
|
||||
#endif
|
||||
TRANSACTION(ttORACLE_DELETE, 52, OracleDelete,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfOracleDocumentID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type fixes a problem in the ledger state */
|
||||
TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LedgerStateFix.h>
|
||||
#endif
|
||||
TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLedgerFixType, soeREQUIRED},
|
||||
{sfOwner, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type creates a MPTokensIssuance instance */
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate,
|
||||
Delegation::delegatable,
|
||||
createMPTIssuance, ({
|
||||
{sfAssetScale, soeOPTIONAL},
|
||||
{sfTransferFee, soeOPTIONAL},
|
||||
{sfMaximumAmount, soeOPTIONAL},
|
||||
@@ -410,24 +636,44 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate, ({
|
||||
}))
|
||||
|
||||
/** This transaction type destroys a MPTokensIssuance instance */
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceDestroy.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy,
|
||||
Delegation::delegatable,
|
||||
destroyMPTIssuance, ({
|
||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type sets flags on a MPTokensIssuance or MPToken instance */
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||
{sfHolder, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type authorizes a MPToken instance */
|
||||
TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/MPTokenAuthorize.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize,
|
||||
Delegation::delegatable,
|
||||
mustAuthorizeMPT, ({
|
||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||
{sfHolder, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type create an Credential instance */
|
||||
TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Credentials.h>
|
||||
#endif
|
||||
TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfSubject, soeREQUIRED},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
@@ -435,41 +681,268 @@ TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate, ({
|
||||
}))
|
||||
|
||||
/** This transaction type accept an Credential object */
|
||||
TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept, ({
|
||||
TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type delete an Credential object */
|
||||
TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete, ({
|
||||
TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfSubject, soeOPTIONAL},
|
||||
{sfIssuer, soeOPTIONAL},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type modify a NFToken */
|
||||
TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenModify.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfNFTokenID, soeREQUIRED},
|
||||
{sfOwner, soeOPTIONAL},
|
||||
{sfURI, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type creates or modifies a Permissioned Domain */
|
||||
TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/PermissionedDomainSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfDomainID, soeOPTIONAL},
|
||||
{sfAcceptedCredentials, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type deletes a Permissioned Domain */
|
||||
TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/PermissionedDomainDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfDomainID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type delegates authorized account specified permissions */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DelegateSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
|
||||
Delegation::notDelegatable,
|
||||
noPriv, ({
|
||||
{sfAuthorize, soeREQUIRED},
|
||||
{sfPermissions, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction creates a single asset vault. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/VaultCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
|
||||
Delegation::delegatable,
|
||||
createPseudoAcct | createMPTIssuance, ({
|
||||
{sfAsset, soeREQUIRED, soeMPTSupported},
|
||||
{sfAssetsMaximum, soeOPTIONAL},
|
||||
{sfMPTokenMetadata, soeOPTIONAL},
|
||||
{sfDomainID, soeOPTIONAL}, // PermissionedDomainID
|
||||
{sfWithdrawalPolicy, soeOPTIONAL},
|
||||
{sfData, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction updates a single asset vault. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/VaultSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_SET, 66, VaultSet,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfAssetsMaximum, soeOPTIONAL},
|
||||
{sfDomainID, soeOPTIONAL}, // PermissionedDomainID
|
||||
{sfData, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction deletes a single asset vault. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/VaultDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
|
||||
Delegation::delegatable,
|
||||
mustDeleteAcct | destroyMPTIssuance, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction trades assets for shares with a vault. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/VaultDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_DEPOSIT, 68, VaultDeposit,
|
||||
Delegation::delegatable,
|
||||
mayAuthorizeMPT, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
}))
|
||||
|
||||
/** This transaction trades shares for assets with a vault. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/VaultWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
{sfDestination, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction claws back tokens from a vault. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/VaultClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfHolder, soeREQUIRED},
|
||||
{sfAmount, soeOPTIONAL, soeMPTSupported},
|
||||
}))
|
||||
|
||||
/** Reserve 71-73 for future Vault-related transactions */
|
||||
|
||||
/** This transaction creates and updates a Loan Broker */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanBrokerSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
|
||||
Delegation::delegatable,
|
||||
createPseudoAcct | mayAuthorizeMPT, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfLoanBrokerID, soeOPTIONAL},
|
||||
{sfData, soeOPTIONAL},
|
||||
{sfManagementFeeRate, soeOPTIONAL},
|
||||
{sfDebtMaximum, soeOPTIONAL},
|
||||
{sfCoverRateMinimum, soeOPTIONAL},
|
||||
{sfCoverRateLiquidation, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction deletes a Loan Broker */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanBrokerDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_DELETE, 75, LoanBrokerDelete,
|
||||
Delegation::delegatable,
|
||||
mustDeleteAcct | mayAuthorizeMPT, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction deposits First Loss Capital into a Loan Broker */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanBrokerCoverDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_DEPOSIT, 76, LoanBrokerCoverDeposit,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
}))
|
||||
|
||||
/** This transaction withdraws First Loss Capital from a Loan Broker */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanBrokerCoverWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_BROKER_COVER_WITHDRAW, 77, LoanBrokerCoverWithdraw,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
}))
|
||||
|
||||
/** This transaction creates a Loan */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_SET, 78, LoanSet,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLoanBrokerID, soeREQUIRED},
|
||||
{sfData, soeOPTIONAL},
|
||||
{sfCounterparty, soeOPTIONAL},
|
||||
{sfCounterpartySignature, soeREQUIRED},
|
||||
{sfLoanOriginationFee, soeOPTIONAL},
|
||||
{sfLoanServiceFee, soeOPTIONAL},
|
||||
{sfLatePaymentFee, soeOPTIONAL},
|
||||
{sfClosePaymentFee, soeOPTIONAL},
|
||||
{sfOverpaymentFee, soeOPTIONAL},
|
||||
{sfInterestRate, soeOPTIONAL},
|
||||
{sfLateInterestRate, soeOPTIONAL},
|
||||
{sfCloseInterestRate, soeOPTIONAL},
|
||||
{sfOverpaymentInterestRate, soeOPTIONAL},
|
||||
{sfPrincipalRequested, soeREQUIRED},
|
||||
{sfStartDate, soeREQUIRED},
|
||||
{sfPaymentTotal, soeOPTIONAL},
|
||||
{sfPaymentInterval, soeOPTIONAL},
|
||||
{sfGracePeriod, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction deletes an existing Loan */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_DELETE, 79, LoanDelete,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLoanID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction is used to change the delinquency status of an existing Loan */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanManage.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_MANAGE, 80, LoanManage,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLoanID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** The Borrower uses this transaction to draws funds from the Loan. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanDraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_DRAW, 81, LoanDraw,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLoanID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
}))
|
||||
|
||||
/** The Borrower uses this transaction to make a Payment on the Loan. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LoanPay.h>
|
||||
#endif
|
||||
TRANSACTION(ttLOAN_PAY, 82, LoanPay,
|
||||
Delegation::delegatable,
|
||||
noPriv, ({
|
||||
{sfLoanID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the status of the various amendments.
|
||||
|
||||
For details, see: https://xrpl.org/amendments.html
|
||||
*/
|
||||
TRANSACTION(ttAMENDMENT, 100, EnableAmendment, ({
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Change.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMENDMENT, 100, EnableAmendment,
|
||||
Delegation::notDelegatable,
|
||||
noPriv, ({
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
{sfAmendment, soeREQUIRED},
|
||||
}))
|
||||
@@ -477,7 +950,9 @@ TRANSACTION(ttAMENDMENT, 100, EnableAmendment, ({
|
||||
/** This system-generated transaction type is used to update the network's fee settings.
|
||||
For details, see: https://xrpl.org/fee-voting.html
|
||||
*/
|
||||
TRANSACTION(ttFEE, 101, SetFee, ({
|
||||
TRANSACTION(ttFEE, 101, SetFee,
|
||||
Delegation::notDelegatable,
|
||||
noPriv, ({
|
||||
{sfLedgerSequence, soeOPTIONAL},
|
||||
// Old version uses raw numbers
|
||||
{sfBaseFee, soeOPTIONAL},
|
||||
@@ -494,7 +969,9 @@ TRANSACTION(ttFEE, 101, SetFee, ({
|
||||
|
||||
For details, see: https://xrpl.org/negative-unl.html
|
||||
*/
|
||||
TRANSACTION(ttUNL_MODIFY, 102, UNLModify, ({
|
||||
TRANSACTION(ttUNL_MODIFY, 102, UNLModify,
|
||||
Delegation::notDelegatable,
|
||||
noPriv, ({
|
||||
{sfUNLModifyDisabling, soeREQUIRED},
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
{sfUNLModifyValidator, soeREQUIRED},
|
||||
|
||||
@@ -20,7 +20,7 @@ struct JsonMissingKeyError : std::exception
|
||||
JsonMissingKeyError(Json::StaticString const& k) : key{k.c_str()}
|
||||
{
|
||||
}
|
||||
const char*
|
||||
char const*
|
||||
what() const noexcept override
|
||||
{
|
||||
if (msg.empty())
|
||||
@@ -40,7 +40,7 @@ struct JsonTypeMismatchError : std::exception
|
||||
: key{k.c_str()}, expectedType{std::move(et)}
|
||||
{
|
||||
}
|
||||
const char*
|
||||
char const*
|
||||
what() const noexcept override
|
||||
{
|
||||
if (msg.empty())
|
||||
|
||||
@@ -95,10 +95,10 @@ JSS(SigningPubKey); // field.
|
||||
JSS(Subject); // in: Credential transactions
|
||||
JSS(TakerGets); // field.
|
||||
JSS(TakerPays); // field.
|
||||
JSS(TxnSignature); // field.
|
||||
JSS(TradingFee); // in/out: AMM trading fee
|
||||
JSS(TransactionType); // in: TransactionSign.
|
||||
JSS(TransferRate); // in: TransferRate.
|
||||
JSS(TxnSignature); // field.
|
||||
JSS(URI); // field.
|
||||
JSS(VoteSlots); // out: AMM Vote
|
||||
JSS(aborted); // out: InboundLedger
|
||||
@@ -145,6 +145,7 @@ JSS(attestations);
|
||||
JSS(attestation_reward_account);
|
||||
JSS(auction_slot); // out: amm_info
|
||||
JSS(authorized); // out: AccountLines
|
||||
JSS(authorize); // out: delegate
|
||||
JSS(authorized_credentials); // in: ledger_entry DepositPreauth
|
||||
JSS(auth_accounts); // out: amm_info
|
||||
JSS(auth_change); // out: AccountInfo
|
||||
@@ -448,6 +449,7 @@ JSS(node_reads_hit); // out: GetCounts
|
||||
JSS(node_reads_total); // out: GetCounts
|
||||
JSS(node_reads_duration_us); // out: GetCounts
|
||||
JSS(node_size); // out: server_info
|
||||
JSS(nodes); // out: VaultInfo
|
||||
JSS(nodestore); // out: GetCounts
|
||||
JSS(node_writes); // out: GetCounts
|
||||
JSS(node_written_bytes); // out: GetCounts
|
||||
@@ -558,6 +560,7 @@ JSS(server_status); // out: NetworkOPs
|
||||
JSS(server_version); // out: NetworkOPs
|
||||
JSS(settle_delay); // out: AccountChannels
|
||||
JSS(severity); // in: LogLevel
|
||||
JSS(shares); // out: VaultInfo
|
||||
JSS(signature); // out: NetworkOPs, ChannelAuthorize
|
||||
JSS(signature_verified); // out: ChannelVerify
|
||||
JSS(signing_key); // out: NetworkOPs
|
||||
@@ -683,6 +686,7 @@ JSS(validations); // out: AmendmentTableImpl
|
||||
JSS(validator_list_threshold); // out: ValidatorList
|
||||
JSS(validator_sites); // out: ValidatorSites
|
||||
JSS(value); // out: STAmount
|
||||
JSS(vault_id); // in: VaultInfo
|
||||
JSS(version); // out: RPCVersion
|
||||
JSS(vetoed); // out: AmendmentTableImpl
|
||||
JSS(volume_a); // out: BookChanges
|
||||
@@ -699,7 +703,7 @@ JSS(write_load); // out: GetCounts
|
||||
#pragma push_macro("TRANSACTION")
|
||||
#undef TRANSACTION
|
||||
|
||||
#define TRANSACTION(tag, value, name, fields) JSS(name);
|
||||
#define TRANSACTION(tag, value, name, ...) JSS(name);
|
||||
|
||||
#include <xrpl/protocol/detail/transactions.macro>
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ extractTarLz4(
|
||||
|
||||
if (archive_entry_size(entry) > 0)
|
||||
{
|
||||
const void* buf;
|
||||
void const* buf;
|
||||
size_t sz;
|
||||
la_int64_t offset;
|
||||
while (true)
|
||||
|
||||
@@ -63,7 +63,7 @@ getFileContents(
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string result{
|
||||
std::string const result{
|
||||
std::istreambuf_iterator<char>{fileStream},
|
||||
std::istreambuf_iterator<char>{}};
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -31,12 +33,13 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#ifdef BOOST_COMP_MSVC
|
||||
#ifdef _MSC_VER
|
||||
#pragma message("Using boost::multiprecision::uint128_t")
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
using uint128_t = boost::multiprecision::uint128_t;
|
||||
#else // !defined(_MSVC_LANG)
|
||||
#else // !defined(_MSC_VER)
|
||||
using uint128_t = __uint128_t;
|
||||
#endif // !defined(_MSVC_LANG)
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -468,7 +471,7 @@ Number::operator/=(Number const& y)
|
||||
}
|
||||
// Shift by 10^17 gives greatest precision while not overflowing uint128_t
|
||||
// or the cast back to int64_t
|
||||
const uint128_t f = 100'000'000'000'000'000;
|
||||
uint128_t const f = 100'000'000'000'000'000;
|
||||
mantissa_ = static_cast<std::int64_t>(uint128_t(nm) * f / uint128_t(dm));
|
||||
exponent_ = ne - de - 17;
|
||||
mantissa_ *= np * dp;
|
||||
|
||||
@@ -89,13 +89,13 @@ parseUrl(parsedURL& pUrl, std::string const& strUrl)
|
||||
boost::algorithm::to_lower(pUrl.scheme);
|
||||
pUrl.username = smMatch[2];
|
||||
pUrl.password = smMatch[3];
|
||||
const std::string domain = smMatch[4];
|
||||
std::string const domain = smMatch[4];
|
||||
// We need to use Endpoint to parse the domain to
|
||||
// strip surrounding brackets from IPv6 addresses,
|
||||
// e.g. [::1] => ::1.
|
||||
const auto result = beast::IP::Endpoint::from_string_checked(domain);
|
||||
auto const result = beast::IP::Endpoint::from_string_checked(domain);
|
||||
pUrl.domain = result ? result->address().to_string() : domain;
|
||||
const std::string port = smMatch[5];
|
||||
std::string const port = smMatch[5];
|
||||
if (!port.empty())
|
||||
{
|
||||
pUrl.port = beast::lexicalCast<std::uint16_t>(port);
|
||||
|
||||
@@ -67,7 +67,7 @@ UptimeClock::time_point
|
||||
UptimeClock::now()
|
||||
{
|
||||
// start the update thread on first use
|
||||
static const auto init = start_clock();
|
||||
static auto const init = start_clock();
|
||||
|
||||
// Return the number of seconds since rippled start
|
||||
return time_point{duration{now_}};
|
||||
|
||||
@@ -31,9 +31,7 @@ namespace ripple {
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div)
|
||||
{
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
uint128_t result;
|
||||
boost::multiprecision::uint128_t result;
|
||||
result = multiply(result, value, mul);
|
||||
|
||||
result /= div;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Json {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<char, const char*> jsonSpecialCharacterEscape = {
|
||||
std::map<char, char const*> jsonSpecialCharacterEscape = {
|
||||
{'"', "\\\""},
|
||||
{'\\', "\\\\"},
|
||||
{'/', "\\/"},
|
||||
@@ -47,13 +47,13 @@ std::map<char, const char*> jsonSpecialCharacterEscape = {
|
||||
static size_t const jsonEscapeLength = 2;
|
||||
|
||||
// All other JSON punctuation.
|
||||
const char closeBrace = '}';
|
||||
const char closeBracket = ']';
|
||||
const char colon = ':';
|
||||
const char comma = ',';
|
||||
const char openBrace = '{';
|
||||
const char openBracket = '[';
|
||||
const char quote = '"';
|
||||
char const closeBrace = '}';
|
||||
char const closeBracket = ']';
|
||||
char const colon = ':';
|
||||
char const comma = ',';
|
||||
char const openBrace = '{';
|
||||
char const openBracket = '[';
|
||||
char const quote = '"';
|
||||
|
||||
static auto const integralFloatsBecomeInts = false;
|
||||
|
||||
|
||||
@@ -78,8 +78,8 @@ bool
|
||||
Reader::parse(std::string const& document, Value& root)
|
||||
{
|
||||
document_ = document;
|
||||
const char* begin = document_.c_str();
|
||||
const char* end = begin + document_.length();
|
||||
char const* begin = document_.c_str();
|
||||
char const* end = begin + document_.length();
|
||||
return parse(begin, end, root);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ Reader::parse(std::istream& sin, Value& root)
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::parse(const char* beginDoc, const char* endDoc, Value& root)
|
||||
Reader::parse(char const* beginDoc, char const* endDoc, Value& root)
|
||||
{
|
||||
begin_ = beginDoc;
|
||||
end_ = endDoc;
|
||||
@@ -193,7 +193,7 @@ Reader::skipCommentTokens(Token& token)
|
||||
}
|
||||
|
||||
bool
|
||||
Reader::expectToken(TokenType type, Token& token, const char* message)
|
||||
Reader::expectToken(TokenType type, Token& token, char const* message)
|
||||
{
|
||||
readToken(token);
|
||||
|
||||
@@ -629,7 +629,7 @@ bool
|
||||
Reader::decodeDouble(Token& token)
|
||||
{
|
||||
double value = 0;
|
||||
const int bufferSize = 32;
|
||||
int const bufferSize = 32;
|
||||
int count;
|
||||
int length = int(token.end_ - token.start_);
|
||||
// Sanity check to avoid buffer overflow exploits.
|
||||
@@ -939,7 +939,7 @@ Reader::getFormatedErrorMessages() const
|
||||
itError != errors_.end();
|
||||
++itError)
|
||||
{
|
||||
const ErrorInfo& error = *itError;
|
||||
ErrorInfo const& error = *itError;
|
||||
formattedMessage +=
|
||||
"* " + getLocationLineAndColumn(error.token_.start_) + "\n";
|
||||
formattedMessage += " " + error.message_ + "\n";
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
|
||||
namespace Json {
|
||||
|
||||
const Value Value::null;
|
||||
const Int Value::minInt = Int(~(UInt(-1) / 2));
|
||||
const Int Value::maxInt = Int(UInt(-1) / 2);
|
||||
const UInt Value::maxUInt = UInt(-1);
|
||||
Value const Value::null;
|
||||
Int const Value::minInt = Int(~(UInt(-1) / 2));
|
||||
Int const Value::maxInt = Int(UInt(-1) / 2);
|
||||
UInt const Value::maxUInt = UInt(-1);
|
||||
|
||||
class DefaultValueAllocator : public ValueAllocator
|
||||
{
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
virtual ~DefaultValueAllocator() = default;
|
||||
|
||||
char*
|
||||
makeMemberName(const char* memberName) override
|
||||
makeMemberName(char const* memberName) override
|
||||
{
|
||||
return duplicateStringValue(memberName);
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
}
|
||||
|
||||
char*
|
||||
duplicateStringValue(const char* value, unsigned int length = unknown)
|
||||
duplicateStringValue(char const* value, unsigned int length = unknown)
|
||||
override
|
||||
{
|
||||
//@todo investigate this old optimization
|
||||
@@ -110,14 +110,14 @@ Value::CZString::CZString(int index) : cstr_(0), index_(index)
|
||||
{
|
||||
}
|
||||
|
||||
Value::CZString::CZString(const char* cstr, DuplicationPolicy allocate)
|
||||
Value::CZString::CZString(char const* cstr, DuplicationPolicy allocate)
|
||||
: cstr_(
|
||||
allocate == duplicate ? valueAllocator()->makeMemberName(cstr) : cstr)
|
||||
, index_(allocate)
|
||||
{
|
||||
}
|
||||
|
||||
Value::CZString::CZString(const CZString& other)
|
||||
Value::CZString::CZString(CZString const& other)
|
||||
: cstr_(
|
||||
other.index_ != noDuplication && other.cstr_ != 0
|
||||
? valueAllocator()->makeMemberName(other.cstr_)
|
||||
@@ -136,7 +136,7 @@ Value::CZString::~CZString()
|
||||
}
|
||||
|
||||
bool
|
||||
Value::CZString::operator<(const CZString& other) const
|
||||
Value::CZString::operator<(CZString const& other) const
|
||||
{
|
||||
if (cstr_ && other.cstr_)
|
||||
return strcmp(cstr_, other.cstr_) < 0;
|
||||
@@ -145,7 +145,7 @@ Value::CZString::operator<(const CZString& other) const
|
||||
}
|
||||
|
||||
bool
|
||||
Value::CZString::operator==(const CZString& other) const
|
||||
Value::CZString::operator==(CZString const& other) const
|
||||
{
|
||||
if (cstr_ && other.cstr_)
|
||||
return strcmp(cstr_, other.cstr_) == 0;
|
||||
@@ -159,7 +159,7 @@ Value::CZString::index() const
|
||||
return index_;
|
||||
}
|
||||
|
||||
const char*
|
||||
char const*
|
||||
Value::CZString::c_str() const
|
||||
{
|
||||
return cstr_;
|
||||
@@ -232,18 +232,25 @@ Value::Value(double value) : type_(realValue)
|
||||
value_.real_ = value;
|
||||
}
|
||||
|
||||
Value::Value(const char* value) : type_(stringValue), allocated_(true)
|
||||
Value::Value(char const* value) : type_(stringValue), allocated_(true)
|
||||
{
|
||||
value_.string_ = valueAllocator()->duplicateStringValue(value);
|
||||
}
|
||||
|
||||
Value::Value(ripple::Number const& value) : type_(stringValue), allocated_(true)
|
||||
{
|
||||
auto const tmp = to_string(value);
|
||||
value_.string_ =
|
||||
valueAllocator()->duplicateStringValue(tmp.c_str(), tmp.length());
|
||||
}
|
||||
|
||||
Value::Value(std::string const& value) : type_(stringValue), allocated_(true)
|
||||
{
|
||||
value_.string_ = valueAllocator()->duplicateStringValue(
|
||||
value.c_str(), (unsigned int)value.length());
|
||||
}
|
||||
|
||||
Value::Value(const StaticString& value) : type_(stringValue), allocated_(false)
|
||||
Value::Value(StaticString const& value) : type_(stringValue), allocated_(false)
|
||||
{
|
||||
value_.string_ = const_cast<char*>(value.c_str());
|
||||
}
|
||||
@@ -253,7 +260,7 @@ Value::Value(bool value) : type_(booleanValue)
|
||||
value_.bool_ = value;
|
||||
}
|
||||
|
||||
Value::Value(const Value& other) : type_(other.type_)
|
||||
Value::Value(Value const& other) : type_(other.type_)
|
||||
{
|
||||
switch (type_)
|
||||
{
|
||||
@@ -370,7 +377,7 @@ integerCmp(Int i, UInt ui)
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(const Value& x, const Value& y)
|
||||
operator<(Value const& x, Value const& y)
|
||||
{
|
||||
if (auto signum = x.type_ - y.type_)
|
||||
{
|
||||
@@ -419,7 +426,7 @@ operator<(const Value& x, const Value& y)
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const Value& x, const Value& y)
|
||||
operator==(Value const& x, Value const& y)
|
||||
{
|
||||
if (x.type_ != y.type_)
|
||||
{
|
||||
@@ -464,7 +471,7 @@ operator==(const Value& x, const Value& y)
|
||||
return 0; // unreachable
|
||||
}
|
||||
|
||||
const char*
|
||||
char const*
|
||||
Value::asCString() const
|
||||
{
|
||||
XRPL_ASSERT(type_ == stringValue, "Json::Value::asCString : valid type");
|
||||
@@ -795,7 +802,7 @@ Value::operator[](UInt index)
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
const Value&
|
||||
Value const&
|
||||
Value::operator[](UInt index) const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
@@ -815,13 +822,13 @@ Value::operator[](UInt index) const
|
||||
}
|
||||
|
||||
Value&
|
||||
Value::operator[](const char* key)
|
||||
Value::operator[](char const* key)
|
||||
{
|
||||
return resolveReference(key, false);
|
||||
}
|
||||
|
||||
Value&
|
||||
Value::resolveReference(const char* key, bool isStatic)
|
||||
Value::resolveReference(char const* key, bool isStatic)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
type_ == nullValue || type_ == objectValue,
|
||||
@@ -844,9 +851,9 @@ Value::resolveReference(const char* key, bool isStatic)
|
||||
}
|
||||
|
||||
Value
|
||||
Value::get(UInt index, const Value& defaultValue) const
|
||||
Value::get(UInt index, Value const& defaultValue) const
|
||||
{
|
||||
const Value* value = &((*this)[index]);
|
||||
Value const* value = &((*this)[index]);
|
||||
return value == &null ? defaultValue : *value;
|
||||
}
|
||||
|
||||
@@ -856,8 +863,8 @@ Value::isValidIndex(UInt index) const
|
||||
return index < size();
|
||||
}
|
||||
|
||||
const Value&
|
||||
Value::operator[](const char* key) const
|
||||
Value const&
|
||||
Value::operator[](char const* key) const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
type_ == nullValue || type_ == objectValue,
|
||||
@@ -881,20 +888,26 @@ Value::operator[](std::string const& key)
|
||||
return (*this)[key.c_str()];
|
||||
}
|
||||
|
||||
const Value&
|
||||
Value const&
|
||||
Value::operator[](std::string const& key) const
|
||||
{
|
||||
return (*this)[key.c_str()];
|
||||
}
|
||||
|
||||
Value&
|
||||
Value::operator[](const StaticString& key)
|
||||
Value::operator[](StaticString const& key)
|
||||
{
|
||||
return resolveReference(key, true);
|
||||
}
|
||||
|
||||
Value const&
|
||||
Value::operator[](StaticString const& key) const
|
||||
{
|
||||
return (*this)[key.c_str()];
|
||||
}
|
||||
|
||||
Value&
|
||||
Value::append(const Value& value)
|
||||
Value::append(Value const& value)
|
||||
{
|
||||
return (*this)[size()] = value;
|
||||
}
|
||||
@@ -906,20 +919,20 @@ Value::append(Value&& value)
|
||||
}
|
||||
|
||||
Value
|
||||
Value::get(const char* key, const Value& defaultValue) const
|
||||
Value::get(char const* key, Value const& defaultValue) const
|
||||
{
|
||||
const Value* value = &((*this)[key]);
|
||||
Value const* value = &((*this)[key]);
|
||||
return value == &null ? defaultValue : *value;
|
||||
}
|
||||
|
||||
Value
|
||||
Value::get(std::string const& key, const Value& defaultValue) const
|
||||
Value::get(std::string const& key, Value const& defaultValue) const
|
||||
{
|
||||
return get(key.c_str(), defaultValue);
|
||||
}
|
||||
|
||||
Value
|
||||
Value::removeMember(const char* key)
|
||||
Value::removeMember(char const* key)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
type_ == nullValue || type_ == objectValue,
|
||||
@@ -946,12 +959,12 @@ Value::removeMember(std::string const& key)
|
||||
}
|
||||
|
||||
bool
|
||||
Value::isMember(const char* key) const
|
||||
Value::isMember(char const* key) const
|
||||
{
|
||||
if (type_ != objectValue)
|
||||
return false;
|
||||
|
||||
const Value* value = &((*this)[key]);
|
||||
Value const* value = &((*this)[key]);
|
||||
return value != &null;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ ValueIteratorBase::ValueIteratorBase() : current_(), isNull_(true)
|
||||
}
|
||||
|
||||
ValueIteratorBase::ValueIteratorBase(
|
||||
const Value::ObjectValues::iterator& current)
|
||||
Value::ObjectValues::iterator const& current)
|
||||
: current_(current), isNull_(false)
|
||||
{
|
||||
}
|
||||
@@ -61,7 +61,7 @@ ValueIteratorBase::decrement()
|
||||
}
|
||||
|
||||
ValueIteratorBase::difference_type
|
||||
ValueIteratorBase::computeDistance(const SelfType& other) const
|
||||
ValueIteratorBase::computeDistance(SelfType const& other) const
|
||||
{
|
||||
// Iterator for null value are initialized using the default
|
||||
// constructor, which initialize current_ to the default
|
||||
@@ -89,7 +89,7 @@ ValueIteratorBase::computeDistance(const SelfType& other) const
|
||||
}
|
||||
|
||||
bool
|
||||
ValueIteratorBase::isEqual(const SelfType& other) const
|
||||
ValueIteratorBase::isEqual(SelfType const& other) const
|
||||
{
|
||||
if (isNull_)
|
||||
{
|
||||
@@ -100,7 +100,7 @@ ValueIteratorBase::isEqual(const SelfType& other) const
|
||||
}
|
||||
|
||||
void
|
||||
ValueIteratorBase::copy(const SelfType& other)
|
||||
ValueIteratorBase::copy(SelfType const& other)
|
||||
{
|
||||
current_ = other.current_;
|
||||
}
|
||||
@@ -108,7 +108,7 @@ ValueIteratorBase::copy(const SelfType& other)
|
||||
Value
|
||||
ValueIteratorBase::key() const
|
||||
{
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
Value::CZString const czstring = (*current_).first;
|
||||
|
||||
if (czstring.c_str())
|
||||
{
|
||||
@@ -124,7 +124,7 @@ ValueIteratorBase::key() const
|
||||
UInt
|
||||
ValueIteratorBase::index() const
|
||||
{
|
||||
const Value::CZString czstring = (*current_).first;
|
||||
Value::CZString const czstring = (*current_).first;
|
||||
|
||||
if (!czstring.c_str())
|
||||
return czstring.index();
|
||||
@@ -132,10 +132,10 @@ ValueIteratorBase::index() const
|
||||
return Value::UInt(-1);
|
||||
}
|
||||
|
||||
const char*
|
||||
char const*
|
||||
ValueIteratorBase::memberName() const
|
||||
{
|
||||
const char* name = (*current_).first.c_str();
|
||||
char const* name = (*current_).first.c_str();
|
||||
return name ? name : "";
|
||||
}
|
||||
|
||||
@@ -148,13 +148,13 @@ ValueIteratorBase::memberName() const
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueConstIterator::ValueConstIterator(
|
||||
const Value::ObjectValues::iterator& current)
|
||||
Value::ObjectValues::iterator const& current)
|
||||
: ValueIteratorBase(current)
|
||||
{
|
||||
}
|
||||
|
||||
ValueConstIterator&
|
||||
ValueConstIterator::operator=(const ValueIteratorBase& other)
|
||||
ValueConstIterator::operator=(ValueIteratorBase const& other)
|
||||
{
|
||||
copy(other);
|
||||
return *this;
|
||||
@@ -168,23 +168,23 @@ ValueConstIterator::operator=(const ValueIteratorBase& other)
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
|
||||
ValueIterator::ValueIterator(Value::ObjectValues::iterator const& current)
|
||||
: ValueIteratorBase(current)
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator(const ValueConstIterator& other)
|
||||
ValueIterator::ValueIterator(ValueConstIterator const& other)
|
||||
: ValueIteratorBase(other)
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator::ValueIterator(const ValueIterator& other)
|
||||
ValueIterator::ValueIterator(ValueIterator const& other)
|
||||
: ValueIteratorBase(other)
|
||||
{
|
||||
}
|
||||
|
||||
ValueIterator&
|
||||
ValueIterator::operator=(const SelfType& other)
|
||||
ValueIterator::operator=(SelfType const& other)
|
||||
{
|
||||
copy(other);
|
||||
return *this;
|
||||
|
||||
@@ -40,7 +40,7 @@ isControlCharacter(char ch)
|
||||
}
|
||||
|
||||
static bool
|
||||
containsControlCharacter(const char* str)
|
||||
containsControlCharacter(char const* str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
@@ -117,7 +117,7 @@ valueToString(bool value)
|
||||
}
|
||||
|
||||
std::string
|
||||
valueToQuotedString(const char* value)
|
||||
valueToQuotedString(char const* value)
|
||||
{
|
||||
// Not sure how to handle unicode...
|
||||
if (strpbrk(value, "\"\\\b\f\n\r\t") == nullptr &&
|
||||
@@ -132,7 +132,7 @@ valueToQuotedString(const char* value)
|
||||
result.reserve(maxsize); // to avoid lots of mallocs
|
||||
result += "\"";
|
||||
|
||||
for (const char* c = value; *c != 0; ++c)
|
||||
for (char const* c = value; *c != 0; ++c)
|
||||
{
|
||||
switch (*c)
|
||||
{
|
||||
@@ -197,7 +197,7 @@ valueToQuotedString(const char* value)
|
||||
// //////////////////////////////////////////////////////////////////
|
||||
|
||||
std::string
|
||||
FastWriter::write(const Value& root)
|
||||
FastWriter::write(Value const& root)
|
||||
{
|
||||
document_ = "";
|
||||
writeValue(root);
|
||||
@@ -205,7 +205,7 @@ FastWriter::write(const Value& root)
|
||||
}
|
||||
|
||||
void
|
||||
FastWriter::writeValue(const Value& value)
|
||||
FastWriter::writeValue(Value const& value)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
@@ -281,7 +281,7 @@ StyledWriter::StyledWriter() : rightMargin_(74), indentSize_(3)
|
||||
}
|
||||
|
||||
std::string
|
||||
StyledWriter::write(const Value& root)
|
||||
StyledWriter::write(Value const& root)
|
||||
{
|
||||
document_ = "";
|
||||
addChildValues_ = false;
|
||||
@@ -292,7 +292,7 @@ StyledWriter::write(const Value& root)
|
||||
}
|
||||
|
||||
void
|
||||
StyledWriter::writeValue(const Value& value)
|
||||
StyledWriter::writeValue(Value const& value)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
@@ -338,7 +338,7 @@ StyledWriter::writeValue(const Value& value)
|
||||
while (true)
|
||||
{
|
||||
std::string const& name = *it;
|
||||
const Value& childValue = value[name];
|
||||
Value const& childValue = value[name];
|
||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
||||
document_ += " : ";
|
||||
writeValue(childValue);
|
||||
@@ -358,7 +358,7 @@ StyledWriter::writeValue(const Value& value)
|
||||
}
|
||||
|
||||
void
|
||||
StyledWriter::writeArrayValue(const Value& value)
|
||||
StyledWriter::writeArrayValue(Value const& value)
|
||||
{
|
||||
unsigned size = value.size();
|
||||
|
||||
@@ -377,7 +377,7 @@ StyledWriter::writeArrayValue(const Value& value)
|
||||
|
||||
while (true)
|
||||
{
|
||||
const Value& childValue = value[index];
|
||||
Value const& childValue = value[index];
|
||||
|
||||
if (hasChildValue)
|
||||
writeWithIndent(childValues_[index]);
|
||||
@@ -417,7 +417,7 @@ StyledWriter::writeArrayValue(const Value& value)
|
||||
}
|
||||
|
||||
bool
|
||||
StyledWriter::isMultineArray(const Value& value)
|
||||
StyledWriter::isMultineArray(Value const& value)
|
||||
{
|
||||
int size = value.size();
|
||||
bool isMultiLine = size * 3 >= rightMargin_;
|
||||
@@ -425,7 +425,7 @@ StyledWriter::isMultineArray(const Value& value)
|
||||
|
||||
for (int index = 0; index < size && !isMultiLine; ++index)
|
||||
{
|
||||
const Value& childValue = value[index];
|
||||
Value const& childValue = value[index];
|
||||
isMultiLine = isMultiLine ||
|
||||
((childValue.isArray() || childValue.isObject()) &&
|
||||
childValue.size() > 0);
|
||||
@@ -507,7 +507,7 @@ StyledStreamWriter::StyledStreamWriter(std::string indentation)
|
||||
}
|
||||
|
||||
void
|
||||
StyledStreamWriter::write(std::ostream& out, const Value& root)
|
||||
StyledStreamWriter::write(std::ostream& out, Value const& root)
|
||||
{
|
||||
document_ = &out;
|
||||
addChildValues_ = false;
|
||||
@@ -518,7 +518,7 @@ StyledStreamWriter::write(std::ostream& out, const Value& root)
|
||||
}
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeValue(const Value& value)
|
||||
StyledStreamWriter::writeValue(Value const& value)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
@@ -564,7 +564,7 @@ StyledStreamWriter::writeValue(const Value& value)
|
||||
while (true)
|
||||
{
|
||||
std::string const& name = *it;
|
||||
const Value& childValue = value[name];
|
||||
Value const& childValue = value[name];
|
||||
writeWithIndent(valueToQuotedString(name.c_str()));
|
||||
*document_ << " : ";
|
||||
writeValue(childValue);
|
||||
@@ -584,7 +584,7 @@ StyledStreamWriter::writeValue(const Value& value)
|
||||
}
|
||||
|
||||
void
|
||||
StyledStreamWriter::writeArrayValue(const Value& value)
|
||||
StyledStreamWriter::writeArrayValue(Value const& value)
|
||||
{
|
||||
unsigned size = value.size();
|
||||
|
||||
@@ -603,7 +603,7 @@ StyledStreamWriter::writeArrayValue(const Value& value)
|
||||
|
||||
while (true)
|
||||
{
|
||||
const Value& childValue = value[index];
|
||||
Value const& childValue = value[index];
|
||||
|
||||
if (hasChildValue)
|
||||
writeWithIndent(childValues_[index]);
|
||||
@@ -643,7 +643,7 @@ StyledStreamWriter::writeArrayValue(const Value& value)
|
||||
}
|
||||
|
||||
bool
|
||||
StyledStreamWriter::isMultineArray(const Value& value)
|
||||
StyledStreamWriter::isMultineArray(Value const& value)
|
||||
{
|
||||
int size = value.size();
|
||||
bool isMultiLine = size * 3 >= rightMargin_;
|
||||
@@ -651,7 +651,7 @@ StyledStreamWriter::isMultineArray(const Value& value)
|
||||
|
||||
for (int index = 0; index < size && !isMultiLine; ++index)
|
||||
{
|
||||
const Value& childValue = value[index];
|
||||
Value const& childValue = value[index];
|
||||
isMultiLine = isMultiLine ||
|
||||
((childValue.isArray() || childValue.isObject()) &&
|
||||
childValue.size() > 0);
|
||||
@@ -726,7 +726,7 @@ StyledStreamWriter::unindent()
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& sout, const Value& root)
|
||||
operator<<(std::ostream& sout, Value const& root)
|
||||
{
|
||||
Json::StyledStreamWriter writer;
|
||||
writer.write(sout, root);
|
||||
|
||||
@@ -39,18 +39,6 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
AccountID
|
||||
ammAccountID(
|
||||
std::uint16_t prefix,
|
||||
uint256 const& parentHash,
|
||||
uint256 const& ammID)
|
||||
{
|
||||
ripesha_hasher rsh;
|
||||
auto const hash = sha512Half(prefix, parentHash, ammID);
|
||||
rsh(hash.data(), hash.size());
|
||||
return AccountID{static_cast<ripesha_hasher::result_type>(rsh)};
|
||||
}
|
||||
|
||||
Currency
|
||||
ammLPTCurrency(Currency const& cur1, Currency const& cur2)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -51,6 +52,12 @@ Asset::setJson(Json::Value& jv) const
|
||||
std::visit([&](auto&& issue) { issue.setJson(jv); }, issue_);
|
||||
}
|
||||
|
||||
STAmount
|
||||
Asset::operator()(Number const& number) const
|
||||
{
|
||||
return STAmount{*this, number};
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string(Asset const& asset)
|
||||
{
|
||||
@@ -78,11 +85,4 @@ assetFromJson(Json::Value const& v)
|
||||
return mptIssueFromJson(v);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
to_json(Asset const& asset)
|
||||
{
|
||||
return std::visit(
|
||||
[&](auto const& issue) { return to_json(issue); }, asset.value());
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -96,6 +96,7 @@ constexpr static ErrorInfo unorderedErrorInfos[]{
|
||||
{rpcNOT_SYNCED, "notSynced", "Not synced to the network.", 503},
|
||||
{rpcNO_EVENTS, "noEvents", "Current transport does not support events.", 405},
|
||||
{rpcNO_NETWORK, "noNetwork", "Not synced to the network.", 503},
|
||||
{rpcWRONG_NETWORK, "wrongNetwork", "Wrong network.", 503},
|
||||
{rpcNO_PERMISSION, "noPermission", "You don't have permission for this command.", 401},
|
||||
{rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress.", 404},
|
||||
{rpcOBJECT_NOT_FOUND, "objectNotFound", "The requested object was not found.", 404},
|
||||
@@ -106,6 +107,7 @@ constexpr static ErrorInfo unorderedErrorInfos[]{
|
||||
{rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed.", 400},
|
||||
{rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided.", 400},
|
||||
{rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found.", 404},
|
||||
{rpcDELEGATE_ACT_NOT_FOUND, "delegateActNotFound", "Delegate account not found.", 404},
|
||||
{rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed.", 400},
|
||||
{rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed.", 400},
|
||||
{rpcSTREAM_MALFORMED, "malformedStream", "Stream malformed.", 400},
|
||||
|
||||
@@ -139,27 +139,27 @@ class FeatureCollections
|
||||
{
|
||||
if (i >= features.size())
|
||||
LogicError("Invalid FeatureBitset index");
|
||||
const auto& sequence = features.get<Feature::byIndex>();
|
||||
auto const& sequence = features.get<Feature::byIndex>();
|
||||
return sequence[i];
|
||||
}
|
||||
size_t
|
||||
getIndex(Feature const& feature) const
|
||||
{
|
||||
const auto& sequence = features.get<Feature::byIndex>();
|
||||
auto const& sequence = features.get<Feature::byIndex>();
|
||||
auto const it_to = sequence.iterator_to(feature);
|
||||
return it_to - sequence.begin();
|
||||
}
|
||||
Feature const*
|
||||
getByFeature(uint256 const& feature) const
|
||||
{
|
||||
const auto& feature_index = features.get<Feature::byFeature>();
|
||||
auto const& feature_index = features.get<Feature::byFeature>();
|
||||
auto const feature_it = feature_index.find(feature);
|
||||
return feature_it == feature_index.end() ? nullptr : &*feature_it;
|
||||
}
|
||||
Feature const*
|
||||
getByName(std::string const& name) const
|
||||
{
|
||||
const auto& name_index = features.get<Feature::byName>();
|
||||
auto const& name_index = features.get<Feature::byName>();
|
||||
auto const name_it = name_index.find(name);
|
||||
return name_it == name_index.end() ? nullptr : &*name_it;
|
||||
}
|
||||
@@ -240,7 +240,7 @@ FeatureCollections::getRegisteredFeature(std::string const& name) const
|
||||
}
|
||||
|
||||
void
|
||||
check(bool condition, const char* logicErrorMessage)
|
||||
check(bool condition, char const* logicErrorMessage)
|
||||
{
|
||||
if (!condition)
|
||||
LogicError(logicErrorMessage);
|
||||
@@ -437,9 +437,13 @@ featureToName(uint256 const& f)
|
||||
uint256 const feature##name = registerFeature(#name, supported, vote);
|
||||
#define XRPL_FIX(name, supported, vote) \
|
||||
uint256 const fix##name = registerFeature("fix" #name, supported, vote);
|
||||
#define XRPL_RETIRE(name) \
|
||||
[[deprecated("The referenced amendment has been retired"), maybe_unused]] \
|
||||
|
||||
// clang-format off
|
||||
#define XRPL_RETIRE(name) \
|
||||
[[deprecated("The referenced amendment has been retired")]] \
|
||||
[[maybe_unused]] \
|
||||
uint256 const retired##name = retireFeature(#name);
|
||||
// clang-format on
|
||||
|
||||
#include <xrpl/protocol/detail/features.macro>
|
||||
|
||||
@@ -455,7 +459,7 @@ featureToName(uint256 const& f)
|
||||
//
|
||||
// Use initialization of one final static variable to set
|
||||
// featureCollections::readOnly.
|
||||
[[maybe_unused]] static const bool readOnlySet =
|
||||
[[maybe_unused]] static bool const readOnlySet =
|
||||
featureCollections.registrationIsDone();
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -94,6 +94,10 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
MPTOKEN = 't',
|
||||
CREDENTIAL = 'D',
|
||||
PERMISSIONED_DOMAIN = 'm',
|
||||
DELEGATE = 'E',
|
||||
VAULT = 'V',
|
||||
LOAN_BROKER = 'l', // lower-case L
|
||||
LOAN = 'L',
|
||||
|
||||
// No longer used or supported. Left here to reserve the space
|
||||
// to avoid accidental reuse.
|
||||
@@ -452,6 +456,14 @@ amm(uint256 const& id) noexcept
|
||||
return {ltAMM, id};
|
||||
}
|
||||
|
||||
Keylet
|
||||
delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept
|
||||
{
|
||||
return {
|
||||
ltDELEGATE,
|
||||
indexHash(LedgerNameSpace::DELEGATE, account, authorizedAccount)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType)
|
||||
{
|
||||
@@ -543,6 +555,24 @@ credential(
|
||||
indexHash(LedgerNameSpace::CREDENTIAL, subject, issuer, credType)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
vault(AccountID const& owner, std::uint32_t seq) noexcept
|
||||
{
|
||||
return vault(indexHash(LedgerNameSpace::VAULT, owner, seq));
|
||||
}
|
||||
|
||||
Keylet
|
||||
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept
|
||||
{
|
||||
return loanbroker(indexHash(LedgerNameSpace::LOAN_BROKER, owner, seq));
|
||||
}
|
||||
|
||||
Keylet
|
||||
loan(uint256 const& loanBrokerID, std::uint32_t loanSeq) noexcept
|
||||
{
|
||||
return loan(indexHash(LedgerNameSpace::LOAN, loanBrokerID, loanSeq));
|
||||
}
|
||||
|
||||
Keylet
|
||||
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept
|
||||
{
|
||||
|
||||
@@ -154,6 +154,18 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
});
|
||||
|
||||
add(sfPermission.jsonName.c_str(),
|
||||
sfPermission.getCode(),
|
||||
{{sfPermissionValue, soeREQUIRED}});
|
||||
|
||||
add(sfCounterpartySignature.jsonName,
|
||||
sfCounterpartySignature.getCode(),
|
||||
{
|
||||
{sfSigningPubKey, soeOPTIONAL},
|
||||
{sfTxnSignature, soeOPTIONAL},
|
||||
{sfSigners, soeOPTIONAL},
|
||||
});
|
||||
}
|
||||
|
||||
InnerObjectFormats const&
|
||||
|
||||
@@ -37,7 +37,7 @@ Keylet::check(STLedgerEntry const& sle) const
|
||||
if (type == ltCHILD)
|
||||
return sle.getType() != ltDIR_NODE;
|
||||
|
||||
return sle.getType() == type;
|
||||
return sle.getType() == type && sle.key() == key;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ripple {
|
||||
LedgerFormats::LedgerFormats()
|
||||
{
|
||||
// Fields shared by all ledger formats:
|
||||
static const std::initializer_list<SOElement> commonFields{
|
||||
static std::initializer_list<SOElement> const commonFields{
|
||||
{sfLedgerIndex, soeOPTIONAL},
|
||||
{sfLedgerEntryType, soeREQUIRED},
|
||||
{sfFlags, soeREQUIRED},
|
||||
|
||||
@@ -48,12 +48,6 @@ MPTIssue::getIssuer() const
|
||||
return *account;
|
||||
}
|
||||
|
||||
MPTID const&
|
||||
MPTIssue::getMptID() const
|
||||
{
|
||||
return mptID_;
|
||||
}
|
||||
|
||||
std::string
|
||||
MPTIssue::getText() const
|
||||
{
|
||||
|
||||
148
src/libxrpl/protocol/Permissions.cpp
Normal file
148
src/libxrpl/protocol/Permissions.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/Permissions.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
Permission::Permission()
|
||||
{
|
||||
delegatableTx_ = {
|
||||
#pragma push_macro("TRANSACTION")
|
||||
#undef TRANSACTION
|
||||
|
||||
#define TRANSACTION(tag, value, name, delegatable, ...) {value, delegatable},
|
||||
|
||||
#include <xrpl/protocol/detail/transactions.macro>
|
||||
|
||||
#undef TRANSACTION
|
||||
#pragma pop_macro("TRANSACTION")
|
||||
};
|
||||
|
||||
granularPermissionMap_ = {
|
||||
#pragma push_macro("PERMISSION")
|
||||
#undef PERMISSION
|
||||
|
||||
#define PERMISSION(type, txType, value) {#type, type},
|
||||
|
||||
#include <xrpl/protocol/detail/permissions.macro>
|
||||
|
||||
#undef PERMISSION
|
||||
#pragma pop_macro("PERMISSION")
|
||||
};
|
||||
|
||||
granularNameMap_ = {
|
||||
#pragma push_macro("PERMISSION")
|
||||
#undef PERMISSION
|
||||
|
||||
#define PERMISSION(type, txType, value) {type, #type},
|
||||
|
||||
#include <xrpl/protocol/detail/permissions.macro>
|
||||
|
||||
#undef PERMISSION
|
||||
#pragma pop_macro("PERMISSION")
|
||||
};
|
||||
|
||||
granularTxTypeMap_ = {
|
||||
#pragma push_macro("PERMISSION")
|
||||
#undef PERMISSION
|
||||
|
||||
#define PERMISSION(type, txType, value) {type, txType},
|
||||
|
||||
#include <xrpl/protocol/detail/permissions.macro>
|
||||
|
||||
#undef PERMISSION
|
||||
#pragma pop_macro("PERMISSION")
|
||||
};
|
||||
|
||||
for ([[maybe_unused]] auto const& permission : granularPermissionMap_)
|
||||
XRPL_ASSERT(
|
||||
permission.second > UINT16_MAX,
|
||||
"ripple::Permission::granularPermissionMap_ : granular permission "
|
||||
"value must not exceed the maximum uint16_t value.");
|
||||
}
|
||||
|
||||
Permission const&
|
||||
Permission::getInstance()
|
||||
{
|
||||
static Permission const instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t>
|
||||
Permission::getGranularValue(std::string const& name) const
|
||||
{
|
||||
auto const it = granularPermissionMap_.find(name);
|
||||
if (it != granularPermissionMap_.end())
|
||||
return static_cast<uint32_t>(it->second);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
Permission::getGranularName(GranularPermissionType const& value) const
|
||||
{
|
||||
auto const it = granularNameMap_.find(value);
|
||||
if (it != granularNameMap_.end())
|
||||
return it->second;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TxType>
|
||||
Permission::getGranularTxType(GranularPermissionType const& gpType) const
|
||||
{
|
||||
auto const it = granularTxTypeMap_.find(gpType);
|
||||
if (it != granularTxTypeMap_.end())
|
||||
return it->second;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool
|
||||
Permission::isDelegatable(std::uint32_t const& permissionValue) const
|
||||
{
|
||||
auto const granularPermission =
|
||||
getGranularName(static_cast<GranularPermissionType>(permissionValue));
|
||||
if (granularPermission)
|
||||
// granular permissions are always allowed to be delegated
|
||||
return true;
|
||||
|
||||
auto const it = delegatableTx_.find(permissionValue - 1);
|
||||
if (it != delegatableTx_.end() && it->second == Delegation::notDelegatable)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Permission::txToPermissionType(TxType const& type) const
|
||||
{
|
||||
return static_cast<uint32_t>(type) + 1;
|
||||
}
|
||||
|
||||
TxType
|
||||
Permission::permissionToTxType(uint32_t const& value) const
|
||||
{
|
||||
return static_cast<TxType>(value - 1);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -183,7 +183,7 @@ Quality
|
||||
Quality::round(int digits) const
|
||||
{
|
||||
// Modulus for mantissa
|
||||
static const std::uint64_t mod[17] = {
|
||||
static std::uint64_t const mod[17] = {
|
||||
/* 0 */ 10000000000000000,
|
||||
/* 1 */ 1000000000000000,
|
||||
/* 2 */ 100000000000000,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
|
||||
#include <map>
|
||||
@@ -28,6 +29,7 @@ namespace ripple {
|
||||
SField::IsSigning const SField::notSigning;
|
||||
int SField::num = 0;
|
||||
std::map<int, SField const*> SField::knownCodeToField;
|
||||
std::map<std::string, SField const*> SField::knownNameToField;
|
||||
|
||||
// Give only this translation unit permission to construct SFields
|
||||
struct SField::private_access_tag_t
|
||||
@@ -45,7 +47,7 @@ TypedField<T>::TypedField(private_access_tag_t pat, Args&&... args)
|
||||
}
|
||||
|
||||
// Construct all compile-time SFields, and register them in the knownCodeToField
|
||||
// database:
|
||||
// and knownNameToField databases:
|
||||
|
||||
// Use macros for most SField construction to enforce naming conventions.
|
||||
#pragma push_macro("UNTYPED_SFIELD")
|
||||
@@ -87,7 +89,7 @@ SField::SField(
|
||||
private_access_tag_t,
|
||||
SerializedTypeID tid,
|
||||
int fv,
|
||||
const char* fn,
|
||||
char const* fn,
|
||||
int meta,
|
||||
IsSigning signing)
|
||||
: fieldCode(field_code(tid, fv))
|
||||
@@ -99,7 +101,14 @@ SField::SField(
|
||||
, signingField(signing)
|
||||
, jsonName(fieldName.c_str())
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
!knownCodeToField.contains(fieldCode),
|
||||
"ripple::SField::SField(tid,fv,fn,meta,signing) : fieldCode is unique");
|
||||
XRPL_ASSERT(
|
||||
!knownNameToField.contains(fieldName),
|
||||
"ripple::SField::SField(tid,fv,fn,meta,signing) : fieldName is unique");
|
||||
knownCodeToField[fieldCode] = this;
|
||||
knownNameToField[fieldName] = this;
|
||||
}
|
||||
|
||||
SField::SField(private_access_tag_t, int fc)
|
||||
@@ -111,6 +120,9 @@ SField::SField(private_access_tag_t, int fc)
|
||||
, signingField(IsSigning::yes)
|
||||
, jsonName(fieldName.c_str())
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
!knownCodeToField.contains(fieldCode),
|
||||
"ripple::SField::SField(fc) : fieldCode is unique");
|
||||
knownCodeToField[fieldCode] = this;
|
||||
}
|
||||
|
||||
@@ -145,11 +157,11 @@ SField::compare(SField const& f1, SField const& f2)
|
||||
SField const&
|
||||
SField::getField(std::string const& fieldName)
|
||||
{
|
||||
for (auto const& [_, f] : knownCodeToField)
|
||||
auto it = knownNameToField.find(fieldName);
|
||||
|
||||
if (it != knownNameToField.end())
|
||||
{
|
||||
(void)_;
|
||||
if (f->fieldName == fieldName)
|
||||
return *f;
|
||||
return *(it->second);
|
||||
}
|
||||
return sfInvalid;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user