mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-01 00:15:51 +00:00
Compare commits
20 Commits
ab9644267d
...
a1q123456/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84e729bc74 | ||
|
|
7af195781c | ||
|
|
628c3c59aa | ||
|
|
73086872f0 | ||
|
|
c00432cc0b | ||
|
|
47b5c0367c | ||
|
|
e6dfddfc30 | ||
|
|
3fa9a9fa38 | ||
|
|
7796b453c2 | ||
|
|
30530e42de | ||
|
|
c4450dc54f | ||
|
|
304c4ceb9e | ||
|
|
e7633c939a | ||
|
|
70ce254511 | ||
|
|
9248f60a09 | ||
|
|
888b97346e | ||
|
|
9dbc4e1c64 | ||
|
|
1bd3d227ff | ||
|
|
31a127eddc | ||
|
|
d1b36dcbd9 |
28
.github/actions/build-deps/action.yml
vendored
28
.github/actions/build-deps/action.yml
vendored
@@ -10,40 +10,24 @@ inputs:
|
||||
build_type:
|
||||
description: 'The build type to use ("Debug", "Release").'
|
||||
required: true
|
||||
build_nproc:
|
||||
description: "The number of processors to use for building."
|
||||
required: true
|
||||
force_build:
|
||||
description: 'Force building of all dependencies ("true", "false").'
|
||||
required: false
|
||||
default: "false"
|
||||
log_verbosity:
|
||||
description: "The logging verbosity."
|
||||
required: false
|
||||
default: "verbose"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install Conan dependencies
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_DIR: ${{ inputs.build_dir }}
|
||||
BUILD_NPROC: ${{ inputs.build_nproc }}
|
||||
BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }}
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
LOG_VERBOSITY: ${{ inputs.log_verbosity }}
|
||||
run: |
|
||||
echo 'Installing dependencies.'
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
cd "${BUILD_DIR}"
|
||||
mkdir -p ${{ inputs.build_dir }}
|
||||
cd ${{ inputs.build_dir }}
|
||||
conan install \
|
||||
--output-folder . \
|
||||
--build="${BUILD_OPTION}" \
|
||||
--options:host='&:tests=True' \
|
||||
--options:host='&:xrpld=True' \
|
||||
--settings:all build_type="${BUILD_TYPE}" \
|
||||
--conf:all tools.build:jobs=${BUILD_NPROC} \
|
||||
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
|
||||
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
|
||||
--build ${{ inputs.force_build == 'true' && '"*"' || 'missing' }} \
|
||||
--options:host '&:tests=True' \
|
||||
--options:host '&:xrpld=True' \
|
||||
--settings:all build_type=${{ inputs.build_type }} \
|
||||
..
|
||||
|
||||
96
.github/actions/build-test/action.yml
vendored
Normal file
96
.github/actions/build-test/action.yml
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
# This action build and tests the binary. The Conan dependencies must have
|
||||
# already been installed (see the build-deps action).
|
||||
name: Build and Test
|
||||
description: "Build and test the binary."
|
||||
|
||||
# Note that actions do not support 'type' and all inputs are strings, see
|
||||
# https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax#inputs.
|
||||
inputs:
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
required: true
|
||||
build_only:
|
||||
description: 'Whether to only build or to build and test the code ("true", "false").'
|
||||
required: false
|
||||
default: "false"
|
||||
build_type:
|
||||
description: 'The build type to use ("Debug", "Release").'
|
||||
required: true
|
||||
cmake_args:
|
||||
description: "Additional arguments to pass to CMake."
|
||||
required: false
|
||||
default: ""
|
||||
cmake_target:
|
||||
description: "The CMake target to build."
|
||||
required: true
|
||||
codecov_token:
|
||||
description: "The Codecov token to use for uploading coverage reports."
|
||||
required: false
|
||||
default: ""
|
||||
os:
|
||||
description: 'The operating system to use for the build ("linux", "macos", "windows").'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
run: |
|
||||
echo 'Configuring CMake.'
|
||||
cmake \
|
||||
-G '${{ inputs.os == 'windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=${{ inputs.build_type }} \
|
||||
${{ inputs.cmake_args }} \
|
||||
..
|
||||
- name: Build the binary
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
run: |
|
||||
echo 'Building binary.'
|
||||
cmake \
|
||||
--build . \
|
||||
--config ${{ inputs.build_type }} \
|
||||
--parallel $(nproc) \
|
||||
--target ${{ inputs.cmake_target }}
|
||||
- name: Check linking
|
||||
if: ${{ inputs.os == 'linux' }}
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
run: |
|
||||
echo 'Checking linking.'
|
||||
ldd ./rippled
|
||||
if [ "$(ldd ./rippled | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then
|
||||
echo 'The binary is statically linked.'
|
||||
else
|
||||
echo 'The binary is dynamically linked.'
|
||||
exit 1
|
||||
fi
|
||||
- name: Verify voidstar
|
||||
if: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
run: |
|
||||
echo 'Verifying presence of instrumentation.'
|
||||
./rippled --version | grep libvoidstar
|
||||
- name: Test the binary
|
||||
if: ${{ inputs.build_only == 'false' }}
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.build_dir }}/${{ inputs.os == 'windows' && inputs.build_type || '' }}
|
||||
run: |
|
||||
echo 'Testing binary.'
|
||||
./rippled --unittest --unittest-jobs $(nproc)
|
||||
ctest -j $(nproc) --output-on-failure
|
||||
- name: Upload coverage report
|
||||
if: ${{ inputs.cmake_target == 'coverage' }}
|
||||
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
|
||||
with:
|
||||
disable_search: true
|
||||
disable_telem: true
|
||||
fail_ci_if_error: true
|
||||
files: ${{ inputs.build_dir }}/coverage.xml
|
||||
plugins: noop
|
||||
token: ${{ inputs.codecov_token }}
|
||||
verbose: true
|
||||
43
.github/actions/print-env/action.yml
vendored
43
.github/actions/print-env/action.yml
vendored
@@ -1,43 +0,0 @@
|
||||
name: Print build environment
|
||||
description: "Print environment and some tooling versions"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Check configuration (Windows)
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'Checking environment variables.'
|
||||
set
|
||||
|
||||
echo 'Checking CMake version.'
|
||||
cmake --version
|
||||
|
||||
echo 'Checking Conan version.'
|
||||
conan --version
|
||||
|
||||
- name: Check configuration (Linux and macOS)
|
||||
if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo 'Checking path.'
|
||||
echo ${PATH} | tr ':' '\n'
|
||||
|
||||
echo 'Checking environment variables.'
|
||||
env | sort
|
||||
|
||||
echo 'Checking CMake version.'
|
||||
cmake --version
|
||||
|
||||
echo 'Checking compiler version.'
|
||||
${{ runner.os == 'Linux' && '${CC}' || 'clang' }} --version
|
||||
|
||||
echo 'Checking Conan version.'
|
||||
conan --version
|
||||
|
||||
echo 'Checking Ninja version.'
|
||||
ninja --version
|
||||
|
||||
echo 'Checking nproc version.'
|
||||
nproc --version
|
||||
7
.github/actions/setup-conan/action.yml
vendored
7
.github/actions/setup-conan/action.yml
vendored
@@ -35,12 +35,9 @@ runs:
|
||||
|
||||
- name: Set up Conan remote
|
||||
shell: bash
|
||||
env:
|
||||
CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }}
|
||||
CONAN_REMOTE_URL: ${{ inputs.conan_remote_url }}
|
||||
run: |
|
||||
echo "Adding Conan remote '${CONAN_REMOTE_NAME}' at '${CONAN_REMOTE_URL}'."
|
||||
conan remote add --index 0 --force "${CONAN_REMOTE_NAME}" "${CONAN_REMOTE_URL}"
|
||||
echo "Adding Conan remote '${{ inputs.conan_remote_name }}' at ${{ inputs.conan_remote_url }}."
|
||||
conan remote add --index 0 --force ${{ inputs.conan_remote_name }} ${{ inputs.conan_remote_url }}
|
||||
|
||||
echo 'Listing Conan remotes.'
|
||||
conan remote list
|
||||
|
||||
6
.github/scripts/levelization/README.md
vendored
6
.github/scripts/levelization/README.md
vendored
@@ -72,15 +72,15 @@ It generates many files of [results](results):
|
||||
desired as described above. In a perfect repo, this file will be
|
||||
empty.
|
||||
This file is committed to the repo, and is used by the [levelization
|
||||
Github workflow](../../workflows/reusable-check-levelization.yml) to validate
|
||||
Github workflow](../../workflows/check-levelization.yml) to validate
|
||||
that nothing changed.
|
||||
- [`ordering.txt`](results/ordering.txt): A list showing relationships
|
||||
between modules where there are no loops as they actually exist, as
|
||||
opposed to how they are desired as described above.
|
||||
This file is committed to the repo, and is used by the [levelization
|
||||
Github workflow](../../workflows/reusable-check-levelization.yml) to validate
|
||||
Github workflow](../../workflows/check-levelization.yml) to validate
|
||||
that nothing changed.
|
||||
- [`levelization.yml`](../../workflows/reusable-check-levelization.yml)
|
||||
- [`levelization.yml`](../../workflows/check-levelization.yml)
|
||||
Github Actions workflow to test that levelization loops haven't
|
||||
changed. Unfortunately, if changes are detected, it can't tell if
|
||||
they are improvements or not, so if you have resolved any issues or
|
||||
|
||||
@@ -17,7 +17,7 @@ Loop: xrpld.app xrpld.rpc
|
||||
xrpld.rpc > xrpld.app
|
||||
|
||||
Loop: xrpld.app xrpld.shamap
|
||||
xrpld.shamap ~= xrpld.app
|
||||
xrpld.app > xrpld.shamap
|
||||
|
||||
Loop: xrpld.core xrpld.perflog
|
||||
xrpld.perflog == xrpld.core
|
||||
|
||||
@@ -8,10 +8,6 @@ libxrpl.ledger > xrpl.ledger
|
||||
libxrpl.ledger > xrpl.protocol
|
||||
libxrpl.net > xrpl.basics
|
||||
libxrpl.net > xrpl.net
|
||||
libxrpl.nodestore > xrpl.basics
|
||||
libxrpl.nodestore > xrpl.json
|
||||
libxrpl.nodestore > xrpl.nodestore
|
||||
libxrpl.nodestore > xrpl.protocol
|
||||
libxrpl.protocol > xrpl.basics
|
||||
libxrpl.protocol > xrpl.json
|
||||
libxrpl.protocol > xrpl.protocol
|
||||
@@ -22,9 +18,6 @@ libxrpl.server > xrpl.basics
|
||||
libxrpl.server > xrpl.json
|
||||
libxrpl.server > xrpl.protocol
|
||||
libxrpl.server > xrpl.server
|
||||
libxrpl.shamap > xrpl.basics
|
||||
libxrpl.shamap > xrpl.protocol
|
||||
libxrpl.shamap > xrpl.shamap
|
||||
test.app > test.jtx
|
||||
test.app > test.rpc
|
||||
test.app > test.toplevel
|
||||
@@ -32,11 +25,11 @@ test.app > test.unit_test
|
||||
test.app > xrpl.basics
|
||||
test.app > xrpld.app
|
||||
test.app > xrpld.core
|
||||
test.app > xrpld.nodestore
|
||||
test.app > xrpld.overlay
|
||||
test.app > xrpld.rpc
|
||||
test.app > xrpl.json
|
||||
test.app > xrpl.ledger
|
||||
test.app > xrpl.nodestore
|
||||
test.app > xrpl.protocol
|
||||
test.app > xrpl.resource
|
||||
test.basics > test.jtx
|
||||
@@ -93,7 +86,8 @@ test.nodestore > test.toplevel
|
||||
test.nodestore > test.unit_test
|
||||
test.nodestore > xrpl.basics
|
||||
test.nodestore > xrpld.core
|
||||
test.nodestore > xrpl.nodestore
|
||||
test.nodestore > xrpld.nodestore
|
||||
test.nodestore > xrpld.unity
|
||||
test.overlay > test.jtx
|
||||
test.overlay > test.toplevel
|
||||
test.overlay > test.unit_test
|
||||
@@ -101,8 +95,8 @@ test.overlay > xrpl.basics
|
||||
test.overlay > xrpld.app
|
||||
test.overlay > xrpld.overlay
|
||||
test.overlay > xrpld.peerfinder
|
||||
test.overlay > xrpld.shamap
|
||||
test.overlay > xrpl.protocol
|
||||
test.overlay > xrpl.shamap
|
||||
test.peerfinder > test.beast
|
||||
test.peerfinder > test.unit_test
|
||||
test.peerfinder > xrpl.basics
|
||||
@@ -137,22 +131,17 @@ test.server > xrpl.json
|
||||
test.server > xrpl.server
|
||||
test.shamap > test.unit_test
|
||||
test.shamap > xrpl.basics
|
||||
test.shamap > xrpl.nodestore
|
||||
test.shamap > xrpld.nodestore
|
||||
test.shamap > xrpld.shamap
|
||||
test.shamap > xrpl.protocol
|
||||
test.shamap > xrpl.shamap
|
||||
test.toplevel > test.csf
|
||||
test.toplevel > xrpl.json
|
||||
test.unit_test > xrpl.basics
|
||||
tests.libxrpl > xrpl.basics
|
||||
tests.libxrpl > xrpl.ledger
|
||||
tests.libxrpl > xrpl.json
|
||||
tests.libxrpl > xrpl.net
|
||||
xrpl.json > xrpl.basics
|
||||
xrpl.ledger > xrpl.basics
|
||||
xrpl.ledger > xrpl.protocol
|
||||
xrpl.net > xrpl.basics
|
||||
xrpl.nodestore > xrpl.basics
|
||||
xrpl.nodestore > xrpl.protocol
|
||||
xrpl.protocol > xrpl.basics
|
||||
xrpl.protocol > xrpl.json
|
||||
xrpl.resource > xrpl.basics
|
||||
@@ -161,21 +150,17 @@ xrpl.resource > xrpl.protocol
|
||||
xrpl.server > xrpl.basics
|
||||
xrpl.server > xrpl.json
|
||||
xrpl.server > xrpl.protocol
|
||||
xrpl.shamap > xrpl.basics
|
||||
xrpl.shamap > xrpl.nodestore
|
||||
xrpl.shamap > xrpl.protocol
|
||||
xrpld.app > test.unit_test
|
||||
xrpld.app > xrpl.basics
|
||||
xrpld.app > xrpld.conditions
|
||||
xrpld.app > xrpld.consensus
|
||||
xrpld.app > xrpld.nodestore
|
||||
xrpld.app > xrpld.perflog
|
||||
xrpld.app > xrpl.json
|
||||
xrpld.app > xrpl.ledger
|
||||
xrpld.app > xrpl.net
|
||||
xrpld.app > xrpl.nodestore
|
||||
xrpld.app > xrpl.protocol
|
||||
xrpld.app > xrpl.resource
|
||||
xrpld.app > xrpl.shamap
|
||||
xrpld.conditions > xrpl.basics
|
||||
xrpld.conditions > xrpl.protocol
|
||||
xrpld.consensus > xrpl.basics
|
||||
@@ -185,6 +170,11 @@ xrpld.core > xrpl.basics
|
||||
xrpld.core > xrpl.json
|
||||
xrpld.core > xrpl.net
|
||||
xrpld.core > xrpl.protocol
|
||||
xrpld.nodestore > xrpl.basics
|
||||
xrpld.nodestore > xrpld.core
|
||||
xrpld.nodestore > xrpld.unity
|
||||
xrpld.nodestore > xrpl.json
|
||||
xrpld.nodestore > xrpl.protocol
|
||||
xrpld.overlay > xrpl.basics
|
||||
xrpld.overlay > xrpld.core
|
||||
xrpld.overlay > xrpld.peerfinder
|
||||
@@ -200,11 +190,13 @@ xrpld.perflog > xrpl.basics
|
||||
xrpld.perflog > xrpl.json
|
||||
xrpld.rpc > xrpl.basics
|
||||
xrpld.rpc > xrpld.core
|
||||
xrpld.rpc > xrpld.nodestore
|
||||
xrpld.rpc > xrpl.json
|
||||
xrpld.rpc > xrpl.ledger
|
||||
xrpld.rpc > xrpl.net
|
||||
xrpld.rpc > xrpl.nodestore
|
||||
xrpld.rpc > xrpl.protocol
|
||||
xrpld.rpc > xrpl.resource
|
||||
xrpld.rpc > xrpl.server
|
||||
xrpld.shamap > xrpl.shamap
|
||||
xrpld.shamap > xrpl.basics
|
||||
xrpld.shamap > xrpld.nodestore
|
||||
xrpld.shamap > xrpl.protocol
|
||||
|
||||
10
.github/scripts/strategy-matrix/generate.py
vendored
10
.github/scripts/strategy-matrix/generate.py
vendored
@@ -74,14 +74,14 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
|
||||
continue
|
||||
|
||||
# RHEL:
|
||||
# - 9 using GCC 12: Debug and Unity on linux/amd64.
|
||||
# - 10 using Clang: Release and no Unity on linux/amd64.
|
||||
# - 9.4 using GCC 12: Debug and Unity on linux/amd64.
|
||||
# - 9.6 using Clang: Release and no Unity on linux/amd64.
|
||||
if os['distro_name'] == 'rhel':
|
||||
skip = True
|
||||
if os['distro_version'] == '9':
|
||||
if os['distro_version'] == '9.4':
|
||||
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-12' and build_type == 'Debug' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64':
|
||||
skip = False
|
||||
elif os['distro_version'] == '10':
|
||||
elif os['distro_version'] == '9.6':
|
||||
if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-any' and build_type == 'Release' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64':
|
||||
skip = False
|
||||
if skip:
|
||||
@@ -162,7 +162,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
|
||||
'config_name': config_name,
|
||||
'cmake_args': cmake_args,
|
||||
'cmake_target': cmake_target,
|
||||
'build_only': build_only,
|
||||
'build_only': 'true' if build_only else 'false',
|
||||
'build_type': build_type,
|
||||
'os': os,
|
||||
'architecture': architecture,
|
||||
|
||||
122
.github/scripts/strategy-matrix/linux.json
vendored
122
.github/scripts/strategy-matrix/linux.json
vendored
@@ -14,169 +14,139 @@
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "12"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "13"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "14"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "15",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "15"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "16",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "16"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "17",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "17"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "18",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "18"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "19",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "19"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "20",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "20"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "8",
|
||||
"distro_version": "9.4",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "10e69b4"
|
||||
"compiler_version": "12"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "8",
|
||||
"distro_version": "9.4",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9.4",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9.6",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9.6",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9.4",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "10e69b4"
|
||||
"compiler_version": "any"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "10e69b4"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "10e69b4"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "10e69b4"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"distro_version": "9.6",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "10e69b4"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "10",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "10e69b4"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "10",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "10e69b4"
|
||||
"compiler_version": "any"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "jammy",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "12"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "13"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "14"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "16",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "16"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "17",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "17"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "18",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "18"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "19",
|
||||
"image_sha": "6948666"
|
||||
"compiler_version": "19"
|
||||
}
|
||||
],
|
||||
"build_type": ["Debug", "Release"],
|
||||
|
||||
3
.github/scripts/strategy-matrix/macos.json
vendored
3
.github/scripts/strategy-matrix/macos.json
vendored
@@ -10,8 +10,7 @@
|
||||
"distro_name": "macos",
|
||||
"distro_version": "",
|
||||
"compiler_name": "",
|
||||
"compiler_version": "",
|
||||
"image_sha": ""
|
||||
"compiler_version": ""
|
||||
}
|
||||
],
|
||||
"build_type": ["Debug", "Release"],
|
||||
|
||||
3
.github/scripts/strategy-matrix/windows.json
vendored
3
.github/scripts/strategy-matrix/windows.json
vendored
@@ -10,8 +10,7 @@
|
||||
"distro_name": "windows",
|
||||
"distro_version": "",
|
||||
"compiler_name": "",
|
||||
"compiler_version": "",
|
||||
"image_sha": ""
|
||||
"compiler_version": ""
|
||||
}
|
||||
],
|
||||
"build_type": ["Debug", "Release"],
|
||||
|
||||
147
.github/workflows/build-test.yml
vendored
Normal file
147
.github/workflows/build-test.yml
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
# This workflow builds and tests the binary for various configurations.
|
||||
name: Build and test
|
||||
|
||||
# This workflow can only be triggered by other workflows. Note that the
|
||||
# workflow_call event does not support the 'choice' input type, see
|
||||
# https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onworkflow_callinputsinput_idtype,
|
||||
# so we use 'string' instead.
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
required: false
|
||||
type: string
|
||||
default: ".build"
|
||||
dependencies_force_build:
|
||||
description: "Force building of all dependencies."
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
dependencies_force_upload:
|
||||
description: "Force uploading of all dependencies."
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
os:
|
||||
description: 'The operating system to use for the build ("linux", "macos", "windows").'
|
||||
required: true
|
||||
type: string
|
||||
strategy_matrix:
|
||||
# TODO: Support additional strategies, e.g. "ubuntu" for generating all Ubuntu configurations.
|
||||
description: 'The strategy matrix to use for generating the configurations ("minimal", "all").'
|
||||
required: false
|
||||
type: string
|
||||
default: "minimal"
|
||||
secrets:
|
||||
codecov_token:
|
||||
description: "The Codecov token to use for uploading coverage reports."
|
||||
required: false
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.os }}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
# Generate the strategy matrix to be used by the following job.
|
||||
generate-matrix:
|
||||
uses: ./.github/workflows/reusable-strategy-matrix.yml
|
||||
with:
|
||||
os: ${{ inputs.os }}
|
||||
strategy_matrix: ${{ inputs.strategy_matrix }}
|
||||
|
||||
# Build and test the binary.
|
||||
build-test:
|
||||
needs:
|
||||
- generate-matrix
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
max-parallel: 10
|
||||
runs-on: ${{ matrix.architecture.runner }}
|
||||
container: ${{ inputs.os == 'linux' && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version) || null }}
|
||||
steps:
|
||||
- name: Check strategy matrix
|
||||
run: |
|
||||
echo 'Operating system distro name: ${{ matrix.os.distro_name }}'
|
||||
echo 'Operating system distro version: ${{ matrix.os.distro_version }}'
|
||||
echo 'Operating system compiler name: ${{ matrix.os.compiler_name }}'
|
||||
echo 'Operating system compiler version: ${{ matrix.os.compiler_version }}'
|
||||
echo 'Architecture platform: ${{ matrix.architecture.platform }}'
|
||||
echo 'Architecture runner: ${{ toJson(matrix.architecture.runner) }}'
|
||||
echo 'Build type: ${{ matrix.build_type }}'
|
||||
echo 'Build only: ${{ matrix.build_only }}'
|
||||
echo 'CMake arguments: ${{ matrix.cmake_args }}'
|
||||
echo 'CMake target: ${{ matrix.cmake_target }}'
|
||||
echo 'Config name: ${{ matrix.config_name }}'
|
||||
|
||||
- name: Cleanup workspace
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@638e0dc11ea230f91bd26622fb542116bb5254d5
|
||||
with:
|
||||
disable_ccache: false
|
||||
|
||||
- name: Check configuration (Windows)
|
||||
if: ${{ inputs.os == 'windows' }}
|
||||
run: |
|
||||
echo 'Checking environment variables.'
|
||||
set
|
||||
|
||||
echo 'Checking CMake version.'
|
||||
cmake --version
|
||||
|
||||
echo 'Checking Conan version.'
|
||||
conan --version
|
||||
- name: Check configuration (Linux and MacOS)
|
||||
if: ${{ inputs.os == 'linux' || inputs.os == 'macos' }}
|
||||
run: |
|
||||
echo 'Checking path.'
|
||||
echo ${PATH} | tr ':' '\n'
|
||||
|
||||
echo 'Checking environment variables.'
|
||||
env | sort
|
||||
|
||||
echo 'Checking CMake version.'
|
||||
cmake --version
|
||||
|
||||
echo 'Checking compiler version.'
|
||||
${{ inputs.os == 'linux' && '${CC}' || 'clang' }} --version
|
||||
|
||||
echo 'Checking Conan version.'
|
||||
conan --version
|
||||
|
||||
echo 'Checking Ninja version.'
|
||||
ninja --version
|
||||
|
||||
echo 'Checking nproc version.'
|
||||
nproc --version
|
||||
|
||||
- name: Setup Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
|
||||
- name: Build dependencies
|
||||
uses: ./.github/actions/build-deps
|
||||
with:
|
||||
build_dir: ${{ inputs.build_dir }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
force_build: ${{ inputs.dependencies_force_build }}
|
||||
|
||||
- name: Build and test binary
|
||||
uses: ./.github/actions/build-test
|
||||
with:
|
||||
build_dir: ${{ inputs.build_dir }}
|
||||
build_only: ${{ matrix.build_only }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
cmake_args: ${{ matrix.cmake_args }}
|
||||
cmake_target: ${{ matrix.cmake_target }}
|
||||
codecov_token: ${{ secrets.codecov_token }}
|
||||
os: ${{ inputs.os }}
|
||||
@@ -40,52 +40,47 @@ jobs:
|
||||
upload:
|
||||
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13-sha-5dd7158
|
||||
container: ghcr.io/xrplf/ci/ubuntu-noble:gcc-13
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
- name: Generate outputs
|
||||
id: generate
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
echo 'Generating user and channel.'
|
||||
echo "user=clio" >> "${GITHUB_OUTPUT}"
|
||||
echo "channel=pr_${PR_NUMBER}" >> "${GITHUB_OUTPUT}"
|
||||
echo "channel=pr_${{ github.event.pull_request.number }}" >> "${GITHUB_OUTPUT}"
|
||||
echo 'Extracting version.'
|
||||
echo "version=$(cat src/libxrpl/protocol/BuildInfo.cpp | grep "versionString =" | awk -F '"' '{print $2}')" >> "${GITHUB_OUTPUT}"
|
||||
- name: Calculate conan reference
|
||||
id: conan_ref
|
||||
run: |
|
||||
echo "conan_ref=${{ steps.generate.outputs.version }}@${{ steps.generate.outputs.user }}/${{ steps.generate.outputs.channel }}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
- name: Set up Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
with:
|
||||
conan_remote_name: ${{ inputs.conan_remote_name }}
|
||||
conan_remote_url: ${{ inputs.conan_remote_url }}
|
||||
|
||||
- name: Log into Conan remote
|
||||
env:
|
||||
CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }}
|
||||
run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}"
|
||||
run: conan remote login ${{ inputs.conan_remote_name }} "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}"
|
||||
- name: Upload package
|
||||
env:
|
||||
CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }}
|
||||
run: |
|
||||
conan export --user=${{ steps.generate.outputs.user }} --channel=${{ steps.generate.outputs.channel }} .
|
||||
conan upload --confirm --check --remote="${CONAN_REMOTE_NAME}" xrpl/${{ steps.conan_ref.outputs.conan_ref }}
|
||||
conan upload --confirm --check --remote=${{ inputs.conan_remote_name }} xrpl/${{ steps.conan_ref.outputs.conan_ref }}
|
||||
outputs:
|
||||
conan_ref: ${{ steps.conan_ref.outputs.conan_ref }}
|
||||
|
||||
notify:
|
||||
needs: upload
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.clio_notify_token }}
|
||||
steps:
|
||||
- name: Notify Clio
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.clio_notify_token }}
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
/repos/xrplf/clio/dispatches -f "event_type=check_libxrpl" \
|
||||
-F "client_payload[conan_ref]=${{ needs.upload.outputs.conan_ref }}" \
|
||||
-F "client_payload[pr_url]=${PR_URL}"
|
||||
-F "client_payload[pr_url]=${{ github.event.pull_request.html_url }}"
|
||||
18
.github/workflows/on-pr.yml
vendored
18
.github/workflows/on-pr.yml
vendored
@@ -50,8 +50,8 @@ jobs:
|
||||
files: |
|
||||
# These paths are unique to `on-pr.yml`.
|
||||
.github/scripts/levelization/**
|
||||
.github/workflows/reusable-check-levelization.yml
|
||||
.github/workflows/reusable-notify-clio.yml
|
||||
.github/workflows/check-levelization.yml
|
||||
.github/workflows/notify-clio.yml
|
||||
.github/workflows/on-pr.yml
|
||||
|
||||
# Keep the paths below in sync with those in `on-trigger.yml`.
|
||||
@@ -59,11 +59,8 @@ jobs:
|
||||
.github/actions/build-test/**
|
||||
.github/actions/setup-conan/**
|
||||
.github/scripts/strategy-matrix/**
|
||||
.github/workflows/reusable-build.yml
|
||||
.github/workflows/reusable-build-test-config.yml
|
||||
.github/workflows/reusable-build-test.yml
|
||||
.github/workflows/build-test.yml
|
||||
.github/workflows/reusable-strategy-matrix.yml
|
||||
.github/workflows/reusable-test.yml
|
||||
.codecov.yml
|
||||
cmake/**
|
||||
conan/**
|
||||
@@ -96,27 +93,26 @@ jobs:
|
||||
check-levelization:
|
||||
needs: should-run
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
uses: ./.github/workflows/reusable-check-levelization.yml
|
||||
uses: ./.github/workflows/check-levelization.yml
|
||||
|
||||
build-test:
|
||||
needs: should-run
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
uses: ./.github/workflows/reusable-build-test.yml
|
||||
uses: ./.github/workflows/build-test.yml
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [linux, macos, windows]
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
codecov_token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
notify-clio:
|
||||
needs:
|
||||
- should-run
|
||||
- build-test
|
||||
if: ${{ needs.should-run.outputs.go == 'true' && contains(fromJSON('["release", "master"]'), github.ref_name) }}
|
||||
uses: ./.github/workflows/reusable-notify-clio.yml
|
||||
uses: ./.github/workflows/notify-clio.yml
|
||||
secrets:
|
||||
clio_notify_token: ${{ secrets.CLIO_NOTIFY_TOKEN }}
|
||||
conan_remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
|
||||
|
||||
43
.github/workflows/on-trigger.yml
vendored
43
.github/workflows/on-trigger.yml
vendored
@@ -9,12 +9,12 @@ name: Trigger
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "release*"
|
||||
- "master"
|
||||
- develop
|
||||
- release
|
||||
- master
|
||||
paths:
|
||||
# These paths are unique to `on-trigger.yml`.
|
||||
- ".github/workflows/reusable-check-missing-commits.yml"
|
||||
- ".github/workflows/check-missing-commits.yml"
|
||||
- ".github/workflows/on-trigger.yml"
|
||||
- ".github/workflows/publish-docs.yml"
|
||||
|
||||
@@ -23,11 +23,8 @@ on:
|
||||
- ".github/actions/build-test/**"
|
||||
- ".github/actions/setup-conan/**"
|
||||
- ".github/scripts/strategy-matrix/**"
|
||||
- ".github/workflows/reusable-build.yml"
|
||||
- ".github/workflows/reusable-build-test-config.yml"
|
||||
- ".github/workflows/reusable-build-test.yml"
|
||||
- ".github/workflows/build-test.yml"
|
||||
- ".github/workflows/reusable-strategy-matrix.yml"
|
||||
- ".github/workflows/reusable-test.yml"
|
||||
- ".codecov.yml"
|
||||
- "cmake/**"
|
||||
- "conan/**"
|
||||
@@ -46,16 +43,25 @@ on:
|
||||
schedule:
|
||||
- cron: "32 6 * * 1-5"
|
||||
|
||||
# Run when manually triggered via the GitHub UI or API.
|
||||
# Run when manually triggered via the GitHub UI or API. If `force_upload` is
|
||||
# true, then the dependencies that were missing (`force_rebuild` is false) or
|
||||
# rebuilt (`force_rebuild` is true) will be uploaded, overwriting existing
|
||||
# dependencies if needed.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dependencies_force_build:
|
||||
description: "Force building of all dependencies."
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
dependencies_force_upload:
|
||||
description: "Force uploading of all dependencies."
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
concurrency:
|
||||
# When a PR is merged into the develop branch it will be assigned a unique
|
||||
# group identifier, so execution will continue even if another PR is merged
|
||||
# while it is still running. In all other cases the group identifier is shared
|
||||
# per branch, so that any in-progress runs are cancelled when a new commit is
|
||||
# pushed.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }}
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
@@ -65,16 +71,15 @@ defaults:
|
||||
jobs:
|
||||
check-missing-commits:
|
||||
if: ${{ github.event_name == 'push' && github.ref_type == 'branch' && contains(fromJSON('["develop", "release"]'), github.ref_name) }}
|
||||
uses: ./.github/workflows/reusable-check-missing-commits.yml
|
||||
uses: ./.github/workflows/check-missing-commits.yml
|
||||
|
||||
build-test:
|
||||
uses: ./.github/workflows/reusable-build-test.yml
|
||||
uses: ./.github/workflows/build-test.yml
|
||||
strategy:
|
||||
fail-fast: ${{ github.event_name == 'merge_group' }}
|
||||
matrix:
|
||||
os: [linux, macos, windows]
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
strategy_matrix: ${{ github.event_name == 'schedule' && 'all' || 'minimal' }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
codecov_token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
5
.github/workflows/pre-commit.yml
vendored
5
.github/workflows/pre-commit.yml
vendored
@@ -7,9 +7,8 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
|
||||
run-hooks:
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@34790936fae4c6c751f62ec8c06696f9c1a5753a
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@af1b0f0d764cda2e5435f5ac97b240d4bd4d95d3
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-a8c7be1" }'
|
||||
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit" }'
|
||||
|
||||
20
.github/workflows/publish-docs.yml
vendored
20
.github/workflows/publish-docs.yml
vendored
@@ -23,24 +23,16 @@ defaults:
|
||||
|
||||
env:
|
||||
BUILD_DIR: .build
|
||||
NPROC_SUBTRACT: 2
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/ci/tools-rippled-documentation:sha-a8c7be1
|
||||
container: ghcr.io/xrplf/ci/tools-rippled-documentation
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
|
||||
id: nproc
|
||||
with:
|
||||
subtract: ${{ env.NPROC_SUBTRACT }}
|
||||
|
||||
- name: Check configuration
|
||||
run: |
|
||||
echo 'Checking path.'
|
||||
@@ -54,16 +46,12 @@ jobs:
|
||||
|
||||
echo 'Checking Doxygen version.'
|
||||
doxygen --version
|
||||
|
||||
- name: Build documentation
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
run: |
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
cd "${BUILD_DIR}"
|
||||
mkdir -p ${{ env.BUILD_DIR }}
|
||||
cd ${{ env.BUILD_DIR }}
|
||||
cmake -Donly_docs=ON ..
|
||||
cmake --build . --target docs --parallel ${BUILD_NPROC}
|
||||
|
||||
cmake --build . --target docs --parallel $(nproc)
|
||||
- name: Publish documentation
|
||||
if: ${{ github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch }}
|
||||
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
|
||||
|
||||
77
.github/workflows/reusable-build-test-config.yml
vendored
77
.github/workflows/reusable-build-test-config.yml
vendored
@@ -1,77 +0,0 @@
|
||||
name: Build and test configuration
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
required: true
|
||||
type: string
|
||||
build_only:
|
||||
description: 'Whether to only build or to build and test the code ("true", "false").'
|
||||
required: true
|
||||
type: boolean
|
||||
build_type:
|
||||
description: 'The build type to use ("Debug", "Release").'
|
||||
type: string
|
||||
required: true
|
||||
cmake_args:
|
||||
description: "Additional arguments to pass to CMake."
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
cmake_target:
|
||||
description: "The CMake target to build."
|
||||
type: string
|
||||
required: true
|
||||
|
||||
runs_on:
|
||||
description: Runner to run the job on as a JSON string
|
||||
required: true
|
||||
type: string
|
||||
image:
|
||||
description: "The image to run in (leave empty to run natively)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
config_name:
|
||||
description: "The configuration string (used for naming artifacts and such)."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
nproc_subtract:
|
||||
description: "The number of processors to subtract when calculating parallelism."
|
||||
required: false
|
||||
type: number
|
||||
default: 2
|
||||
|
||||
secrets:
|
||||
CODECOV_TOKEN:
|
||||
description: "The Codecov token to use for uploading coverage reports."
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: ./.github/workflows/reusable-build.yml
|
||||
with:
|
||||
build_dir: ${{ inputs.build_dir }}
|
||||
build_type: ${{ inputs.build_type }}
|
||||
cmake_args: ${{ inputs.cmake_args }}
|
||||
cmake_target: ${{ inputs.cmake_target }}
|
||||
runs_on: ${{ inputs.runs_on }}
|
||||
image: ${{ inputs.image }}
|
||||
config_name: ${{ inputs.config_name }}
|
||||
nproc_subtract: ${{ inputs.nproc_subtract }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
test:
|
||||
needs: build
|
||||
uses: ./.github/workflows/reusable-test.yml
|
||||
with:
|
||||
run_tests: ${{ !inputs.build_only }}
|
||||
verify_voidstar: ${{ contains(inputs.cmake_args, '-Dvoidstar=ON') }}
|
||||
runs_on: ${{ inputs.runs_on }}
|
||||
image: ${{ inputs.image }}
|
||||
config_name: ${{ inputs.config_name }}
|
||||
nproc_subtract: ${{ inputs.nproc_subtract }}
|
||||
58
.github/workflows/reusable-build-test.yml
vendored
58
.github/workflows/reusable-build-test.yml
vendored
@@ -1,58 +0,0 @@
|
||||
# This workflow builds and tests the binary for various configurations.
|
||||
name: Build and test
|
||||
|
||||
# This workflow can only be triggered by other workflows. Note that the
|
||||
# workflow_call event does not support the 'choice' input type, see
|
||||
# https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#onworkflow_callinputsinput_idtype,
|
||||
# so we use 'string' instead.
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
required: false
|
||||
type: string
|
||||
default: ".build"
|
||||
os:
|
||||
description: 'The operating system to use for the build ("linux", "macos", "windows").'
|
||||
required: true
|
||||
type: string
|
||||
strategy_matrix:
|
||||
# TODO: Support additional strategies, e.g. "ubuntu" for generating all Ubuntu configurations.
|
||||
description: 'The strategy matrix to use for generating the configurations ("minimal", "all").'
|
||||
required: false
|
||||
type: string
|
||||
default: "minimal"
|
||||
secrets:
|
||||
CODECOV_TOKEN:
|
||||
description: "The Codecov token to use for uploading coverage reports."
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
# Generate the strategy matrix to be used by the following job.
|
||||
generate-matrix:
|
||||
uses: ./.github/workflows/reusable-strategy-matrix.yml
|
||||
with:
|
||||
os: ${{ inputs.os }}
|
||||
strategy_matrix: ${{ inputs.strategy_matrix }}
|
||||
|
||||
# Build and test the binary for each configuration.
|
||||
build-test-config:
|
||||
needs:
|
||||
- generate-matrix
|
||||
uses: ./.github/workflows/reusable-build-test-config.yml
|
||||
strategy:
|
||||
fail-fast: ${{ github.event_name == 'merge_group' }}
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
max-parallel: 10
|
||||
with:
|
||||
build_dir: ${{ inputs.build_dir }}
|
||||
build_only: ${{ matrix.build_only }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
cmake_args: ${{ matrix.cmake_args }}
|
||||
cmake_target: ${{ matrix.cmake_target }}
|
||||
runs_on: ${{ toJSON(matrix.architecture.runner) }}
|
||||
image: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || '' }}
|
||||
config_name: ${{ matrix.config_name }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
154
.github/workflows/reusable-build.yml
vendored
154
.github/workflows/reusable-build.yml
vendored
@@ -1,154 +0,0 @@
|
||||
name: Build rippled
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
required: true
|
||||
type: string
|
||||
build_type:
|
||||
description: 'The build type to use ("Debug", "Release").'
|
||||
required: true
|
||||
type: string
|
||||
cmake_args:
|
||||
description: "Additional arguments to pass to CMake."
|
||||
required: true
|
||||
type: string
|
||||
cmake_target:
|
||||
description: "The CMake target to build."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
runs_on:
|
||||
description: Runner to run the job on as a JSON string
|
||||
required: true
|
||||
type: string
|
||||
image:
|
||||
description: "The image to run in (leave empty to run natively)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
config_name:
|
||||
description: "The name of the configuration."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
nproc_subtract:
|
||||
description: "The number of processors to subtract when calculating parallelism."
|
||||
required: true
|
||||
type: number
|
||||
|
||||
secrets:
|
||||
CODECOV_TOKEN:
|
||||
description: "The Codecov token to use for uploading coverage reports."
|
||||
required: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build ${{ inputs.config_name }}
|
||||
runs-on: ${{ fromJSON(inputs.runs_on) }}
|
||||
container: ${{ inputs.image != '' && inputs.image || null }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Cleanup workspace
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a
|
||||
with:
|
||||
disable_ccache: false
|
||||
|
||||
- name: Print build environment
|
||||
uses: ./.github/actions/print-env
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
|
||||
id: nproc
|
||||
with:
|
||||
subtract: ${{ inputs.nproc_subtract }}
|
||||
|
||||
- name: Setup Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
|
||||
- name: Build dependencies
|
||||
uses: ./.github/actions/build-deps
|
||||
with:
|
||||
build_dir: ${{ inputs.build_dir }}
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ inputs.build_type }}
|
||||
# Set the verbosity to "quiet" for Windows to avoid an excessive
|
||||
# amount of logs. For other OSes, the "verbose" logs are more useful.
|
||||
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
|
||||
|
||||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
env:
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
CMAKE_ARGS: ${{ inputs.cmake_args }}
|
||||
run: |
|
||||
cmake \
|
||||
-G '${{ runner.os == 'Windows' && 'Visual Studio 17 2022' || 'Ninja' }}' \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
||||
${CMAKE_ARGS} \
|
||||
..
|
||||
|
||||
- name: Build the binary
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
CMAKE_TARGET: ${{ inputs.cmake_target }}
|
||||
run: |
|
||||
cmake \
|
||||
--build . \
|
||||
--config "${BUILD_TYPE}" \
|
||||
--parallel ${BUILD_NPROC} \
|
||||
--target "${CMAKE_TARGET}"
|
||||
|
||||
- name: Put built binaries in one location
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.build_dir }}
|
||||
env:
|
||||
BUILD_TYPE_DIR: ${{ runner.os == 'Windows' && inputs.build_type || '' }}
|
||||
CMAKE_TARGET: ${{ inputs.cmake_target }}
|
||||
run: |
|
||||
mkdir -p ./binaries/doctest/
|
||||
|
||||
cp ./${BUILD_TYPE_DIR}/rippled* ./binaries/
|
||||
if [ "${CMAKE_TARGET}" != 'coverage' ]; then
|
||||
cp ./src/tests/libxrpl/${BUILD_TYPE_DIR}/xrpl.test.* ./binaries/doctest/
|
||||
fi
|
||||
|
||||
- name: Upload rippled artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
env:
|
||||
BUILD_DIR: ${{ inputs.build_dir }}
|
||||
with:
|
||||
name: rippled-${{ inputs.config_name }}
|
||||
path: ${{ env.BUILD_DIR }}/binaries/
|
||||
retention-days: 3
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ github.repository_owner == 'XRPLF' && inputs.cmake_target == 'coverage' }}
|
||||
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
|
||||
with:
|
||||
disable_search: true
|
||||
disable_telem: true
|
||||
fail_ci_if_error: true
|
||||
files: ${{ inputs.build_dir }}/coverage.xml
|
||||
plugins: noop
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
@@ -35,7 +35,4 @@ jobs:
|
||||
- name: Generate strategy matrix
|
||||
working-directory: .github/scripts/strategy-matrix
|
||||
id: generate
|
||||
env:
|
||||
GENERATE_CONFIG: ${{ inputs.os != '' && format('--config={0}.json', inputs.os) || '' }}
|
||||
GENERATE_OPTION: ${{ inputs.strategy_matrix == 'all' && '--all' || '' }}
|
||||
run: ./generate.py ${GENERATE_OPTION} ${GENERATE_CONFIG} >> "${GITHUB_OUTPUT}"
|
||||
run: ./generate.py ${{ inputs.strategy_matrix == 'all' && '--all' || '' }} ${{ inputs.os != '' && format('--config={0}.json', inputs.os) || '' }} >> "${GITHUB_OUTPUT}"
|
||||
|
||||
111
.github/workflows/reusable-test.yml
vendored
111
.github/workflows/reusable-test.yml
vendored
@@ -1,111 +0,0 @@
|
||||
name: Test rippled
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
verify_voidstar:
|
||||
description: "Whether to verify the presence of voidstar instrumentation."
|
||||
required: true
|
||||
type: boolean
|
||||
run_tests:
|
||||
description: "Whether to run unit tests"
|
||||
required: true
|
||||
type: boolean
|
||||
|
||||
runs_on:
|
||||
description: Runner to run the job on as a JSON string
|
||||
required: true
|
||||
type: string
|
||||
image:
|
||||
description: "The image to run in (leave empty to run natively)"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
config_name:
|
||||
description: "The name of the configuration."
|
||||
required: true
|
||||
type: string
|
||||
|
||||
nproc_subtract:
|
||||
description: "The number of processors to subtract when calculating parallelism."
|
||||
required: true
|
||||
type: number
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test ${{ inputs.config_name }}
|
||||
runs-on: ${{ fromJSON(inputs.runs_on) }}
|
||||
container: ${{ inputs.image != '' && inputs.image || null }}
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Cleanup workspace
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
|
||||
id: nproc
|
||||
with:
|
||||
subtract: ${{ inputs.nproc_subtract }}
|
||||
|
||||
- name: Download rippled artifact
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: rippled-${{ inputs.config_name }}
|
||||
|
||||
- name: Make binary executable (Linux and macOS)
|
||||
shell: bash
|
||||
if: ${{ runner.os == 'Linux' || runner.os == 'macOS' }}
|
||||
run: |
|
||||
chmod +x ./rippled
|
||||
|
||||
- name: Check linking (Linux)
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
shell: bash
|
||||
run: |
|
||||
ldd ./rippled
|
||||
if [ "$(ldd ./rippled | grep -E '(libstdc\+\+|libgcc)' | wc -l)" -eq 0 ]; then
|
||||
echo 'The binary is statically linked.'
|
||||
else
|
||||
echo 'The binary is dynamically linked.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Verifying presence of instrumentation
|
||||
if: ${{ inputs.verify_voidstar }}
|
||||
shell: bash
|
||||
run: |
|
||||
./rippled --version | grep libvoidstar
|
||||
|
||||
- name: Run the embedded tests
|
||||
if: ${{ inputs.run_tests }}
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
run: |
|
||||
./rippled --unittest --unittest-jobs ${BUILD_NPROC}
|
||||
|
||||
- name: Run the separate tests
|
||||
if: ${{ inputs.run_tests }}
|
||||
env:
|
||||
EXT: ${{ runner.os == 'Windows' && '.exe' || '' }}
|
||||
shell: bash
|
||||
run: |
|
||||
for test_file in ./doctest/*${EXT}; do
|
||||
echo "Executing $test_file"
|
||||
chmod +x "$test_file"
|
||||
if [[ "${{ runner.os }}" == "Windows" && "$test_file" == "./doctest/xrpl.test.net.exe" ]]; then
|
||||
echo "Skipping $test_file on Windows"
|
||||
else
|
||||
"$test_file"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Debug failure (Linux)
|
||||
if: ${{ failure() && runner.os == 'Linux' && inputs.run_tests }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "IPv4 local port range:"
|
||||
cat /proc/sys/net/ipv4/ip_local_port_range
|
||||
echo "Netstat:"
|
||||
netstat -an
|
||||
38
.github/workflows/upload-conan-deps.yml
vendored
38
.github/workflows/upload-conan-deps.yml
vendored
@@ -24,30 +24,30 @@ on:
|
||||
branches: [develop]
|
||||
paths:
|
||||
- .github/workflows/upload-conan-deps.yml
|
||||
|
||||
- .github/workflows/reusable-strategy-matrix.yml
|
||||
|
||||
- .github/actions/build-deps/action.yml
|
||||
- .github/actions/setup-conan/action.yml
|
||||
- ".github/scripts/strategy-matrix/**"
|
||||
|
||||
- conanfile.py
|
||||
- conan.lock
|
||||
|
||||
env:
|
||||
CONAN_REMOTE_NAME: xrplf
|
||||
CONAN_REMOTE_URL: https://conan.ripplex.io
|
||||
NPROC_SUBTRACT: 2
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Generate the strategy matrix to be used by the following job.
|
||||
generate-matrix:
|
||||
uses: ./.github/workflows/reusable-strategy-matrix.yml
|
||||
with:
|
||||
strategy_matrix: ${{ github.event_name == 'pull_request' && 'minimal' || 'all' }}
|
||||
|
||||
# Build and upload the dependencies for each configuration.
|
||||
run-upload-conan-deps:
|
||||
needs:
|
||||
- generate-matrix
|
||||
@@ -56,29 +56,19 @@ jobs:
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
max-parallel: 10
|
||||
runs-on: ${{ matrix.architecture.runner }}
|
||||
container: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) || null }}
|
||||
container: ${{ contains(matrix.architecture.platform, 'linux') && format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version) || null }}
|
||||
|
||||
steps:
|
||||
- name: Cleanup workspace
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@99685816bb60a95a66852f212f382580e180df3a
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@638e0dc11ea230f91bd26622fb542116bb5254d5
|
||||
with:
|
||||
disable_ccache: false
|
||||
|
||||
- name: Print build environment
|
||||
uses: ./.github/actions/print-env
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/.github/actions/get-nproc@046b1620f6bfd6cd0985dc82c3df02786801fe0a
|
||||
id: nproc
|
||||
with:
|
||||
subtract: ${{ env.NPROC_SUBTRACT }}
|
||||
|
||||
- name: Setup Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
with:
|
||||
@@ -89,19 +79,13 @@ jobs:
|
||||
uses: ./.github/actions/build-deps
|
||||
with:
|
||||
build_dir: .build
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }}
|
||||
# Set the verbosity to "quiet" for Windows to avoid an excessive
|
||||
# amount of logs. For other OSes, the "verbose" logs are more useful.
|
||||
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
|
||||
|
||||
- name: Log into Conan remote
|
||||
if: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
|
||||
run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.CONAN_REMOTE_USERNAME }}" --password "${{ secrets.CONAN_REMOTE_PASSWORD }}"
|
||||
if: ${{ github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' }}
|
||||
run: conan remote login ${{ env.CONAN_REMOTE_NAME }} "${{ secrets.CONAN_REMOTE_USERNAME }}" --password "${{ secrets.CONAN_REMOTE_PASSWORD }}"
|
||||
|
||||
- name: Upload Conan packages
|
||||
if: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
|
||||
env:
|
||||
FORCE_OPTION: ${{ github.event.inputs.force_upload == 'true' && '--force' || '' }}
|
||||
run: conan upload "*" --remote="${CONAN_REMOTE_NAME}" --confirm ${FORCE_OPTION}
|
||||
if: ${{ github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' && github.event_name != 'schedule' }}
|
||||
run: conan upload "*" -r=${{ env.CONAN_REMOTE_NAME }} --confirm ${{ github.event.inputs.force_upload == 'true' && '--force' || '' }}
|
||||
|
||||
22
BUILD.md
22
BUILD.md
@@ -39,12 +39,17 @@ found here](./docs/build/environment.md).
|
||||
|
||||
- [Python 3.11](https://www.python.org/downloads/), or higher
|
||||
- [Conan 2.17](https://conan.io/downloads.html)[^1], or higher
|
||||
- [CMake 3.22](https://cmake.org/download/), or higher
|
||||
- [CMake 3.22](https://cmake.org/download/)[^2], or higher
|
||||
|
||||
[^1]:
|
||||
It is possible to build with Conan 1.60+, but the instructions are
|
||||
significantly different, which is why we are not recommending it.
|
||||
|
||||
[^2]:
|
||||
CMake 4 is not yet supported by all dependencies required by this project.
|
||||
If you are affected by this issue, follow [conan workaround for cmake
|
||||
4](#workaround-for-cmake-4)
|
||||
|
||||
`rippled` is written in the C++20 dialect and includes the `<concepts>` header.
|
||||
The [minimum compiler versions][2] required are:
|
||||
|
||||
@@ -277,6 +282,21 @@ sed -i.bak -e 's|^arch=.*$|arch=x86_64|' $(conan config home)/profiles/default
|
||||
sed -i.bak -e 's|^compiler\.runtime=.*$|compiler.runtime=static|' $(conan config home)/profiles/default
|
||||
```
|
||||
|
||||
#### Workaround for CMake 4
|
||||
|
||||
If your system CMake is version 4 rather than 3, you may have to configure Conan
|
||||
profile to use CMake version 3 for dependencies, by adding the following two
|
||||
lines to your profile:
|
||||
|
||||
```text
|
||||
[tool_requires]
|
||||
!cmake/*: cmake/[>=3 <4]
|
||||
```
|
||||
|
||||
This will force Conan to download and use a locally cached CMake 3 version, and
|
||||
is needed because some of the dependencies used by this project do not support
|
||||
CMake 4.
|
||||
|
||||
#### Clang workaround for grpc
|
||||
|
||||
If your compiler is clang, version 19 or later, or apple-clang, version 17 or
|
||||
|
||||
@@ -975,47 +975,6 @@
|
||||
# number of ledger records online. Must be greater
|
||||
# than or equal to ledger_history.
|
||||
#
|
||||
# Optional keys for NuDB only:
|
||||
#
|
||||
# nudb_block_size EXPERIMENTAL: Block size in bytes for NuDB storage.
|
||||
# Must be a power of 2 between 4096 and 32768. Default is 4096.
|
||||
#
|
||||
# This parameter controls the fundamental storage unit
|
||||
# size for NuDB's internal data structures. The choice
|
||||
# of block size can significantly impact performance
|
||||
# depending on your storage hardware and filesystem:
|
||||
#
|
||||
# - 4096 bytes: Optimal for most standard SSDs and
|
||||
# traditional filesystems (ext4, NTFS, HFS+).
|
||||
# Provides good balance of performance and storage
|
||||
# efficiency. Recommended for most deployments.
|
||||
# Minimizes memory footprint and provides consistent
|
||||
# low-latency access patterns across diverse hardware.
|
||||
#
|
||||
# - 8192-16384 bytes: May improve performance on
|
||||
# high-end NVMe SSDs and copy-on-write filesystems
|
||||
# like ZFS or Btrfs that benefit from larger block
|
||||
# alignment. Can reduce metadata overhead for large
|
||||
# databases. Offers better sequential throughput and
|
||||
# reduced I/O operations at the cost of higher memory
|
||||
# usage per operation.
|
||||
#
|
||||
# - 32768 bytes (32K): Maximum supported block size
|
||||
# for high-performance scenarios with very fast
|
||||
# storage. May increase memory usage and reduce
|
||||
# efficiency for smaller databases. Best suited for
|
||||
# enterprise environments with abundant RAM.
|
||||
#
|
||||
# Performance testing is recommended before deploying
|
||||
# any non-default block size in production environments.
|
||||
#
|
||||
# Note: This setting cannot be changed after database
|
||||
# creation without rebuilding the entire database.
|
||||
# Choose carefully based on your hardware and expected
|
||||
# database size.
|
||||
#
|
||||
# Example: nudb_block_size=4096
|
||||
#
|
||||
# These keys modify the behavior of online_delete, and thus are only
|
||||
# relevant if online_delete is defined and non-zero:
|
||||
#
|
||||
@@ -1512,7 +1471,6 @@ secure_gateway = 127.0.0.1
|
||||
[node_db]
|
||||
type=NuDB
|
||||
path=/var/lib/rippled/db/nudb
|
||||
nudb_block_size=4096
|
||||
online_delete=512
|
||||
advisory_delete=0
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ if (static OR APPLE OR MSVC)
|
||||
set (OPENSSL_USE_STATIC_LIBS ON)
|
||||
endif ()
|
||||
set (OPENSSL_MSVC_STATIC_RT ON)
|
||||
find_dependency (OpenSSL REQUIRED)
|
||||
find_dependency (OpenSSL 1.1.1 REQUIRED)
|
||||
find_dependency (ZLIB)
|
||||
find_dependency (date)
|
||||
if (TARGET ZLIB::ZLIB)
|
||||
|
||||
@@ -53,15 +53,14 @@ add_library(xrpl.imports.main INTERFACE)
|
||||
|
||||
target_link_libraries(xrpl.imports.main
|
||||
INTERFACE
|
||||
absl::random_random
|
||||
date::date
|
||||
ed25519::ed25519
|
||||
LibArchive::LibArchive
|
||||
OpenSSL::Crypto
|
||||
Ripple::boost
|
||||
Ripple::libs
|
||||
Ripple::opts
|
||||
Ripple::syslibs
|
||||
absl::random_random
|
||||
date::date
|
||||
ed25519::ed25519
|
||||
secp256k1::secp256k1
|
||||
xrpl.libpb
|
||||
xxHash::xxhash
|
||||
@@ -112,21 +111,6 @@ target_link_libraries(xrpl.libxrpl.net PUBLIC
|
||||
add_module(xrpl server)
|
||||
target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol)
|
||||
|
||||
add_module(xrpl nodestore)
|
||||
target_link_libraries(xrpl.libxrpl.nodestore PUBLIC
|
||||
xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.json
|
||||
xrpl.libxrpl.protocol
|
||||
)
|
||||
|
||||
add_module(xrpl shamap)
|
||||
target_link_libraries(xrpl.libxrpl.shamap PUBLIC
|
||||
xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.crypto
|
||||
xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.nodestore
|
||||
)
|
||||
|
||||
add_module(xrpl ledger)
|
||||
target_link_libraries(xrpl.libxrpl.ledger PUBLIC
|
||||
xrpl.libxrpl.basics
|
||||
@@ -152,8 +136,6 @@ target_link_modules(xrpl PUBLIC
|
||||
protocol
|
||||
resource
|
||||
server
|
||||
nodestore
|
||||
shamap
|
||||
net
|
||||
ledger
|
||||
)
|
||||
|
||||
@@ -8,23 +8,20 @@ install (
|
||||
TARGETS
|
||||
common
|
||||
opts
|
||||
ripple_boost
|
||||
ripple_libs
|
||||
ripple_syslibs
|
||||
ripple_boost
|
||||
xrpl.imports.main
|
||||
xrpl.libpb
|
||||
xrpl.libxrpl
|
||||
xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.beast
|
||||
xrpl.libxrpl.crypto
|
||||
xrpl.libxrpl.json
|
||||
xrpl.libxrpl.ledger
|
||||
xrpl.libxrpl.net
|
||||
xrpl.libxrpl.nodestore
|
||||
xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.resource
|
||||
xrpl.libxrpl.ledger
|
||||
xrpl.libxrpl.server
|
||||
xrpl.libxrpl.shamap
|
||||
xrpl.libxrpl.net
|
||||
xrpl.libxrpl
|
||||
antithesis-sdk-cpp
|
||||
EXPORT RippleExports
|
||||
LIBRARY DESTINATION lib
|
||||
@@ -41,7 +38,7 @@ install(CODE "
|
||||
set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\")
|
||||
include(create_symbolic_link)
|
||||
create_symbolic_link(xrpl \
|
||||
\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple)
|
||||
\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/ripple)
|
||||
")
|
||||
|
||||
install (EXPORT RippleExports
|
||||
@@ -75,7 +72,7 @@ if (is_root_project AND TARGET rippled)
|
||||
set(CMAKE_MODULE_PATH \"${CMAKE_MODULE_PATH}\")
|
||||
include(create_symbolic_link)
|
||||
create_symbolic_link(rippled${suffix} \
|
||||
\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix})
|
||||
\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/xrpld${suffix})
|
||||
")
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
option (validator_keys "Enables building of validator-keys tool as a separate target (imported via FetchContent)" OFF)
|
||||
option (validator_keys "Enables building of validator-keys-tool as a separate target (imported via FetchContent)" OFF)
|
||||
|
||||
if (validator_keys)
|
||||
git_branch (current_branch)
|
||||
@@ -6,15 +6,17 @@ if (validator_keys)
|
||||
if (NOT (current_branch STREQUAL "release"))
|
||||
set (current_branch "master")
|
||||
endif ()
|
||||
message (STATUS "Tracking ValidatorKeys branch: ${current_branch}")
|
||||
message (STATUS "tracking ValidatorKeys branch: ${current_branch}")
|
||||
|
||||
FetchContent_Declare (
|
||||
validator_keys
|
||||
validator_keys_src
|
||||
GIT_REPOSITORY https://github.com/ripple/validator-keys-tool.git
|
||||
GIT_TAG "${current_branch}"
|
||||
)
|
||||
FetchContent_MakeAvailable(validator_keys)
|
||||
set_target_properties(validator-keys PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
install(TARGETS validator-keys RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
FetchContent_GetProperties (validator_keys_src)
|
||||
if (NOT validator_keys_src_POPULATED)
|
||||
message (STATUS "Pausing to download ValidatorKeys...")
|
||||
FetchContent_Populate (validator_keys_src)
|
||||
endif ()
|
||||
add_subdirectory (${validator_keys_src_SOURCE_DIR} ${CMAKE_BINARY_DIR}/validator-keys)
|
||||
endif ()
|
||||
|
||||
@@ -7,7 +7,7 @@ function(xrpl_add_test name)
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}/*.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${name}.cpp"
|
||||
)
|
||||
add_executable(${target} ${ARGN} ${sources})
|
||||
add_executable(${target} EXCLUDE_FROM_ALL ${ARGN} ${sources})
|
||||
|
||||
isolate_headers(
|
||||
${target}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"rocksdb/10.0.1#85537f46e538974d67da0c3977de48ac%1756234304.347",
|
||||
"re2/20230301#dfd6e2bf050eb90ddd8729cfb4c844a4%1756234257.976",
|
||||
"protobuf/3.21.12#d927114e28de9f4691a6bbcdd9a529d1%1756234251.614",
|
||||
"openssl/3.5.4#a1d5835cc6ed5c5b8f3cd5b9b5d24205%1759746684.671",
|
||||
"openssl/3.5.2#0c5a5e15ae569f45dff57adcf1770cf7%1756234259.61",
|
||||
"nudb/2.0.9#c62cfd501e57055a7e0d8ee3d5e5427d%1756234237.107",
|
||||
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1756234228.999",
|
||||
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1756223727.64",
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Global configuration for Conan. This is used to set the number of parallel
|
||||
# downloads and uploads.
|
||||
# downloads, uploads, and build jobs. The verbosity is set to verbose to
|
||||
# provide more information during the build process.
|
||||
core:non_interactive=True
|
||||
core.download:parallel={{ os.cpu_count() }}
|
||||
core.upload:parallel={{ os.cpu_count() }}
|
||||
tools.build:jobs={{ (os.cpu_count() * 4/5) | int }}
|
||||
tools.build:verbosity=verbose
|
||||
tools.compilation:verbosity=verbose
|
||||
|
||||
@@ -21,11 +21,14 @@ compiler.libcxx={{detect_api.detect_libcxx(compiler, version, compiler_exe)}}
|
||||
|
||||
[conf]
|
||||
{% if compiler == "clang" and compiler_version >= 19 %}
|
||||
grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw']
|
||||
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
|
||||
{% endif %}
|
||||
{% if compiler == "apple-clang" and compiler_version >= 17 %}
|
||||
grpc/1.50.1:tools.build:cxxflags+=['-Wno-missing-template-arg-list-after-template-kw']
|
||||
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
|
||||
{% endif %}
|
||||
{% if compiler == "gcc" and compiler_version < 13 %}
|
||||
tools.build:cxxflags+=['-Wno-restrict']
|
||||
tools.build:cxxflags=['-Wno-restrict']
|
||||
{% endif %}
|
||||
|
||||
[tool_requires]
|
||||
!cmake/*: cmake/[>=3 <4]
|
||||
|
||||
@@ -27,7 +27,7 @@ class Xrpl(ConanFile):
|
||||
'grpc/1.50.1',
|
||||
'libarchive/3.8.1',
|
||||
'nudb/2.0.9',
|
||||
'openssl/3.5.4',
|
||||
'openssl/3.5.2',
|
||||
'soci/4.0.3',
|
||||
'zlib/1.3.1',
|
||||
]
|
||||
|
||||
@@ -654,14 +654,12 @@ SharedWeakUnion<T>::convertToWeak()
|
||||
break;
|
||||
case destroy:
|
||||
// We just added a weak ref. How could we destroy?
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"ripple::SharedWeakUnion::convertToWeak : destroying freshly "
|
||||
"added ref");
|
||||
delete p;
|
||||
unsafeSetRawPtr(nullptr);
|
||||
return true; // Should never happen
|
||||
// LCOV_EXCL_STOP
|
||||
case partialDestroy:
|
||||
// This is a weird case. We just converted the last strong
|
||||
// pointer to a weak pointer.
|
||||
|
||||
@@ -170,6 +170,9 @@ public:
|
||||
bool
|
||||
retrieve(key_type const& key, T& data);
|
||||
|
||||
mutex_type&
|
||||
peekMutex();
|
||||
|
||||
std::vector<key_type>
|
||||
getKeys() const;
|
||||
|
||||
|
||||
@@ -668,6 +668,29 @@ TaggedCache<
|
||||
return true;
|
||||
}
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
bool IsKeyCache,
|
||||
class SharedWeakUnionPointer,
|
||||
class SharedPointerType,
|
||||
class Hash,
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline auto
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::peekMutex() -> mutex_type&
|
||||
{
|
||||
return m_mutex;
|
||||
}
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
|
||||
@@ -632,16 +632,6 @@ 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)
|
||||
{
|
||||
static_assert(
|
||||
base_uint<Bits, Tag>::bytes > 4,
|
||||
"For 4 bytes or less, use a native type");
|
||||
return strHex(a.cbegin(), a.cbegin() + 4) + "...";
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& out, base_uint<Bits, Tag> const& u)
|
||||
|
||||
@@ -28,8 +28,9 @@ namespace ripple {
|
||||
// the destination can hold all values of the source. This is particularly
|
||||
// handy when the source or destination is an enumeration type.
|
||||
|
||||
template <class Src, class Dest>
|
||||
concept SafeToCast = (std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
|
||||
template <class Dest, class Src>
|
||||
static constexpr bool is_safetocasttovalue_v =
|
||||
(std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
|
||||
(std::is_signed<Src>::value || std::is_unsigned<Dest>::value) &&
|
||||
(std::is_signed<Src>::value != std::is_signed<Dest>::value
|
||||
? sizeof(Dest) > sizeof(Src)
|
||||
@@ -77,7 +78,7 @@ inline constexpr std::
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
static_assert(
|
||||
!SafeToCast<Src, Dest>,
|
||||
!is_safetocasttovalue_v<Dest, Src>,
|
||||
"Only unsafe if casting signed to unsigned or "
|
||||
"destination is too small");
|
||||
return static_cast<Dest>(s);
|
||||
|
||||
@@ -94,11 +94,7 @@ hash_append(Hasher& h, beast::IP::Address const& addr) noexcept
|
||||
else if (addr.is_v6())
|
||||
hash_append(h, addr.to_v6().to_bytes());
|
||||
else
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("beast::hash_append : invalid address type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
} // namespace beast
|
||||
|
||||
|
||||
@@ -39,16 +39,11 @@ 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
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
* without formatting (not human friendly).
|
||||
*
|
||||
* The JSON document is written in a single line. It is not intended for 'human'
|
||||
* consumption, but may be useful to support feature such as RPC where bandwidth
|
||||
* consumption, but may be useful to support feature such as RPC where bandwith
|
||||
* is limited. \sa Reader, Value
|
||||
*/
|
||||
|
||||
|
||||
@@ -284,14 +284,12 @@ public:
|
||||
{
|
||||
if (key.type != ltOFFER)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"ripple::ApplyView::dirAppend : only Offers are appended to "
|
||||
"book directories");
|
||||
// Only Offers are appended to book directories. Call dirInsert()
|
||||
// instead
|
||||
return std::nullopt;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
return dirAdd(true, directory, key.key, describe);
|
||||
}
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 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_APP_LEDGER_INDEX_MAP_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_INDEX_MAP_H_INCLUDED
|
||||
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
template <class Key, class Mapped>
|
||||
class LedgerIndexMap
|
||||
{
|
||||
public:
|
||||
LedgerIndexMap() = default;
|
||||
explicit LedgerIndexMap(std::size_t reserve_capacity)
|
||||
{
|
||||
data_.reserve(reserve_capacity);
|
||||
}
|
||||
|
||||
LedgerIndexMap(LedgerIndexMap const&) = delete;
|
||||
LedgerIndexMap&
|
||||
operator=(LedgerIndexMap const&) = delete;
|
||||
LedgerIndexMap(LedgerIndexMap&&) = delete;
|
||||
LedgerIndexMap&
|
||||
operator=(LedgerIndexMap&&) = delete;
|
||||
|
||||
Mapped&
|
||||
operator[](Key const& k)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return data_[k];
|
||||
}
|
||||
|
||||
Mapped&
|
||||
operator[](Key&& k)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return data_[std::move(k)];
|
||||
}
|
||||
|
||||
[[nodiscard]] Mapped*
|
||||
get(Key const& k)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
auto it = data_.find(k);
|
||||
return it == data_.end() ? nullptr : &it->second;
|
||||
}
|
||||
|
||||
[[nodiscard]] Mapped const*
|
||||
get(Key const& k) const
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
auto it = data_.find(k);
|
||||
return it == data_.end() ? nullptr : &it->second;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
Mapped&
|
||||
put(Key const& k, Args&&... args)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
auto [it, inserted] = data_.try_emplace(k, std::forward<Args>(args)...);
|
||||
if (!inserted)
|
||||
it->second = Mapped(std::forward<Args>(args)...);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool
|
||||
contains(Key const& k) const
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return data_.find(k) != data_.end();
|
||||
}
|
||||
|
||||
std::size_t
|
||||
size() const noexcept
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
bool
|
||||
empty() const noexcept
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
return data_.empty();
|
||||
}
|
||||
|
||||
void
|
||||
reserve(std::size_t n)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
data_.reserve(n);
|
||||
}
|
||||
|
||||
void
|
||||
rehash(std::size_t n)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
data_.rehash(n);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
eraseBefore(Key const& cutoff)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
auto const before = data_.size();
|
||||
std::erase_if(data_, [&](auto const& kv) { return kv.first < cutoff; });
|
||||
return before - data_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<Key, Mapped> data_;
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // RIPPLE_APP_LEDGER_INDEX_MAP_H_INCLUDED
|
||||
@@ -561,28 +561,12 @@ createPseudoAccount(
|
||||
[[nodiscard]] bool
|
||||
isPseudoAccount(std::shared_ptr<SLE const> sleAcct);
|
||||
|
||||
// Returns the list of fields that define an ACCOUNT_ROOT as a pseudo-account if
|
||||
// set
|
||||
// Pseudo-account designator fields MUST be maintained by including the
|
||||
// SField::sMD_PseudoAccount flag in the SField definition. (Don't forget to
|
||||
// "| SField::sMD_Default"!) The fields do NOT need to be amendment-gated,
|
||||
// since a non-active amendment will not set any field, by definition.
|
||||
// Specific properties of a pseudo-account are NOT checked here, that's what
|
||||
// InvariantCheck is for.
|
||||
[[nodiscard]] std::vector<SField const*> const&
|
||||
getPseudoAccountFields();
|
||||
|
||||
[[nodiscard]] inline bool
|
||||
isPseudoAccount(ReadView const& view, AccountID accountId)
|
||||
{
|
||||
return isPseudoAccount(view.read(keylet::account(accountId)));
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
canAddHolding(ReadView const& view, Asset const& asset);
|
||||
|
||||
/// Any transactors that call addEmptyHolding() in doApply must call
|
||||
/// canAddHolding() in preflight with the same View and Asset
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
|
||||
565
include/xrpl/protocol/FeeUnits.h
Normal file
565
include/xrpl/protocol/FeeUnits.h
Normal file
@@ -0,0 +1,565 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2019 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 BASICS_FEES_H_INCLUDED
|
||||
#define BASICS_FEES_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace feeunit {
|
||||
|
||||
/** "drops" are the smallest divisible amount of XRP. This is what most
|
||||
of the code uses. */
|
||||
struct dropTag;
|
||||
/** "fee units" calculations are a not-really-unitless value that is used
|
||||
to express the cost of a given transaction vs. a reference transaction.
|
||||
They are primarily used by the Transactor classes. */
|
||||
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
|
||||
used for calculations in this header. */
|
||||
struct unitlessTag;
|
||||
|
||||
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> &&
|
||||
std::is_object_v<typename T::value_type>>;
|
||||
|
||||
/** `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
|
||||
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>;
|
||||
|
||||
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>>
|
||||
{
|
||||
public:
|
||||
using unit_type = UnitTag;
|
||||
using value_type = T;
|
||||
|
||||
private:
|
||||
value_type fee_;
|
||||
|
||||
protected:
|
||||
template <class Other>
|
||||
static constexpr bool is_compatible_v =
|
||||
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 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>>;
|
||||
|
||||
public:
|
||||
TaggedFee() = default;
|
||||
constexpr TaggedFee(TaggedFee const& other) = default;
|
||||
constexpr TaggedFee&
|
||||
operator=(TaggedFee const& other) = default;
|
||||
|
||||
constexpr explicit TaggedFee(beast::Zero) : fee_(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr TaggedFee&
|
||||
operator=(beast::Zero)
|
||||
{
|
||||
fee_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr explicit TaggedFee(value_type fee) : fee_(fee)
|
||||
{
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator=(value_type fee)
|
||||
{
|
||||
fee_ = fee;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Instances with the same unit, and a type that is
|
||||
"safe" to convert to this one can be converted
|
||||
implicitly */
|
||||
template <
|
||||
class Other,
|
||||
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 TaggedFee
|
||||
operator*(value_type const& rhs) const
|
||||
{
|
||||
return TaggedFee{fee_ * rhs};
|
||||
}
|
||||
|
||||
friend constexpr TaggedFee
|
||||
operator*(value_type lhs, TaggedFee const& rhs)
|
||||
{
|
||||
// multiplication is commutative
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
constexpr value_type
|
||||
operator/(TaggedFee const& rhs) const
|
||||
{
|
||||
return fee_ / rhs.fee_;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator+=(TaggedFee const& other)
|
||||
{
|
||||
fee_ += other.fee();
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator-=(TaggedFee const& other)
|
||||
{
|
||||
fee_ -= other.fee();
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator++()
|
||||
{
|
||||
++fee_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator--()
|
||||
{
|
||||
--fee_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator*=(value_type const& rhs)
|
||||
{
|
||||
fee_ *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee&
|
||||
operator/=(value_type const& rhs)
|
||||
{
|
||||
fee_ /= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class transparent = value_type>
|
||||
std::enable_if_t<std::is_integral_v<transparent>, TaggedFee&>
|
||||
operator%=(value_type const& rhs)
|
||||
{
|
||||
fee_ %= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedFee
|
||||
operator-() const
|
||||
{
|
||||
static_assert(
|
||||
std::is_signed_v<T>, "- operator illegal on unsigned fee types");
|
||||
return TaggedFee{-fee_};
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(TaggedFee const& other) const
|
||||
{
|
||||
return fee_ == other.fee_;
|
||||
}
|
||||
|
||||
template <class Other, class = enable_if_compatible_t<Other>>
|
||||
bool
|
||||
operator==(TaggedFee<unit_type, Other> const& other) const
|
||||
{
|
||||
return fee_ == other.fee();
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(value_type other) const
|
||||
{
|
||||
return fee_ == other;
|
||||
}
|
||||
|
||||
template <class Other, class = enable_if_compatible_t<Other>>
|
||||
bool
|
||||
operator!=(TaggedFee<unit_type, Other> const& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(TaggedFee const& other) const
|
||||
{
|
||||
return fee_ < other.fee_;
|
||||
}
|
||||
|
||||
/** Returns true if the amount is not zero */
|
||||
explicit constexpr
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return fee_ != 0;
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
constexpr int
|
||||
signum() const noexcept
|
||||
{
|
||||
return (fee_ < 0) ? -1 : (fee_ ? 1 : 0);
|
||||
}
|
||||
|
||||
/** Returns the number of drops */
|
||||
constexpr value_type
|
||||
fee() const
|
||||
{
|
||||
return fee_;
|
||||
}
|
||||
|
||||
template <class Other>
|
||||
constexpr double
|
||||
decimalFromReference(TaggedFee<unit_type, Other> reference) const
|
||||
{
|
||||
return static_cast<double>(fee_) / reference.fee();
|
||||
}
|
||||
|
||||
// `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>
|
||||
jsonClipped() const
|
||||
{
|
||||
if constexpr (std::is_integral_v<value_type>)
|
||||
{
|
||||
using jsontype = std::conditional_t<
|
||||
std::is_signed_v<value_type>,
|
||||
Json::Int,
|
||||
Json::UInt>;
|
||||
|
||||
constexpr auto min = std::numeric_limits<jsontype>::min();
|
||||
constexpr auto max = std::numeric_limits<jsontype>::max();
|
||||
|
||||
if (fee_ < min)
|
||||
return min;
|
||||
if (fee_ > max)
|
||||
return max;
|
||||
return static_cast<jsontype>(fee_);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fee_;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the underlying value. Code SHOULD NOT call this
|
||||
function unless the type has been abstracted away,
|
||||
e.g. in a templated function.
|
||||
*/
|
||||
constexpr value_type
|
||||
value() const
|
||||
{
|
||||
return fee_;
|
||||
}
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& s, TaggedFee& val)
|
||||
{
|
||||
s >> val.fee_;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
// Output Fees 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, TaggedFee<UnitTag, T> const& q)
|
||||
{
|
||||
return os << q.value();
|
||||
}
|
||||
|
||||
template <class UnitTag, class T>
|
||||
std::string
|
||||
to_string(TaggedFee<UnitTag, T> const& amount)
|
||||
{
|
||||
return std::to_string(amount.fee());
|
||||
}
|
||||
|
||||
template <class Source, class = enable_if_unit_t<Source>>
|
||||
constexpr bool can_muldiv_source_v =
|
||||
std::is_convertible_v<typename Source::value_type, std::uint64_t>;
|
||||
|
||||
template <class Dest, class = enable_if_unit_t<Dest>>
|
||||
constexpr bool can_muldiv_dest_v =
|
||||
can_muldiv_source_v<Dest> && // Dest is also a source
|
||||
std::is_convertible_v<std::uint64_t, typename Dest::value_type> &&
|
||||
sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class = enable_if_unit_t<Source1>,
|
||||
class = enable_if_unit_t<Source2>>
|
||||
constexpr bool can_muldiv_sources_v =
|
||||
can_muldiv_source_v<Source1> && can_muldiv_source_v<Source2> &&
|
||||
std::is_same_v<typename Source1::unit_type, typename Source2::unit_type>;
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = enable_if_unit_t<Source1>,
|
||||
class = enable_if_unit_t<Source2>,
|
||||
class = enable_if_unit_t<Dest>>
|
||||
constexpr bool can_muldiv_v =
|
||||
can_muldiv_sources_v<Source1, Source2> && can_muldiv_dest_v<Dest>;
|
||||
// Source and Dest can be the same by default
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = enable_if_unit_t<Source1>,
|
||||
class = enable_if_unit_t<Source2>,
|
||||
class = enable_if_unit_t<Dest>>
|
||||
constexpr bool can_muldiv_commute_v = can_muldiv_v<Source1, Source2, Dest> &&
|
||||
!std::is_same_v<typename Source1::unit_type, typename Dest::unit_type>;
|
||||
|
||||
template <class T>
|
||||
using enable_muldiv_source_t =
|
||||
typename std::enable_if_t<can_muldiv_source_v<T>>;
|
||||
|
||||
template <class T>
|
||||
using enable_muldiv_dest_t = typename std::enable_if_t<can_muldiv_dest_v<T>>;
|
||||
|
||||
template <class Source1, class Source2>
|
||||
using enable_muldiv_sources_t =
|
||||
typename std::enable_if_t<can_muldiv_sources_v<Source1, Source2>>;
|
||||
|
||||
template <class Source1, class Source2, class Dest>
|
||||
using enable_muldiv_t =
|
||||
typename std::enable_if_t<can_muldiv_v<Source1, Source2, Dest>>;
|
||||
|
||||
template <class Source1, class Source2, class Dest>
|
||||
using enable_muldiv_commute_t =
|
||||
typename std::enable_if_t<can_muldiv_commute_v<Source1, Source2, Dest>>;
|
||||
|
||||
template <class T>
|
||||
TaggedFee<unitlessTag, T>
|
||||
scalar(T value)
|
||||
{
|
||||
return TaggedFee<unitlessTag, T>{value};
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = enable_muldiv_t<Source1, Source2, Dest>>
|
||||
std::optional<Dest>
|
||||
mulDivU(Source1 value, Dest mul, Source2 div)
|
||||
{
|
||||
// Fees 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");
|
||||
XRPL_ASSERT(
|
||||
mul.value() >= 0, "ripple::feeunit::mulDivU : minimum mul input");
|
||||
XRPL_ASSERT(
|
||||
div.value() >= 0, "ripple::feeunit::mulDivU : minimum div input");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
using desttype = typename Dest::value_type;
|
||||
constexpr auto max = std::numeric_limits<desttype>::max();
|
||||
|
||||
// Shortcuts, since these happen a lot in the real world
|
||||
if (value == div)
|
||||
return mul;
|
||||
if (mul.value() == div.value())
|
||||
{
|
||||
if (value.value() > max)
|
||||
return std::nullopt;
|
||||
return Dest{static_cast<desttype>(value.value())};
|
||||
}
|
||||
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
uint128_t product;
|
||||
product = multiply(
|
||||
product,
|
||||
static_cast<std::uint64_t>(value.value()),
|
||||
static_cast<std::uint64_t>(mul.value()));
|
||||
|
||||
auto quotient = product / div.value();
|
||||
|
||||
if (quotient > max)
|
||||
return std::nullopt;
|
||||
|
||||
return Dest{static_cast<desttype>(quotient)};
|
||||
}
|
||||
|
||||
} // namespace feeunit
|
||||
|
||||
template <class T>
|
||||
using FeeLevel = feeunit::TaggedFee<feeunit::feelevelTag, T>;
|
||||
using FeeLevel64 = FeeLevel<std::uint64_t>;
|
||||
using FeeLevelDouble = FeeLevel<double>;
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = feeunit::enable_muldiv_t<Source1, Source2, Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(Source1 value, Dest mul, Source2 div)
|
||||
{
|
||||
return feeunit::mulDivU(value, mul, div);
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class Dest,
|
||||
class = feeunit::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);
|
||||
}
|
||||
|
||||
template <class Dest, class = feeunit::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));
|
||||
}
|
||||
|
||||
template <class Dest, class = feeunit::enable_muldiv_dest_t<Dest>>
|
||||
std::optional<Dest>
|
||||
mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return mulDiv(mul, value, div);
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class = feeunit::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);
|
||||
|
||||
if (!unitresult)
|
||||
return std::nullopt;
|
||||
|
||||
return unitresult->value();
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
class = feeunit::enable_muldiv_sources_t<Source1, Source2>>
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(std::uint64_t value, Source1 mul, Source2 div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return mulDiv(mul, value, div);
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
|
||||
std::is_integral_v<typename Dest::value_type> &&
|
||||
std::is_integral_v<typename Src::value_type>,
|
||||
Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{safe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_same_v<typename Dest::unit_type, typename Src::unit_type> &&
|
||||
std::is_integral_v<typename Dest::value_type> &&
|
||||
std::is_integral_v<typename Src::value_type>,
|
||||
Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif // BASICS_FEES_H_INCLUDED
|
||||
@@ -54,11 +54,11 @@ class SeqProxy;
|
||||
namespace keylet {
|
||||
|
||||
/** AccountID root */
|
||||
Keylet
|
||||
TypedKeylet<ltACCOUNT_ROOT>
|
||||
account(AccountID const& id) noexcept;
|
||||
|
||||
/** The index of the amendment table */
|
||||
Keylet const&
|
||||
TypedKeylet<ltAMENDMENTS> const&
|
||||
amendments() noexcept;
|
||||
|
||||
/** Any item that can be in an owner dir. */
|
||||
@@ -70,7 +70,7 @@ child(uint256 const& key) noexcept;
|
||||
The "short" skip list is a node (at a fixed index) that holds the hashes
|
||||
of ledgers since the last flag ledger. It will contain, at most, 256 hashes.
|
||||
*/
|
||||
Keylet const&
|
||||
TypedKeylet<ltLEDGER_HASHES> const&
|
||||
skip() noexcept;
|
||||
|
||||
/** The index of the long skip for a particular ledger range.
|
||||
@@ -83,15 +83,15 @@ skip() noexcept;
|
||||
and uses it to get the hash of the flag ledger whose short skip list will
|
||||
contain the hash of the requested ledger.
|
||||
*/
|
||||
Keylet
|
||||
TypedKeylet<ltLEDGER_HASHES>
|
||||
skip(LedgerIndex ledger) noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing the ledger fees. */
|
||||
Keylet const&
|
||||
TypedKeylet<ltFEE_SETTINGS> const&
|
||||
fees() noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing the ledger negativeUNL. */
|
||||
Keylet const&
|
||||
TypedKeylet<ltNEGATIVE_UNL> const&
|
||||
negativeUNL() noexcept;
|
||||
|
||||
/** The beginning of an order book */
|
||||
@@ -99,7 +99,7 @@ struct book_t
|
||||
{
|
||||
explicit book_t() = default;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
operator()(Book const& b) const;
|
||||
};
|
||||
static book_t const book{};
|
||||
@@ -112,13 +112,13 @@ static book_t const book{};
|
||||
between them.
|
||||
*/
|
||||
/** @{ */
|
||||
Keylet
|
||||
TypedKeylet<ltRIPPLE_STATE>
|
||||
line(
|
||||
AccountID const& id0,
|
||||
AccountID const& id1,
|
||||
Currency const& currency) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltRIPPLE_STATE>
|
||||
line(AccountID const& id, Issue const& issue) noexcept
|
||||
{
|
||||
return line(id, issue.account, issue.currency);
|
||||
@@ -127,27 +127,27 @@ line(AccountID const& id, Issue const& issue) noexcept
|
||||
|
||||
/** An offer from an account */
|
||||
/** @{ */
|
||||
Keylet
|
||||
TypedKeylet<ltOFFER>
|
||||
offer(AccountID const& id, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltOFFER>
|
||||
offer(uint256 const& key) noexcept
|
||||
{
|
||||
return {ltOFFER, key};
|
||||
return {key};
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** The initial directory page for a specific quality */
|
||||
Keylet
|
||||
quality(Keylet const& k, std::uint64_t q) noexcept;
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
quality(TypedKeylet<ltDIR_NODE> const& k, std::uint64_t q) noexcept;
|
||||
|
||||
/** The directory for the next lower quality */
|
||||
struct next_t
|
||||
{
|
||||
explicit next_t() = default;
|
||||
|
||||
Keylet
|
||||
operator()(Keylet const& k) const;
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
operator()(TypedKeylet<ltDIR_NODE> const& k) const;
|
||||
};
|
||||
static next_t const next{};
|
||||
|
||||
@@ -156,50 +156,50 @@ struct ticket_t
|
||||
{
|
||||
explicit ticket_t() = default;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltTICKET>
|
||||
operator()(AccountID const& id, std::uint32_t ticketSeq) const;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltTICKET>
|
||||
operator()(AccountID const& id, SeqProxy ticketSeq) const;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltTICKET>
|
||||
operator()(uint256 const& key) const
|
||||
{
|
||||
return {ltTICKET, key};
|
||||
return {key};
|
||||
}
|
||||
};
|
||||
static ticket_t const ticket{};
|
||||
|
||||
/** A SignerList */
|
||||
Keylet
|
||||
TypedKeylet<ltSIGNER_LIST>
|
||||
signers(AccountID const& account) noexcept;
|
||||
|
||||
/** A Check */
|
||||
/** @{ */
|
||||
Keylet
|
||||
TypedKeylet<ltCHECK>
|
||||
check(AccountID const& id, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltCHECK>
|
||||
check(uint256 const& key) noexcept
|
||||
{
|
||||
return {ltCHECK, key};
|
||||
return {key};
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** A DepositPreauth */
|
||||
/** @{ */
|
||||
Keylet
|
||||
TypedKeylet<ltDEPOSIT_PREAUTH>
|
||||
depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDEPOSIT_PREAUTH>
|
||||
depositPreauth(
|
||||
AccountID const& owner,
|
||||
std::set<std::pair<AccountID, Slice>> const& authCreds) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltDEPOSIT_PREAUTH>
|
||||
depositPreauth(uint256 const& key) noexcept
|
||||
{
|
||||
return {ltDEPOSIT_PREAUTH, key};
|
||||
return {key};
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@@ -210,15 +210,15 @@ Keylet
|
||||
unchecked(uint256 const& key) noexcept;
|
||||
|
||||
/** The root page of an account's directory */
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
ownerDir(AccountID const& id) noexcept;
|
||||
|
||||
/** A page in a directory */
|
||||
/** @{ */
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
page(uint256 const& root, std::uint64_t index = 0) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltDIR_NODE>
|
||||
page(Keylet const& root, std::uint64_t index = 0) noexcept
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
@@ -228,11 +228,11 @@ page(Keylet const& root, std::uint64_t index = 0) noexcept
|
||||
/** @} */
|
||||
|
||||
/** An escrow entry */
|
||||
Keylet
|
||||
TypedKeylet<ltESCROW>
|
||||
escrow(AccountID const& src, std::uint32_t seq) noexcept;
|
||||
|
||||
/** A PaymentChannel */
|
||||
Keylet
|
||||
TypedKeylet<ltPAYCHAN>
|
||||
payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
|
||||
|
||||
/** NFT page keylets
|
||||
@@ -244,112 +244,112 @@ payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
|
||||
*/
|
||||
/** @{ */
|
||||
/** A keylet for the owner's first possible NFT page. */
|
||||
Keylet
|
||||
TypedKeylet<ltNFTOKEN_PAGE>
|
||||
nftpage_min(AccountID const& owner);
|
||||
|
||||
/** A keylet for the owner's last possible NFT page. */
|
||||
Keylet
|
||||
TypedKeylet<ltNFTOKEN_PAGE>
|
||||
nftpage_max(AccountID const& owner);
|
||||
|
||||
Keylet
|
||||
nftpage(Keylet const& k, uint256 const& token);
|
||||
TypedKeylet<ltNFTOKEN_PAGE>
|
||||
nftpage(TypedKeylet<ltNFTOKEN_PAGE> const& k, uint256 const& token);
|
||||
/** @} */
|
||||
|
||||
/** An offer from an account to buy or sell an NFT */
|
||||
Keylet
|
||||
TypedKeylet<ltNFTOKEN_OFFER>
|
||||
nftoffer(AccountID const& owner, std::uint32_t seq);
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltNFTOKEN_OFFER>
|
||||
nftoffer(uint256 const& offer)
|
||||
{
|
||||
return {ltNFTOKEN_OFFER, offer};
|
||||
return {offer};
|
||||
}
|
||||
|
||||
/** The directory of buy offers for the specified NFT */
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
nft_buys(uint256 const& id) noexcept;
|
||||
|
||||
/** The directory of sell offers for the specified NFT */
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
nft_sells(uint256 const& id) noexcept;
|
||||
|
||||
/** AMM entry */
|
||||
Keylet
|
||||
TypedKeylet<ltAMM>
|
||||
amm(Asset const& issue1, Asset const& issue2) noexcept;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltAMM>
|
||||
amm(uint256 const& amm) noexcept;
|
||||
|
||||
/** A keylet for Delegate object */
|
||||
Keylet
|
||||
TypedKeylet<ltDELEGATE>
|
||||
delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltBRIDGE>
|
||||
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType);
|
||||
|
||||
// `seq` is stored as `sfXChainClaimID` in the object
|
||||
Keylet
|
||||
TypedKeylet<ltXCHAIN_OWNED_CLAIM_ID>
|
||||
xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq);
|
||||
|
||||
// `seq` is stored as `sfXChainAccountCreateCount` in the object
|
||||
Keylet
|
||||
TypedKeylet<ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID>
|
||||
xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq);
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDID>
|
||||
did(AccountID const& account) noexcept;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltORACLE>
|
||||
oracle(AccountID const& account, std::uint32_t const& documentID) noexcept;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltCREDENTIAL>
|
||||
credential(
|
||||
AccountID const& subject,
|
||||
AccountID const& issuer,
|
||||
Slice const& credType) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltCREDENTIAL>
|
||||
credential(uint256 const& key) noexcept
|
||||
{
|
||||
return {ltCREDENTIAL, key};
|
||||
return {key};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltMPTOKEN_ISSUANCE>
|
||||
mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltMPTOKEN_ISSUANCE>
|
||||
mptIssuance(MPTID const& issuanceID) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltMPTOKEN_ISSUANCE>
|
||||
mptIssuance(uint256 const& issuanceKey)
|
||||
{
|
||||
return {ltMPTOKEN_ISSUANCE, issuanceKey};
|
||||
return {issuanceKey};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltMPTOKEN>
|
||||
mptoken(MPTID const& issuanceID, AccountID const& holder) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltMPTOKEN>
|
||||
mptoken(uint256 const& mptokenKey)
|
||||
{
|
||||
return {ltMPTOKEN, mptokenKey};
|
||||
return {mptokenKey};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltMPTOKEN>
|
||||
mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltVAULT>
|
||||
vault(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
inline TypedKeylet<ltVAULT>
|
||||
vault(uint256 const& vaultKey)
|
||||
{
|
||||
return {ltVAULT, vaultKey};
|
||||
return {vaultKey};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltPERMISSIONED_DOMAIN>
|
||||
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept;
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltPERMISSIONED_DOMAIN>
|
||||
permissionedDomain(uint256 const& domainID) noexcept;
|
||||
} // namespace keylet
|
||||
|
||||
|
||||
@@ -49,6 +49,22 @@ struct Keylet
|
||||
check(STLedgerEntry const&) const;
|
||||
};
|
||||
|
||||
template <LedgerEntryType Type>
|
||||
struct TypedKeylet : Keylet
|
||||
{
|
||||
static constexpr LedgerEntryType LedgerType = Type;
|
||||
|
||||
TypedKeylet(uint256 const& key_) : Keylet(Type, key_)
|
||||
{
|
||||
}
|
||||
|
||||
Keylet
|
||||
untyped() const
|
||||
{
|
||||
return Keylet(LedgerType, key);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -55,13 +55,33 @@ enum LedgerEntryType : std::uint16_t
|
||||
|
||||
#pragma push_macro("LEDGER_ENTRY")
|
||||
#undef LEDGER_ENTRY
|
||||
#pragma push_macro("LEDGER_ENTRY_FIELD")
|
||||
#undef LEDGER_ENTRY_FIELD
|
||||
#pragma push_macro("DEFINE_LEDGER_ENTRY_FIELDS")
|
||||
#undef DEFINE_LEDGER_ENTRY_FIELDS
|
||||
#pragma push_macro("LEDGER_ENTRIES_BEGIN")
|
||||
#undef LEDGER_ENTRIES_BEGIN
|
||||
#pragma push_macro("LEDGER_ENTRIES_END")
|
||||
#undef LEDGER_ENTRIES_END
|
||||
|
||||
#define LEDGER_ENTRY(tag, value, ...) tag = value,
|
||||
#define LEDGER_ENTRIES_BEGIN
|
||||
#define LEDGER_ENTRIES_END
|
||||
#define DEFINE_LEDGER_ENTRY_FIELDS(...) ({__VA_ARGS__})
|
||||
#define LEDGER_ENTRY_FIELD(...) {__VA_ARGS__},
|
||||
#define LEDGER_ENTRY(tag, value, name, rpcName, fields) tag = value,
|
||||
|
||||
#include <xrpl/protocol/detail/ledger_entries.macro>
|
||||
|
||||
#undef LEDGER_ENTRY
|
||||
#pragma pop_macro("LEDGER_ENTRY")
|
||||
#undef LEDGER_ENTRY_FIELD
|
||||
#pragma pop_macro("LEDGER_ENTRY_FIELD")
|
||||
#undef DEFINE_LEDGER_ENTRY_FIELDS
|
||||
#pragma pop_macro("DEFINE_LEDGER_ENTRY_FIELDS")
|
||||
#undef LEDGER_ENTRIES_BEGIN
|
||||
#pragma pop_macro("LEDGER_ENTRIES_BEGIN")
|
||||
#undef LEDGER_ENTRIES_END
|
||||
#pragma pop_macro("LEDGER_ENTRIES_END")
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
/** A special type, matching any ledger entry type.
|
||||
@@ -188,14 +208,14 @@ enum LedgerSpecificFlags {
|
||||
lsfMPTCanTransfer = 0x00000020,
|
||||
lsfMPTCanClawback = 0x00000040,
|
||||
|
||||
lsmfMPTCanMutateCanLock = 0x00000002,
|
||||
lsmfMPTCanMutateRequireAuth = 0x00000004,
|
||||
lsmfMPTCanMutateCanEscrow = 0x00000008,
|
||||
lsmfMPTCanMutateCanTrade = 0x00000010,
|
||||
lsmfMPTCanMutateCanTransfer = 0x00000020,
|
||||
lsmfMPTCanMutateCanClawback = 0x00000040,
|
||||
lsmfMPTCanMutateMetadata = 0x00010000,
|
||||
lsmfMPTCanMutateTransferFee = 0x00020000,
|
||||
lmfMPTCanMutateCanLock = 0x00000002,
|
||||
lmfMPTCanMutateRequireAuth = 0x00000004,
|
||||
lmfMPTCanMutateCanEscrow = 0x00000008,
|
||||
lmfMPTCanMutateCanTrade = 0x00000010,
|
||||
lmfMPTCanMutateCanTransfer = 0x00000020,
|
||||
lmfMPTCanMutateCanClawback = 0x00000040,
|
||||
lmfMPTCanMutateMetadata = 0x00010000,
|
||||
lmfMPTCanMutateTransferFee = 0x00020000,
|
||||
|
||||
// ltMPTOKEN
|
||||
lsfMPTAuthorized = 0x00000002,
|
||||
|
||||
@@ -74,9 +74,6 @@ public:
|
||||
Permission&
|
||||
operator=(Permission const&) = delete;
|
||||
|
||||
std::optional<std::string>
|
||||
getPermissionName(std::uint32_t const value) const;
|
||||
|
||||
std::optional<std::uint32_t>
|
||||
getGranularValue(std::string const& name) const;
|
||||
|
||||
@@ -86,9 +83,6 @@ public:
|
||||
std::optional<TxType>
|
||||
getGranularTxType(GranularPermissionType const& gpType) const;
|
||||
|
||||
std::optional<std::reference_wrapper<uint256 const>> const
|
||||
getTxFeature(TxType txType) const;
|
||||
|
||||
bool
|
||||
isDelegatable(std::uint32_t const& permissionValue, Rules const& rules)
|
||||
const;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/partitioned_unordered_map.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -55,10 +56,7 @@ std::size_t constexpr oversizeMetaDataCap = 5200;
|
||||
/** The maximum number of entries per directory page */
|
||||
std::size_t constexpr dirNodeMaxEntries = 32;
|
||||
|
||||
/** The maximum number of pages allowed in a directory
|
||||
|
||||
Made obsolete by fixDirectoryLimit amendment.
|
||||
*/
|
||||
/** The maximum number of pages allowed in a directory */
|
||||
std::uint64_t constexpr dirNodeMaxPages = 262144;
|
||||
|
||||
/** The maximum number of items in an NFT page */
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#define RIPPLE_PROTOCOL_PUBLICKEY_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/beast/net/IPEndpoint.h>
|
||||
#include <xrpl/protocol/KeyType.h>
|
||||
#include <xrpl/protocol/STExchange.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
@@ -265,24 +264,6 @@ calcNodeID(PublicKey const&);
|
||||
AccountID
|
||||
calcAccountID(PublicKey const& pk);
|
||||
|
||||
inline std::string
|
||||
getFingerprint(
|
||||
beast::IP::Endpoint const& address,
|
||||
std::optional<PublicKey> const& publicKey = std::nullopt,
|
||||
std::optional<std::string> const& id = std::nullopt)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "IP Address: " << address;
|
||||
if (publicKey.has_value())
|
||||
{
|
||||
ss << ", Public Key: " << toBase58(TokenType::NodePublic, *publicKey);
|
||||
}
|
||||
if (id.has_value())
|
||||
{
|
||||
ss << ", Id: " << id.value();
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
} // namespace ripple
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
@@ -72,10 +71,8 @@ class STCurrency;
|
||||
STYPE(STI_VL, 7) \
|
||||
STYPE(STI_ACCOUNT, 8) \
|
||||
STYPE(STI_NUMBER, 9) \
|
||||
STYPE(STI_INT32, 10) \
|
||||
STYPE(STI_INT64, 11) \
|
||||
\
|
||||
/* 12-13 are reserved */ \
|
||||
/* 10-13 are reserved */ \
|
||||
STYPE(STI_OBJECT, 14) \
|
||||
STYPE(STI_ARRAY, 15) \
|
||||
\
|
||||
@@ -151,10 +148,8 @@ 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, // value is treated as base 10, overriding behavior
|
||||
sMD_PseudoAccount = 0x40, // if this field is set in an ACCOUNT_ROOT
|
||||
// _only_, then it is a pseudo-account
|
||||
sMD_Always = 0x10, // value when node containing it is affected at all
|
||||
sMD_BaseTen = 0x20,
|
||||
sMD_Default =
|
||||
sMD_ChangeOrig | sMD_ChangeNew | sMD_DeleteFinal | sMD_Create
|
||||
};
|
||||
@@ -189,7 +184,7 @@ public:
|
||||
char const* fn,
|
||||
int meta = sMD_Default,
|
||||
IsSigning signing = IsSigning::yes);
|
||||
explicit SField(private_access_tag_t, int fc, char const* fn);
|
||||
explicit SField(private_access_tag_t, int fc);
|
||||
|
||||
static SField const&
|
||||
getField(int fieldCode);
|
||||
@@ -302,7 +297,7 @@ public:
|
||||
static int
|
||||
compare(SField const& f1, SField const& f2);
|
||||
|
||||
static std::unordered_map<int, SField const*> const&
|
||||
static std::map<int, SField const*> const&
|
||||
getKnownCodeToField()
|
||||
{
|
||||
return knownCodeToField;
|
||||
@@ -310,8 +305,7 @@ public:
|
||||
|
||||
private:
|
||||
static int num;
|
||||
static std::unordered_map<int, SField const*> knownCodeToField;
|
||||
static std::unordered_map<std::string, SField const*> knownNameToField;
|
||||
static std::map<int, SField const*> knownCodeToField;
|
||||
};
|
||||
|
||||
/** A field with a type known at compile time. */
|
||||
@@ -358,9 +352,6 @@ using SF_UINT256 = TypedField<STBitString<256>>;
|
||||
using SF_UINT384 = TypedField<STBitString<384>>;
|
||||
using SF_UINT512 = TypedField<STBitString<512>>;
|
||||
|
||||
using SF_INT32 = TypedField<STInteger<std::int32_t>>;
|
||||
using SF_INT64 = TypedField<STInteger<std::int64_t>>;
|
||||
|
||||
using SF_ACCOUNT = TypedField<STAccount>;
|
||||
using SF_AMOUNT = TypedField<STAmount>;
|
||||
using SF_ISSUE = TypedField<STIssue>;
|
||||
@@ -377,11 +368,15 @@ using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>;
|
||||
#undef UNTYPED_SFIELD
|
||||
#pragma push_macro("TYPED_SFIELD")
|
||||
#undef TYPED_SFIELD
|
||||
#pragma push_macro("ARRAY_SFIELD")
|
||||
#undef ARRAY_SFIELD
|
||||
|
||||
#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \
|
||||
extern SField const sfName;
|
||||
#define TYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \
|
||||
extern SF_##stiSuffix const sfName;
|
||||
#define ARRAY_SFIELD(sfName, sfItemName, stiSuffix, fieldValue, ...) \
|
||||
UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, __VA_ARGS__)
|
||||
|
||||
extern SField const sfInvalid;
|
||||
extern SField const sfGeneric;
|
||||
@@ -392,6 +387,8 @@ extern SField const sfGeneric;
|
||||
#pragma pop_macro("TYPED_SFIELD")
|
||||
#undef UNTYPED_SFIELD
|
||||
#pragma pop_macro("UNTYPED_SFIELD")
|
||||
#undef ARRAY_SFIELD
|
||||
#pragma pop_macro("ARRAY_SFIELD")
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -709,6 +709,37 @@ canAdd(STAmount const& amt1, STAmount const& amt2);
|
||||
bool
|
||||
canSubtract(STAmount const& amt1, STAmount const& amt2);
|
||||
|
||||
// Since `canonicalize` does not have access to a ledger, this is needed to put
|
||||
// the low-level routine stAmountCanonicalize on an amendment switch. Only
|
||||
// transactions need to use this switchover. Outside of a transaction it's safe
|
||||
// to unconditionally use the new behavior.
|
||||
|
||||
bool
|
||||
getSTAmountCanonicalizeSwitchover();
|
||||
|
||||
void
|
||||
setSTAmountCanonicalizeSwitchover(bool v);
|
||||
|
||||
/** RAII class to set and restore the STAmount canonicalize switchover.
|
||||
*/
|
||||
|
||||
class STAmountSO
|
||||
{
|
||||
public:
|
||||
explicit STAmountSO(bool v) : saved_(getSTAmountCanonicalizeSwitchover())
|
||||
{
|
||||
setSTAmountCanonicalizeSwitchover(v);
|
||||
}
|
||||
|
||||
~STAmountSO()
|
||||
{
|
||||
setSTAmountCanonicalizeSwitchover(saved_);
|
||||
}
|
||||
|
||||
private:
|
||||
bool saved_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -81,8 +81,6 @@ using STUInt16 = STInteger<std::uint16_t>;
|
||||
using STUInt32 = STInteger<std::uint32_t>;
|
||||
using STUInt64 = STInteger<std::uint64_t>;
|
||||
|
||||
using STInt32 = STInteger<std::int32_t>;
|
||||
|
||||
template <typename Integer>
|
||||
inline STInteger<Integer>::STInteger(Integer v) : value_(v)
|
||||
{
|
||||
|
||||
@@ -26,9 +26,7 @@
|
||||
namespace ripple {
|
||||
|
||||
class Rules;
|
||||
namespace test {
|
||||
class Invariants_test;
|
||||
}
|
||||
|
||||
class STLedgerEntry final : public STObject, public CountedObject<STLedgerEntry>
|
||||
{
|
||||
@@ -38,8 +36,6 @@ class STLedgerEntry final : public STObject, public CountedObject<STLedgerEntry>
|
||||
public:
|
||||
using pointer = 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);
|
||||
@@ -58,7 +54,7 @@ public:
|
||||
getText() const override;
|
||||
|
||||
Json::Value
|
||||
getJson(JsonOptions options = JsonOptions::none) const override;
|
||||
getJson(JsonOptions options) const override;
|
||||
|
||||
/** Returns the 'key' (or 'index') of this item.
|
||||
The key identifies this entry's position in
|
||||
@@ -88,8 +84,7 @@ private:
|
||||
void
|
||||
setSLEType();
|
||||
|
||||
friend test::Invariants_test; // this test wants access to the private
|
||||
// type_
|
||||
friend Invariants_test; // this test wants access to the private type_
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#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>
|
||||
@@ -33,7 +34,6 @@
|
||||
#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>
|
||||
@@ -231,8 +231,6 @@ public:
|
||||
getFieldH192(SField const& field) const;
|
||||
uint256
|
||||
getFieldH256(SField const& field) const;
|
||||
std::int32_t
|
||||
getFieldI32(SField const& field) const;
|
||||
AccountID
|
||||
getAccountID(SField const& field) const;
|
||||
|
||||
@@ -244,9 +242,6 @@ public:
|
||||
getFieldPathSet(SField const& field) const;
|
||||
STVector256 const&
|
||||
getFieldV256(SField const& field) const;
|
||||
// If not found, returns an object constructed with the given field
|
||||
STObject
|
||||
getFieldObject(SField const& field) const;
|
||||
STArray const&
|
||||
getFieldArray(SField const& field) const;
|
||||
STCurrency const&
|
||||
@@ -370,8 +365,6 @@ public:
|
||||
void
|
||||
setFieldH256(SField const& field, uint256 const&);
|
||||
void
|
||||
setFieldI32(SField const& field, std::int32_t);
|
||||
void
|
||||
setFieldVL(SField const& field, Blob const&);
|
||||
void
|
||||
setFieldVL(SField const& field, Slice const&);
|
||||
@@ -393,8 +386,6 @@ public:
|
||||
setFieldV256(SField const& field, STVector256 const& v);
|
||||
void
|
||||
setFieldArray(SField const& field, STArray const& v);
|
||||
void
|
||||
setFieldObject(SField const& field, STObject const& v);
|
||||
|
||||
template <class Tag>
|
||||
void
|
||||
|
||||
@@ -54,6 +54,34 @@ public:
|
||||
Json::Value error;
|
||||
};
|
||||
|
||||
/** Holds the serialized result of parsing an input JSON array.
|
||||
This does validation and checking on the provided JSON.
|
||||
*/
|
||||
class STParsedJSONArray
|
||||
{
|
||||
public:
|
||||
/** Parses and creates an STParsedJSON array.
|
||||
The result of the parsing is stored in array and error.
|
||||
Exceptions:
|
||||
Does not throw.
|
||||
@param name The name of the JSON field, used in diagnostics.
|
||||
@param json The JSON-RPC to parse.
|
||||
*/
|
||||
STParsedJSONArray(std::string const& name, Json::Value const& json);
|
||||
|
||||
STParsedJSONArray() = delete;
|
||||
STParsedJSONArray(STParsedJSONArray const&) = delete;
|
||||
STParsedJSONArray&
|
||||
operator=(STParsedJSONArray const&) = delete;
|
||||
~STParsedJSONArray() = default;
|
||||
|
||||
/** The STArray if the parse was successful. */
|
||||
std::optional<STArray> array;
|
||||
|
||||
/** On failure, an appropriate set of error values. */
|
||||
Json::Value error;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -87,14 +87,8 @@ public:
|
||||
getFullText() const override;
|
||||
|
||||
// Outer transaction functions / signature functions.
|
||||
static Blob
|
||||
getSignature(STObject const& sigObject);
|
||||
|
||||
Blob
|
||||
getSignature() const
|
||||
{
|
||||
return getSignature(*this);
|
||||
}
|
||||
getSignature() const;
|
||||
|
||||
uint256
|
||||
getSigningHash() const;
|
||||
@@ -125,20 +119,13 @@ public:
|
||||
getJson(JsonOptions options, bool binary) const;
|
||||
|
||||
void
|
||||
sign(
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
std::optional<std::reference_wrapper<SField const>> signatureTarget =
|
||||
{});
|
||||
|
||||
enum class RequireFullyCanonicalSig : bool { no, yes };
|
||||
sign(PublicKey const& publicKey, SecretKey const& secretKey);
|
||||
|
||||
/** 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;
|
||||
@@ -163,34 +150,17 @@ public:
|
||||
char status,
|
||||
std::string const& escapedMetaData) const;
|
||||
|
||||
std::vector<uint256> const&
|
||||
std::vector<uint256>
|
||||
getBatchTransactionIDs() const;
|
||||
|
||||
private:
|
||||
/** 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 sigObject Reference to object that contains the signature fields.
|
||||
Will be *this more often than not.
|
||||
@return `true` if valid signature. If invalid, the error message string.
|
||||
*/
|
||||
Expected<void, std::string>
|
||||
checkSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules,
|
||||
STObject const& sigObject) const;
|
||||
|
||||
Expected<void, std::string>
|
||||
checkSingleSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
STObject const& sigObject) const;
|
||||
checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig) const;
|
||||
|
||||
Expected<void, std::string>
|
||||
checkMultiSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules,
|
||||
STObject const& sigObject) const;
|
||||
Rules const& rules) const;
|
||||
|
||||
Expected<void, std::string>
|
||||
checkBatchSingleSign(
|
||||
@@ -209,7 +179,7 @@ private:
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend class detail::STVar;
|
||||
mutable std::vector<uint256> batchTxnIds_;
|
||||
mutable std::vector<uint256> batch_txn_ids_;
|
||||
};
|
||||
|
||||
bool
|
||||
|
||||
@@ -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 <optional>
|
||||
|
||||
@@ -73,8 +73,14 @@ static constexpr std::uint32_t XRP_LEDGER_EARLIEST_SEQ{32570u};
|
||||
* used in asserts and tests. */
|
||||
static constexpr std::uint32_t XRP_LEDGER_EARLIEST_FEES{562177u};
|
||||
|
||||
/** The minimum amount of support an amendment should have. */
|
||||
constexpr std::ratio<80, 100> amendmentMajorityCalcThreshold;
|
||||
/** The minimum amount of support an amendment should have.
|
||||
|
||||
@note This value is used by legacy code and will become obsolete
|
||||
once the fixAmendmentMajorityCalc amendment activates.
|
||||
*/
|
||||
constexpr std::ratio<204, 256> preFixAmendmentMajorityCalcThreshold;
|
||||
|
||||
constexpr std::ratio<80, 100> postFixAmendmentMajorityCalcThreshold;
|
||||
|
||||
/** The minimum amount of time an amendment must hold a majority */
|
||||
constexpr std::chrono::seconds const defaultAmendmentMajorityTime = weeks{2};
|
||||
|
||||
@@ -225,9 +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
|
||||
terNO_DELEGATE_PERMISSION, // Delegate does not have permission
|
||||
terADDRESS_COLLISION, // Failed to allocate AccountID when trying to
|
||||
// create a pseudo-account
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -362,9 +361,6 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecLIMIT_EXCEEDED = 195,
|
||||
tecPSEUDO_ACCOUNT = 196,
|
||||
tecPRECISION_LOSS = 197,
|
||||
// DEPRECATED: This error code tecNO_DELEGATE_PERMISSION is reserved for
|
||||
// backward compatibility with historical data on non-prod networks, can be
|
||||
// reclaimed after those networks reset.
|
||||
tecNO_DELEGATE_PERMISSION = 198,
|
||||
};
|
||||
|
||||
@@ -677,8 +673,7 @@ isTerRetry(TER x) noexcept
|
||||
inline bool
|
||||
isTesSuccess(TER x) noexcept
|
||||
{
|
||||
// Makes use of TERSubset::operator bool()
|
||||
return !(x);
|
||||
return (x == tesSUCCESS);
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
||||
@@ -127,8 +127,6 @@ constexpr std::uint32_t tfTrustSetPermissionMask = ~(tfUniversal | tfSetfAuth |
|
||||
// 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;
|
||||
@@ -143,8 +141,7 @@ constexpr std::uint32_t const tfTransferable = 0x00000008;
|
||||
constexpr std::uint32_t const tfMutable = 0x00000010;
|
||||
|
||||
// MPTokenIssuanceCreate flags:
|
||||
// Note: tf/lsfMPTLocked is intentionally omitted, since this transaction
|
||||
// is not allowed to modify it.
|
||||
// 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;
|
||||
@@ -156,14 +153,14 @@ constexpr std::uint32_t const tfMPTokenIssuanceCreateMask =
|
||||
|
||||
// MPTokenIssuanceCreate MutableFlags:
|
||||
// Indicating specific fields or flags may be changed after issuance.
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanLock = lsmfMPTCanMutateCanLock;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateRequireAuth = lsmfMPTCanMutateRequireAuth;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanEscrow = lsmfMPTCanMutateCanEscrow;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanTrade = lsmfMPTCanMutateCanTrade;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanTransfer = lsmfMPTCanMutateCanTransfer;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanClawback = lsmfMPTCanMutateCanClawback;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanLock = lmfMPTCanMutateCanLock;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateRequireAuth = lmfMPTCanMutateRequireAuth;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanEscrow = lmfMPTCanMutateCanEscrow;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanTrade = lmfMPTCanMutateCanTrade;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanTransfer = lmfMPTCanMutateCanTransfer;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateCanClawback = lmfMPTCanMutateCanClawback;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateMetadata = lmfMPTCanMutateMetadata;
|
||||
constexpr std::uint32_t const tmfMPTCanMutateTransferFee = lmfMPTCanMutateTransferFee;
|
||||
constexpr std::uint32_t const tmfMPTokenIssuanceCreateMutableMask =
|
||||
~(tmfMPTCanMutateCanLock | tmfMPTCanMutateRequireAuth | tmfMPTCanMutateCanEscrow | tmfMPTCanMutateCanTrade
|
||||
| tmfMPTCanMutateCanTransfer | tmfMPTCanMutateCanClawback | tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee);
|
||||
|
||||
@@ -33,35 +33,51 @@ namespace ripple {
|
||||
|
||||
class TxMeta
|
||||
{
|
||||
private:
|
||||
struct CtorHelper
|
||||
{
|
||||
explicit CtorHelper() = default;
|
||||
};
|
||||
template <class T>
|
||||
TxMeta(
|
||||
uint256 const& txID,
|
||||
std::uint32_t ledger,
|
||||
T const& data,
|
||||
CtorHelper);
|
||||
|
||||
public:
|
||||
TxMeta(uint256 const& transactionID, std::uint32_t ledger);
|
||||
TxMeta(
|
||||
uint256 const& transactionID,
|
||||
std::uint32_t ledger,
|
||||
std::optional<uint256> parentBatchId = std::nullopt);
|
||||
TxMeta(uint256 const& txID, std::uint32_t ledger, Blob const&);
|
||||
TxMeta(uint256 const& txID, std::uint32_t ledger, std::string const&);
|
||||
TxMeta(uint256 const& txID, std::uint32_t ledger, STObject const&);
|
||||
|
||||
uint256 const&
|
||||
getTxID() const
|
||||
{
|
||||
return transactionID_;
|
||||
return mTransactionID;
|
||||
}
|
||||
std::uint32_t
|
||||
getLgrSeq() const
|
||||
{
|
||||
return ledgerSeq_;
|
||||
return mLedger;
|
||||
}
|
||||
int
|
||||
getResult() const
|
||||
{
|
||||
return result_;
|
||||
return mResult;
|
||||
}
|
||||
TER
|
||||
getResultTER() const
|
||||
{
|
||||
return TER::fromInt(result_);
|
||||
return TER::fromInt(mResult);
|
||||
}
|
||||
std::uint32_t
|
||||
getIndex() const
|
||||
{
|
||||
return index_;
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -88,52 +104,66 @@ public:
|
||||
STArray&
|
||||
getNodes()
|
||||
{
|
||||
return nodes_;
|
||||
return (mNodes);
|
||||
}
|
||||
STArray const&
|
||||
getNodes() const
|
||||
{
|
||||
return nodes_;
|
||||
return (mNodes);
|
||||
}
|
||||
|
||||
void
|
||||
setAdditionalFields(STObject const& obj)
|
||||
setDeliveredAmount(STAmount const& delivered)
|
||||
{
|
||||
if (obj.isFieldPresent(sfDeliveredAmount))
|
||||
deliveredAmount_ = obj.getFieldAmount(sfDeliveredAmount);
|
||||
|
||||
if (obj.isFieldPresent(sfParentBatchID))
|
||||
parentBatchID_ = obj.getFieldH256(sfParentBatchID);
|
||||
mDelivered = delivered;
|
||||
}
|
||||
|
||||
std::optional<STAmount> const&
|
||||
STAmount
|
||||
getDeliveredAmount() const
|
||||
{
|
||||
return deliveredAmount_;
|
||||
XRPL_ASSERT(
|
||||
hasDeliveredAmount(),
|
||||
"ripple::TxMeta::getDeliveredAmount : non-null delivered amount");
|
||||
return *mDelivered;
|
||||
}
|
||||
|
||||
bool
|
||||
hasDeliveredAmount() const
|
||||
{
|
||||
return static_cast<bool>(mDelivered);
|
||||
}
|
||||
|
||||
void
|
||||
setDeliveredAmount(std::optional<STAmount> const& amount)
|
||||
setParentBatchId(uint256 const& parentBatchId)
|
||||
{
|
||||
deliveredAmount_ = amount;
|
||||
mParentBatchId = parentBatchId;
|
||||
}
|
||||
|
||||
void
|
||||
setParentBatchID(std::optional<uint256> const& id)
|
||||
uint256
|
||||
getParentBatchId() const
|
||||
{
|
||||
parentBatchID_ = id;
|
||||
XRPL_ASSERT(
|
||||
hasParentBatchId(),
|
||||
"ripple::TxMeta::getParentBatchId : non-null batch id");
|
||||
return *mParentBatchId;
|
||||
}
|
||||
|
||||
bool
|
||||
hasParentBatchId() const
|
||||
{
|
||||
return static_cast<bool>(mParentBatchId);
|
||||
}
|
||||
|
||||
private:
|
||||
uint256 transactionID_;
|
||||
std::uint32_t ledgerSeq_;
|
||||
std::uint32_t index_;
|
||||
int result_;
|
||||
uint256 mTransactionID;
|
||||
std::uint32_t mLedger;
|
||||
std::uint32_t mIndex;
|
||||
int mResult;
|
||||
|
||||
std::optional<STAmount> deliveredAmount_;
|
||||
std::optional<uint256> parentBatchID_;
|
||||
std::optional<STAmount> mDelivered;
|
||||
std::optional<uint256> mParentBatchId;
|
||||
|
||||
STArray nodes_;
|
||||
STArray mNodes;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
1046
include/xrpl/protocol/TypedLedgerEntries.h
Normal file
1046
include/xrpl/protocol/TypedLedgerEntries.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,555 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2019 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 PROTOCOL_UNITS_H_INCLUDED
|
||||
#define PROTOCOL_UNITS_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace unit {
|
||||
|
||||
/** "drops" are the smallest divisible amount of XRP. This is what most
|
||||
of the code uses. */
|
||||
struct dropTag;
|
||||
/** "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 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;
|
||||
|
||||
// These names don't have to be too descriptive, because we're in the "unit"
|
||||
// namespace.
|
||||
|
||||
template <class T>
|
||||
concept Valid = std::is_class_v<T> && std::is_object_v<typename T::unit_type> &&
|
||||
std::is_object_v<typename T::value_type>;
|
||||
|
||||
/** `Usable` is checked to ensure that only values with
|
||||
known valid type tags can be used (sometimes transparently) in
|
||||
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>
|
||||
concept Usable = Valid<T> &&
|
||||
(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, BipsTag> ||
|
||||
std::is_same_v<typename T::unit_type, TenthBipsTag>);
|
||||
|
||||
template <class Other, class VU>
|
||||
concept Compatible = Valid<VU> && std::is_arithmetic_v<Other> &&
|
||||
std::is_arithmetic_v<typename VU::value_type> &&
|
||||
std::is_convertible_v<Other, typename VU::value_type>;
|
||||
|
||||
template <class T>
|
||||
concept Integral = std::is_integral_v<T>;
|
||||
|
||||
template <class VU>
|
||||
concept IntegralValue = Integral<typename VU::value_type>;
|
||||
|
||||
template <class VU1, class VU2>
|
||||
concept CastableValue = IntegralValue<VU1> && IntegralValue<VU2> &&
|
||||
std::is_same_v<typename VU1::unit_type, typename VU2::unit_type>;
|
||||
|
||||
template <class UnitTag, class 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 value_;
|
||||
|
||||
public:
|
||||
ValueUnit() = default;
|
||||
constexpr ValueUnit(ValueUnit const& other) = default;
|
||||
constexpr ValueUnit&
|
||||
operator=(ValueUnit const& other) = default;
|
||||
|
||||
constexpr explicit ValueUnit(beast::Zero) : value_(0)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr ValueUnit&
|
||||
operator=(beast::Zero)
|
||||
{
|
||||
value_ = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr explicit ValueUnit(value_type value) : value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr ValueUnit&
|
||||
operator=(value_type value)
|
||||
{
|
||||
value_ = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Instances with the same unit, and a type that is
|
||||
"safe" to convert to this one can be converted
|
||||
implicitly */
|
||||
template <Compatible<ValueUnit> Other>
|
||||
constexpr ValueUnit(ValueUnit<unit_type, Other> const& value)
|
||||
requires SafeToCast<Other, value_type>
|
||||
: ValueUnit(safe_cast<value_type>(value.value()))
|
||||
{
|
||||
}
|
||||
|
||||
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 ValueUnit{value_ * rhs};
|
||||
}
|
||||
|
||||
friend constexpr ValueUnit
|
||||
operator*(value_type lhs, ValueUnit const& rhs)
|
||||
{
|
||||
// multiplication is commutative
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
constexpr value_type
|
||||
operator/(ValueUnit const& rhs) const
|
||||
{
|
||||
return value_ / rhs.value_;
|
||||
}
|
||||
|
||||
ValueUnit&
|
||||
operator+=(ValueUnit const& other)
|
||||
{
|
||||
value_ += other.value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueUnit&
|
||||
operator-=(ValueUnit const& other)
|
||||
{
|
||||
value_ -= other.value();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueUnit&
|
||||
operator++()
|
||||
{
|
||||
++value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueUnit&
|
||||
operator--()
|
||||
{
|
||||
--value_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueUnit&
|
||||
operator*=(value_type const& rhs)
|
||||
{
|
||||
value_ *= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueUnit&
|
||||
operator/=(value_type const& rhs)
|
||||
{
|
||||
value_ /= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <Integral transparent = value_type>
|
||||
ValueUnit&
|
||||
operator%=(value_type const& rhs)
|
||||
{
|
||||
value_ %= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ValueUnit
|
||||
operator-() const
|
||||
{
|
||||
static_assert(
|
||||
std::is_signed_v<T>, "- operator illegal on unsigned value types");
|
||||
return ValueUnit{-value_};
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator==(ValueUnit const& other) const
|
||||
{
|
||||
return value_ == other.value_;
|
||||
}
|
||||
|
||||
template <Compatible<ValueUnit> Other>
|
||||
constexpr bool
|
||||
operator==(ValueUnit<unit_type, Other> const& other) const
|
||||
{
|
||||
return value_ == other.value();
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator==(value_type other) const
|
||||
{
|
||||
return value_ == other;
|
||||
}
|
||||
|
||||
template <Compatible<ValueUnit> Other>
|
||||
constexpr bool
|
||||
operator!=(ValueUnit<unit_type, Other> const& other) const
|
||||
{
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator<(ValueUnit const& other) const
|
||||
{
|
||||
return value_ < other.value_;
|
||||
}
|
||||
|
||||
/** Returns true if the amount is not zero */
|
||||
explicit constexpr
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return value_ != 0;
|
||||
}
|
||||
|
||||
/** Return the sign of the amount */
|
||||
constexpr int
|
||||
signum() const noexcept
|
||||
{
|
||||
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 value_;
|
||||
}
|
||||
|
||||
template <class Other>
|
||||
constexpr double
|
||||
decimalFromReference(ValueUnit<unit_type, Other> reference) const
|
||||
{
|
||||
return static_cast<double>(value_) / reference.value();
|
||||
}
|
||||
|
||||
// `Usable` 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.
|
||||
Json::Value
|
||||
jsonClipped() const
|
||||
requires Usable<ValueUnit>
|
||||
{
|
||||
if constexpr (std::is_integral_v<value_type>)
|
||||
{
|
||||
using jsontype = std::conditional_t<
|
||||
std::is_signed_v<value_type>,
|
||||
Json::Int,
|
||||
Json::UInt>;
|
||||
|
||||
constexpr auto min = std::numeric_limits<jsontype>::min();
|
||||
constexpr auto max = std::numeric_limits<jsontype>::max();
|
||||
|
||||
if (value_ < min)
|
||||
return min;
|
||||
if (value_ > max)
|
||||
return max;
|
||||
return static_cast<jsontype>(value_);
|
||||
}
|
||||
else
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the underlying value. Code SHOULD NOT call this
|
||||
function unless the type has been abstracted away,
|
||||
e.g. in a templated function.
|
||||
*/
|
||||
constexpr value_type
|
||||
value() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& s, ValueUnit& val)
|
||||
{
|
||||
s >> val.value_;
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
// 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, ValueUnit<UnitTag, T> const& q)
|
||||
{
|
||||
return os << q.value();
|
||||
}
|
||||
|
||||
template <class UnitTag, class T>
|
||||
std::string
|
||||
to_string(ValueUnit<UnitTag, T> const& amount)
|
||||
{
|
||||
return std::to_string(amount.value());
|
||||
}
|
||||
|
||||
template <class Source>
|
||||
concept muldivSource = Valid<Source> &&
|
||||
std::is_convertible_v<typename Source::value_type, std::uint64_t>;
|
||||
|
||||
template <class Dest>
|
||||
concept muldivDest = muldivSource<Dest> && // Dest is also a source
|
||||
std::is_convertible_v<std::uint64_t, typename Dest::value_type> &&
|
||||
sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
|
||||
|
||||
template <class Source2, class Source1>
|
||||
concept muldivSources = muldivSource<Source1> && muldivSource<Source2> &&
|
||||
std::is_same_v<typename Source1::unit_type, typename Source2::unit_type>;
|
||||
|
||||
template <class Dest, class Source1, class Source2>
|
||||
concept muldivable = muldivSources<Source1, Source2> && muldivDest<Dest>;
|
||||
// Source and Dest can be the same by default
|
||||
|
||||
template <class Dest, class Source1, class Source2>
|
||||
concept muldivCommutable = muldivable<Dest, Source1, Source2> &&
|
||||
!std::is_same_v<typename Source1::unit_type, typename Dest::unit_type>;
|
||||
|
||||
template <class T>
|
||||
ValueUnit<unitlessTag, T>
|
||||
scalar(T value)
|
||||
{
|
||||
return ValueUnit<unitlessTag, T>{value};
|
||||
}
|
||||
|
||||
template <class Source1, class Source2, unit::muldivable<Source1, Source2> Dest>
|
||||
std::optional<Dest>
|
||||
mulDivU(Source1 value, Dest mul, Source2 div)
|
||||
{
|
||||
// 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::unit::mulDivU : minimum value input");
|
||||
XRPL_ASSERT(
|
||||
mul.value() >= 0, "ripple::unit::mulDivU : minimum mul input");
|
||||
XRPL_ASSERT(
|
||||
div.value() > 0, "ripple::unit::mulDivU : minimum div input");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
using desttype = typename Dest::value_type;
|
||||
constexpr auto max = std::numeric_limits<desttype>::max();
|
||||
|
||||
// Shortcuts, since these happen a lot in the real world
|
||||
if (value == div)
|
||||
return mul;
|
||||
if (mul.value() == div.value())
|
||||
{
|
||||
if (value.value() > max)
|
||||
return std::nullopt;
|
||||
return Dest{static_cast<desttype>(value.value())};
|
||||
}
|
||||
|
||||
using namespace boost::multiprecision;
|
||||
|
||||
uint128_t product;
|
||||
product = multiply(
|
||||
product,
|
||||
static_cast<std::uint64_t>(value.value()),
|
||||
static_cast<std::uint64_t>(mul.value()));
|
||||
|
||||
auto quotient = product / div.value();
|
||||
|
||||
if (quotient > max)
|
||||
return std::nullopt;
|
||||
|
||||
return Dest{static_cast<desttype>(quotient)};
|
||||
}
|
||||
|
||||
} // namespace unit
|
||||
|
||||
// Fee Levels
|
||||
template <class 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, unit::muldivable<Source1, Source2> Dest>
|
||||
std::optional<Dest>
|
||||
mulDiv(Source1 value, Dest mul, Source2 div)
|
||||
{
|
||||
return unit::mulDivU(value, mul, div);
|
||||
}
|
||||
|
||||
template <
|
||||
class Source1,
|
||||
class Source2,
|
||||
unit::muldivCommutable<Source1, Source2> Dest>
|
||||
std::optional<Dest>
|
||||
mulDiv(Dest value, Source1 mul, Source2 div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return unit::mulDivU(mul, value, div);
|
||||
}
|
||||
|
||||
template <unit::muldivDest 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 unit::mulDivU(unit::scalar(value), mul, unit::scalar(div));
|
||||
}
|
||||
|
||||
template <unit::muldivDest Dest>
|
||||
std::optional<Dest>
|
||||
mulDiv(Dest value, std::uint64_t mul, std::uint64_t div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return mulDiv(mul, value, div);
|
||||
}
|
||||
|
||||
template <unit::muldivSource Source1, unit::muldivSources<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 = unit::mulDivU(value, unit::scalar(mul), div);
|
||||
|
||||
if (!unitresult)
|
||||
return std::nullopt;
|
||||
|
||||
return unitresult->value();
|
||||
}
|
||||
|
||||
template <unit::muldivSource Source1, unit::muldivSources<Source1> Source2>
|
||||
std::optional<std::uint64_t>
|
||||
mulDiv(std::uint64_t value, Source1 mul, Source2 div)
|
||||
{
|
||||
// Multiplication is commutative
|
||||
return mulDiv(mul, value, div);
|
||||
}
|
||||
|
||||
template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
|
||||
constexpr Dest
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{safe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
template <unit::IntegralValue Dest, unit::Integral Src>
|
||||
constexpr Dest
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{safe_cast<typename Dest::value_type>(s)};
|
||||
}
|
||||
|
||||
template <unit::IntegralValue Dest, unit::CastableValue<Dest> Src>
|
||||
constexpr Dest
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
// Dest may not have an explicit value constructor
|
||||
return Dest{unsafe_cast<typename Dest::value_type>(s.value())};
|
||||
}
|
||||
|
||||
template <unit::IntegralValue Dest, unit::Integral Src>
|
||||
constexpr 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 // 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/Units.h>
|
||||
#include <xrpl/protocol/FeeUnits.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 = unit::dropTag;
|
||||
using unit_type = feeunit::dropTag;
|
||||
using value_type = std::int64_t;
|
||||
|
||||
private:
|
||||
|
||||
@@ -129,12 +129,10 @@ inplace_bigint_div_rem(std::span<uint64_t> numerator, std::uint64_t divisor)
|
||||
{
|
||||
// should never happen, but if it does then it seems natural to define
|
||||
// the a null set of numbers to be zero, so the remainder is also zero.
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"ripple::b58_fast::detail::inplace_bigint_div_rem : empty "
|
||||
"numerator");
|
||||
return 0;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
auto to_u128 = [](std::uint64_t high,
|
||||
|
||||
@@ -29,14 +29,15 @@
|
||||
|
||||
// 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(PermissionDelegationV1_1, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (IncludeKeyletFields, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (IncludeKeyletFields, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DynamicMPT, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (TokenEscrowV1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PriceOracleOrder, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (MPTDeliveredAmount, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (DelegateV1_1, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PriceOracleOrder, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (MPTDeliveredAmount, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
@@ -44,6 +45,7 @@ XRPL_FIX (AMMv1_3, Supported::yes, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(PermissionedDEX, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Batch, 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)
|
||||
@@ -77,6 +79,7 @@ XRPL_FIX (DisallowIncomingV1, Supported::yes, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(XChainBridge, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(AMM, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Clawback, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (ReducedOffersV1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (NFTokenRemint, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (NonFungibleTokensV1_2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (UniversalNumber, Supported::yes, VoteBehavior::DefaultNo)
|
||||
@@ -88,17 +91,33 @@ XRPL_FIX (TrustLinesToSelf, Supported::yes, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(NonFungibleTokensV1_1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(ExpandedSignerList, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(CheckCashMakesTrustLine, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (RmSmallIncreasedQOffers, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (STAmountCanonicalize, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(FlowSortStrands, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(TicketBatch, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(NegativeUNL, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (AmendmentMajorityCalc, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(HardenedValidations, Supported::yes, VoteBehavior::DefaultYes)
|
||||
// fix1781: XRPEndpointSteps should be included in the circular payment check
|
||||
XRPL_FIX (1781, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(RequireFullyCanonicalSig, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (QualityUpperBound, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(DeletableAccounts, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (PayChanRecipientOwnerDir, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (CheckThreading, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (MasterKeyAsRegularKey, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (TakerDryOfferRemoval, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(MultiSignReserve, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (1578, Supported::yes, VoteBehavior::DefaultYes)
|
||||
// fix1515: Use liquidity from strands that consume max offers, but mark as dry
|
||||
XRPL_FIX (1515, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(DepositPreauth, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (1623, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (1543, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (1571, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(Checks, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(DepositAuth, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (1513, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes)
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
@@ -119,38 +138,21 @@ XRPL_FEATURE(CryptoConditionsSuite, Supported::yes, VoteBehavior::Obsolete)
|
||||
|
||||
// The following amendments have been active for at least two years. Their
|
||||
// pre-amendment code has been removed and the identifiers are deprecated.
|
||||
// All known amendments and amendments that may appear in a validated ledger
|
||||
// must be registered either here or above with the "active" amendments
|
||||
//
|
||||
// Please keep this list sorted alphabetically for convenience.
|
||||
XRPL_RETIRE(fix1201)
|
||||
// All known amendments and amendments that may appear in a validated
|
||||
// ledger must be registered either here or above with the "active" amendments
|
||||
XRPL_RETIRE(MultiSign)
|
||||
XRPL_RETIRE(TrustSetAuth)
|
||||
XRPL_RETIRE(FeeEscalation)
|
||||
XRPL_RETIRE(PayChan)
|
||||
XRPL_RETIRE(CryptoConditions)
|
||||
XRPL_RETIRE(TickSize)
|
||||
XRPL_RETIRE(fix1368)
|
||||
XRPL_RETIRE(Escrow)
|
||||
XRPL_RETIRE(fix1373)
|
||||
XRPL_RETIRE(EnforceInvariants)
|
||||
XRPL_RETIRE(SortedDirectories)
|
||||
XRPL_RETIRE(fix1201)
|
||||
XRPL_RETIRE(fix1512)
|
||||
XRPL_RETIRE(fix1513)
|
||||
XRPL_RETIRE(fix1515)
|
||||
XRPL_RETIRE(fix1523)
|
||||
XRPL_RETIRE(fix1528)
|
||||
XRPL_RETIRE(fix1543)
|
||||
XRPL_RETIRE(fix1571)
|
||||
XRPL_RETIRE(fix1578)
|
||||
XRPL_RETIRE(fix1623)
|
||||
XRPL_RETIRE(fix1781)
|
||||
XRPL_RETIRE(fixAmendmentMajorityCalc)
|
||||
XRPL_RETIRE(fixCheckThreading)
|
||||
XRPL_RETIRE(fixMasterKeyAsRegularKey)
|
||||
XRPL_RETIRE(fixQualityUpperBound)
|
||||
XRPL_RETIRE(fixReducedOffersV1)
|
||||
XRPL_RETIRE(fixRmSmallIncreasedQOffers)
|
||||
XRPL_RETIRE(fixSTAmountCanonicalize)
|
||||
XRPL_RETIRE(fixTakerDryOfferRemoval)
|
||||
XRPL_RETIRE(CryptoConditions)
|
||||
XRPL_RETIRE(Escrow)
|
||||
XRPL_RETIRE(EnforceInvariants)
|
||||
XRPL_RETIRE(FeeEscalation)
|
||||
XRPL_RETIRE(FlowCross)
|
||||
XRPL_RETIRE(MultiSign)
|
||||
XRPL_RETIRE(PayChan)
|
||||
XRPL_RETIRE(SortedDirectories)
|
||||
XRPL_RETIRE(TickSize)
|
||||
XRPL_RETIRE(TrustSetAuth)
|
||||
|
||||
175
include/xrpl/protocol/detail/inner_objects.macro
Normal file
175
include/xrpl/protocol/detail/inner_objects.macro
Normal file
@@ -0,0 +1,175 @@
|
||||
|
||||
#if !defined(INNER_OBJECT)
|
||||
#error "undefined macro: INNER_OBJECT"
|
||||
#endif
|
||||
|
||||
#if !defined(FIELDS)
|
||||
#error "undefined macro: FIELDS"
|
||||
#endif
|
||||
|
||||
#if !defined(FIELD)
|
||||
#error "undefined macro: FIELD"
|
||||
#endif
|
||||
|
||||
#if !defined(INNER_OBJECT_BEGIN)
|
||||
#error "undefined macro: INNER_OBJECT_BEGIN"
|
||||
#endif
|
||||
|
||||
#if !defined(INNER_OBJECT_END)
|
||||
#error "undefined macro: INNER_OBJECT_END"
|
||||
#endif
|
||||
|
||||
INNER_OBJECT_BEGIN
|
||||
|
||||
INNER_OBJECT(sfSignerEntry,
|
||||
FIELDS(
|
||||
FIELD(sfSignerEntry, sfAccount, soeREQUIRED)
|
||||
FIELD(sfSignerEntry, sfSignerWeight, soeREQUIRED)
|
||||
FIELD(sfSignerEntry, sfWalletLocator, soeOPTIONAL)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfSigner,
|
||||
FIELDS(
|
||||
FIELD(sfSigner, sfAccount, soeREQUIRED)
|
||||
FIELD(sfSigner, sfSigningPubKey, soeREQUIRED)
|
||||
FIELD(sfSigner, sfTxnSignature, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfMajority,
|
||||
FIELDS(
|
||||
FIELD(sfMajority, sfAmendment, soeREQUIRED)
|
||||
FIELD(sfMajority, sfCloseTime, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfDisabledValidator,
|
||||
FIELDS(
|
||||
FIELD(sfDisabledValidator, sfPublicKey, soeREQUIRED)
|
||||
FIELD(sfDisabledValidator, sfFirstLedgerSequence, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfNFToken,
|
||||
FIELDS(
|
||||
FIELD(sfNFToken, sfNFTokenID, soeREQUIRED)
|
||||
FIELD(sfNFToken, sfURI, soeOPTIONAL)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfVoteEntry,
|
||||
FIELDS(
|
||||
FIELD(sfVoteEntry, sfAccount, soeREQUIRED)
|
||||
FIELD(sfVoteEntry, sfTradingFee, soeDEFAULT)
|
||||
FIELD(sfVoteEntry, sfVoteWeight, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfAuctionSlot,
|
||||
FIELDS(
|
||||
FIELD(sfAuctionSlot, sfAccount, soeREQUIRED)
|
||||
FIELD(sfAuctionSlot, sfExpiration, soeREQUIRED)
|
||||
FIELD(sfAuctionSlot, sfDiscountedFee, soeDEFAULT)
|
||||
FIELD(sfAuctionSlot, sfPrice, soeREQUIRED)
|
||||
FIELD(sfAuctionSlot, sfAuthAccounts, soeOPTIONAL)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfXChainClaimAttestationCollectionElement,
|
||||
FIELDS(
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfAttestationSignerAccount, soeREQUIRED)
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfPublicKey, soeREQUIRED)
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfSignature, soeREQUIRED)
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfAmount, soeREQUIRED)
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfAccount, soeREQUIRED)
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfAttestationRewardAccount, soeREQUIRED)
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfWasLockingChainSend, soeREQUIRED)
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfXChainClaimID, soeREQUIRED)
|
||||
FIELD(sfXChainClaimAttestationCollectionElement, sfDestination, soeOPTIONAL)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfXChainCreateAccountAttestationCollectionElement,
|
||||
FIELDS(
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfAttestationSignerAccount, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfPublicKey, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfSignature, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfAmount, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfAccount, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfAttestationRewardAccount, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfWasLockingChainSend, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfXChainAccountCreateCount, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfDestination, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountAttestationCollectionElement, sfSignatureReward, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfXChainClaimProofSig,
|
||||
FIELDS(
|
||||
FIELD(sfXChainClaimProofSig, sfAttestationSignerAccount, soeREQUIRED)
|
||||
FIELD(sfXChainClaimProofSig, sfPublicKey, soeREQUIRED)
|
||||
FIELD(sfXChainClaimProofSig, sfAmount, soeREQUIRED)
|
||||
FIELD(sfXChainClaimProofSig, sfAttestationRewardAccount, soeREQUIRED)
|
||||
FIELD(sfXChainClaimProofSig, sfWasLockingChainSend, soeREQUIRED)
|
||||
FIELD(sfXChainClaimProofSig, sfDestination, soeOPTIONAL)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfXChainCreateAccountProofSig,
|
||||
FIELDS(
|
||||
FIELD(sfXChainCreateAccountProofSig, sfAttestationSignerAccount, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountProofSig, sfPublicKey, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountProofSig, sfAmount, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountProofSig, sfSignatureReward, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountProofSig, sfAttestationRewardAccount, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountProofSig, sfWasLockingChainSend, soeREQUIRED)
|
||||
FIELD(sfXChainCreateAccountProofSig, sfDestination, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfAuthAccount,
|
||||
FIELDS(
|
||||
FIELD(sfAuthAccount, sfAccount, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfPriceData,
|
||||
FIELDS(
|
||||
FIELD(sfPriceData, sfBaseAsset, soeREQUIRED)
|
||||
FIELD(sfPriceData, sfQuoteAsset, soeREQUIRED)
|
||||
FIELD(sfPriceData, sfAssetPrice, soeOPTIONAL)
|
||||
FIELD(sfPriceData, sfScale, soeDEFAULT)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfCredential,
|
||||
FIELDS(
|
||||
FIELD(sfCredential, sfIssuer, soeREQUIRED)
|
||||
FIELD(sfCredential, sfCredentialType, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfPermission,
|
||||
FIELDS(
|
||||
FIELD(sfPermission, sfPermissionValue, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfBatchSigner,
|
||||
FIELDS(
|
||||
FIELD(sfBatchSigner, sfAccount, soeREQUIRED)
|
||||
FIELD(sfBatchSigner, sfSigningPubKey, soeOPTIONAL)
|
||||
FIELD(sfBatchSigner, sfTxnSignature, soeOPTIONAL)
|
||||
FIELD(sfBatchSigner, sfSigners, soeOPTIONAL)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT(sfBook,
|
||||
FIELDS(
|
||||
FIELD(sfBook, sfBookDirectory, soeREQUIRED)
|
||||
FIELD(sfBook, sfBookNode, soeREQUIRED)
|
||||
)
|
||||
)
|
||||
|
||||
INNER_OBJECT_END
|
||||
@@ -21,6 +21,22 @@
|
||||
#error "undefined macro: LEDGER_ENTRY"
|
||||
#endif
|
||||
|
||||
#if !defined(LEDGER_ENTRY_FIELD)
|
||||
#error "undefined macro: LEDGER_ENTRY_FIELD"
|
||||
#endif
|
||||
|
||||
#if !defined(DEFINE_LEDGER_ENTRY_FIELDS)
|
||||
#error "undefined macro: DEFINE_LEDGER_ENTRY_FIELDS"
|
||||
#endif
|
||||
|
||||
#if !defined(LEDGER_ENTRIES_BEGIN)
|
||||
#error "undefined macro: LEDGER_ENTRIES_BEGIN"
|
||||
#endif
|
||||
|
||||
#if !defined(LEDGER_ENTRIES_END)
|
||||
#error "undefined macro: LEDGER_ENTRIES_END"
|
||||
#endif
|
||||
|
||||
#ifndef LEDGER_ENTRY_DUPLICATE
|
||||
// The EXPAND macro is needed for Windows
|
||||
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
|
||||
@@ -32,6 +48,8 @@
|
||||
#define LEDGER_ENTRY_DUPLICATE(...) EXPAND(LEDGER_ENTRY(__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
LEDGER_ENTRIES_BEGIN
|
||||
|
||||
/**
|
||||
* These objects are listed in order of increasing ledger type ID.
|
||||
* There are many gaps between these IDs.
|
||||
@@ -42,50 +60,50 @@
|
||||
|
||||
\sa keylet::nftoffer
|
||||
*/
|
||||
LEDGER_ENTRY(ltNFTOKEN_OFFER, 0x0037, NFTokenOffer, nft_offer, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfNFTokenID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfNFTokenOfferNode, soeREQUIRED},
|
||||
{sfDestination, soeOPTIONAL},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltNFTOKEN_OFFER, 0x0037, NFTokenOffer, nft_offer, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfOwner, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfNFTokenID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAmount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfNFTokenOfferNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfDestination, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfExpiration, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which describes a check.
|
||||
|
||||
\sa keylet::check
|
||||
*/
|
||||
LEDGER_ENTRY(ltCHECK, 0x0043, Check, check, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfSendMax, soeREQUIRED},
|
||||
{sfSequence, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfDestinationNode, soeREQUIRED},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
{sfInvoiceID, soeOPTIONAL},
|
||||
{sfSourceTag, soeOPTIONAL},
|
||||
{sfDestinationTag, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltCHECK, 0x0043, Check, check, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfDestination, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSendMax, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSequence, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfDestinationNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfExpiration, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfInvoiceID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfSourceTag, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfDestinationTag, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** The ledger object which tracks the DID.
|
||||
|
||||
\sa keylet::did
|
||||
*/
|
||||
LEDGER_ENTRY(ltDID, 0x0049, DID, did, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfDIDDocument, soeOPTIONAL},
|
||||
{sfURI, soeOPTIONAL},
|
||||
{sfData, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltDID, 0x0049, DID, did, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfDIDDocument, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfURI, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfData, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** The ledger object which tracks the current negative UNL state.
|
||||
|
||||
@@ -93,25 +111,25 @@ LEDGER_ENTRY(ltDID, 0x0049, DID, did, ({
|
||||
|
||||
\sa keylet::negativeUNL
|
||||
*/
|
||||
LEDGER_ENTRY(ltNEGATIVE_UNL, 0x004e, NegativeUNL, nunl, ({
|
||||
{sfDisabledValidators, soeOPTIONAL},
|
||||
{sfValidatorToDisable, soeOPTIONAL},
|
||||
{sfValidatorToReEnable, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeOPTIONAL},
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY(ltNEGATIVE_UNL, 0x004e, NegativeUNL, nunl, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfDisabledValidators, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfValidatorToDisable, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfValidatorToReEnable, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** A ledger object which contains a list of NFTs
|
||||
|
||||
\sa keylet::nftpage_min, keylet::nftpage_max, keylet::nftpage
|
||||
*/
|
||||
LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({
|
||||
{sfPreviousPageMin, soeOPTIONAL},
|
||||
{sfNextPageMin, soeOPTIONAL},
|
||||
{sfNFTokens, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfPreviousPageMin, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfNextPageMin, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfNFTokens, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which contains a signer list for an account.
|
||||
|
||||
@@ -119,78 +137,78 @@ LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({
|
||||
*/
|
||||
// All fields are soeREQUIRED because there is always a SignerEntries.
|
||||
// If there are no SignerEntries the node is deleted.
|
||||
LEDGER_ENTRY(ltSIGNER_LIST, 0x0053, SignerList, signer_list, ({
|
||||
{sfOwner, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfSignerQuorum, soeREQUIRED},
|
||||
{sfSignerEntries, soeREQUIRED},
|
||||
{sfSignerListID, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltSIGNER_LIST, 0x0053, SignerList, signer_list, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfOwner, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSignerQuorum, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSignerEntries, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSignerListID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which describes a ticket.
|
||||
|
||||
\sa keylet::ticket
|
||||
*/
|
||||
LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ticket, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfTicketSequence, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ticket, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfTicketSequence, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which describes an account.
|
||||
|
||||
\sa keylet::account
|
||||
*/
|
||||
LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfSequence, soeREQUIRED},
|
||||
{sfBalance, soeREQUIRED},
|
||||
{sfOwnerCount, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfAccountTxnID, soeOPTIONAL},
|
||||
{sfRegularKey, soeOPTIONAL},
|
||||
{sfEmailHash, soeOPTIONAL},
|
||||
{sfWalletLocator, soeOPTIONAL},
|
||||
{sfWalletSize, soeOPTIONAL},
|
||||
{sfMessageKey, soeOPTIONAL},
|
||||
{sfTransferRate, soeOPTIONAL},
|
||||
{sfDomain, soeOPTIONAL},
|
||||
{sfTickSize, soeOPTIONAL},
|
||||
{sfTicketCount, soeOPTIONAL},
|
||||
{sfNFTokenMinter, soeOPTIONAL},
|
||||
{sfMintedNFTokens, soeDEFAULT},
|
||||
{sfBurnedNFTokens, soeDEFAULT},
|
||||
{sfFirstNFTokenSequence, soeOPTIONAL},
|
||||
{sfAMMID, soeOPTIONAL}, // pseudo-account designator
|
||||
{sfVaultID, soeOPTIONAL}, // pseudo-account designator
|
||||
}))
|
||||
LEDGER_ENTRY(ltACCOUNT_ROOT, 0x0061, AccountRoot, account, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSequence, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfBalance, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerCount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAccountTxnID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfRegularKey, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfEmailHash, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfWalletLocator, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfWalletSize, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfMessageKey, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfTransferRate, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfDomain, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfTickSize, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfTicketCount, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfNFTokenMinter, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfMintedNFTokens, soeDEFAULT)
|
||||
LEDGER_ENTRY_FIELD(sfBurnedNFTokens, soeDEFAULT)
|
||||
LEDGER_ENTRY_FIELD(sfFirstNFTokenSequence, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfAMMID, soeOPTIONAL) // pseudo-account designator
|
||||
LEDGER_ENTRY_FIELD(sfVaultID, soeOPTIONAL) // pseudo-account designator
|
||||
))
|
||||
|
||||
/** A ledger object which contains a list of object identifiers.
|
||||
|
||||
\sa keylet::page, keylet::quality, keylet::book, keylet::next and
|
||||
keylet::ownerDir
|
||||
*/
|
||||
LEDGER_ENTRY(ltDIR_NODE, 0x0064, DirectoryNode, directory, ({
|
||||
{sfOwner, soeOPTIONAL}, // for owner directories
|
||||
{sfTakerPaysCurrency, soeOPTIONAL}, // order book directories
|
||||
{sfTakerPaysIssuer, soeOPTIONAL}, // order book directories
|
||||
{sfTakerGetsCurrency, soeOPTIONAL}, // order book directories
|
||||
{sfTakerGetsIssuer, soeOPTIONAL}, // order book directories
|
||||
{sfExchangeRate, soeOPTIONAL}, // order book directories
|
||||
{sfIndexes, soeREQUIRED},
|
||||
{sfRootIndex, soeREQUIRED},
|
||||
{sfIndexNext, soeOPTIONAL},
|
||||
{sfIndexPrevious, soeOPTIONAL},
|
||||
{sfNFTokenID, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeOPTIONAL},
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
{sfDomainID, soeOPTIONAL} // order book directories
|
||||
}))
|
||||
LEDGER_ENTRY(ltDIR_NODE, 0x0064, DirectoryNode, directory, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfOwner, soeOPTIONAL) // for owner directories
|
||||
LEDGER_ENTRY_FIELD(sfTakerPaysCurrency, soeOPTIONAL) // order book directories
|
||||
LEDGER_ENTRY_FIELD(sfTakerPaysIssuer, soeOPTIONAL) // order book directories
|
||||
LEDGER_ENTRY_FIELD(sfTakerGetsCurrency, soeOPTIONAL) // order book directories
|
||||
LEDGER_ENTRY_FIELD(sfTakerGetsIssuer, soeOPTIONAL) // order book directories
|
||||
LEDGER_ENTRY_FIELD(sfExchangeRate, soeOPTIONAL) // order book directories
|
||||
LEDGER_ENTRY_FIELD(sfIndexes, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfRootIndex, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfIndexNext, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfIndexPrevious, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfNFTokenID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfDomainID, soeOPTIONAL) // order book directories
|
||||
))
|
||||
|
||||
/** The ledger object which lists details about amendments on the network.
|
||||
|
||||
@@ -198,12 +216,12 @@ LEDGER_ENTRY(ltDIR_NODE, 0x0064, DirectoryNode, directory, ({
|
||||
|
||||
\sa keylet::amendments
|
||||
*/
|
||||
LEDGER_ENTRY(ltAMENDMENTS, 0x0066, Amendments, amendments, ({
|
||||
{sfAmendments, soeOPTIONAL}, // Enabled
|
||||
{sfMajorities, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeOPTIONAL},
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY(ltAMENDMENTS, 0x0066, Amendments, amendments, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAmendments, soeOPTIONAL) // Enabled
|
||||
LEDGER_ENTRY_FIELD(sfMajorities, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** A ledger object that contains a list of ledger hashes.
|
||||
|
||||
@@ -213,76 +231,76 @@ LEDGER_ENTRY(ltAMENDMENTS, 0x0066, Amendments, amendments, ({
|
||||
|
||||
\sa keylet::skip
|
||||
*/
|
||||
LEDGER_ENTRY(ltLEDGER_HASHES, 0x0068, LedgerHashes, hashes, ({
|
||||
{sfFirstLedgerSequence, soeOPTIONAL},
|
||||
{sfLastLedgerSequence, soeOPTIONAL},
|
||||
{sfHashes, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltLEDGER_HASHES, 0x0068, LedgerHashes, hashes, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfFirstLedgerSequence, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfLastLedgerSequence, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfHashes, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** The ledger object which lists details about sidechains.
|
||||
|
||||
\sa keylet::bridge
|
||||
*/
|
||||
LEDGER_ENTRY(ltBRIDGE, 0x0069, Bridge, bridge, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfSignatureReward, soeREQUIRED},
|
||||
{sfMinAccountCreateAmount, soeOPTIONAL},
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfXChainClaimID, soeREQUIRED},
|
||||
{sfXChainAccountCreateCount, soeREQUIRED},
|
||||
{sfXChainAccountClaimCount, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltBRIDGE, 0x0069, Bridge, bridge, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSignatureReward, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfMinAccountCreateAmount, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfXChainBridge, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainClaimID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainAccountCreateCount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainAccountClaimCount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which describes an offer on the DEX.
|
||||
|
||||
\sa keylet::offer
|
||||
*/
|
||||
LEDGER_ENTRY(ltOFFER, 0x006f, Offer, offer, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfSequence, soeREQUIRED},
|
||||
{sfTakerPays, soeREQUIRED},
|
||||
{sfTakerGets, soeREQUIRED},
|
||||
{sfBookDirectory, soeREQUIRED},
|
||||
{sfBookNode, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
{sfDomainID, soeOPTIONAL},
|
||||
{sfAdditionalBooks, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY(ltOFFER, 0x006f, Offer, offer, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSequence, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfTakerPays, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfTakerGets, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfBookDirectory, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfBookNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfExpiration, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfDomainID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfAdditionalBooks, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** A ledger object which describes a deposit preauthorization.
|
||||
|
||||
\sa keylet::depositPreauth
|
||||
*/
|
||||
LEDGER_ENTRY_DUPLICATE(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, deposit_preauth, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfAuthorize, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfAuthorizeCredentials, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY_DUPLICATE(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, deposit_preauth, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAuthorize, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAuthorizeCredentials, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** A claim id for a cross chain transaction.
|
||||
|
||||
\sa keylet::xChainClaimID
|
||||
*/
|
||||
LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_claim_id, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfXChainClaimID, soeREQUIRED},
|
||||
{sfOtherChainSource, soeREQUIRED},
|
||||
{sfXChainClaimAttestations, soeREQUIRED},
|
||||
{sfSignatureReward, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_claim_id, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainBridge, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainClaimID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOtherChainSource, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainClaimAttestations, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSignatureReward, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which describes a bidirectional trust line.
|
||||
|
||||
@@ -290,19 +308,19 @@ LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_c
|
||||
|
||||
\sa keylet::line
|
||||
*/
|
||||
LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
{sfBalance, soeREQUIRED},
|
||||
{sfLowLimit, soeREQUIRED},
|
||||
{sfHighLimit, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfLowNode, soeOPTIONAL},
|
||||
{sfLowQualityIn, soeOPTIONAL},
|
||||
{sfLowQualityOut, soeOPTIONAL},
|
||||
{sfHighNode, soeOPTIONAL},
|
||||
{sfHighQualityIn, soeOPTIONAL},
|
||||
{sfHighQualityOut, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfBalance, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfLowLimit, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfHighLimit, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfLowNode, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfLowQualityIn, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfLowQualityOut, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfHighNode, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfHighQualityIn, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfHighQualityOut, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** The ledger object which lists the network's fee settings.
|
||||
|
||||
@@ -310,204 +328,206 @@ LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
|
||||
\sa keylet::fees
|
||||
*/
|
||||
LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
// Old version uses raw numbers
|
||||
{sfBaseFee, soeOPTIONAL},
|
||||
{sfReferenceFeeUnits, soeOPTIONAL},
|
||||
{sfReserveBase, soeOPTIONAL},
|
||||
{sfReserveIncrement, soeOPTIONAL},
|
||||
LEDGER_ENTRY_FIELD(sfBaseFee, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfReferenceFeeUnits, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfReserveBase, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfReserveIncrement, soeOPTIONAL)
|
||||
// New version uses Amounts
|
||||
{sfBaseFeeDrops, soeOPTIONAL},
|
||||
{sfReserveBaseDrops, soeOPTIONAL},
|
||||
{sfReserveIncrementDrops, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeOPTIONAL},
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY_FIELD(sfBaseFeeDrops, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfReserveBaseDrops, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfReserveIncrementDrops, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** A claim id for a cross chain create account transaction.
|
||||
|
||||
\sa keylet::xChainCreateAccountClaimID
|
||||
*/
|
||||
LEDGER_ENTRY(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, 0x0074, XChainOwnedCreateAccountClaimID, xchain_owned_create_account_claim_id, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfXChainAccountCreateCount, soeREQUIRED},
|
||||
{sfXChainCreateAccountAttestations, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, 0x0074, XChainOwnedCreateAccountClaimID, xchain_owned_create_account_claim_id, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainBridge, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainAccountCreateCount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfXChainCreateAccountAttestations, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object describing a single escrow.
|
||||
|
||||
\sa keylet::escrow
|
||||
*/
|
||||
LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfSequence, soeOPTIONAL},
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfCondition, soeOPTIONAL},
|
||||
{sfCancelAfter, soeOPTIONAL},
|
||||
{sfFinishAfter, soeOPTIONAL},
|
||||
{sfSourceTag, soeOPTIONAL},
|
||||
{sfDestinationTag, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfDestinationNode, soeOPTIONAL},
|
||||
{sfTransferRate, soeOPTIONAL},
|
||||
{sfIssuerNode, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSequence, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfDestination, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAmount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfCondition, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfCancelAfter, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfFinishAfter, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfSourceTag, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfDestinationTag, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfDestinationNode, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfTransferRate, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfIssuerNode, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** A ledger object describing a single unidirectional XRP payment channel.
|
||||
|
||||
\sa keylet::payChan
|
||||
*/
|
||||
LEDGER_ENTRY(ltPAYCHAN, 0x0078, PayChannel, payment_channel, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfSequence, soeOPTIONAL},
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfBalance, soeREQUIRED},
|
||||
{sfPublicKey, soeREQUIRED},
|
||||
{sfSettleDelay, soeREQUIRED},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
{sfCancelAfter, soeOPTIONAL},
|
||||
{sfSourceTag, soeOPTIONAL},
|
||||
{sfDestinationTag, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfDestinationNode, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY(ltPAYCHAN, 0x0078, PayChannel, payment_channel, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfDestination, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSequence, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfAmount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfBalance, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPublicKey, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSettleDelay, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfExpiration, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfCancelAfter, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfSourceTag, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfDestinationTag, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfDestinationNode, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** The ledger object which tracks the AMM.
|
||||
|
||||
\sa keylet::amm
|
||||
*/
|
||||
LEDGER_ENTRY(ltAMM, 0x0079, AMM, amm, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfTradingFee, soeDEFAULT},
|
||||
{sfVoteSlots, soeOPTIONAL},
|
||||
{sfAuctionSlot, soeOPTIONAL},
|
||||
{sfLPTokenBalance, soeREQUIRED},
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeOPTIONAL},
|
||||
{sfPreviousTxnLgrSeq, soeOPTIONAL},
|
||||
}))
|
||||
LEDGER_ENTRY(ltAMM, 0x0079, AMM, amm, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfTradingFee, soeDEFAULT)
|
||||
LEDGER_ENTRY_FIELD(sfVoteSlots, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfAuctionSlot, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfLPTokenBalance, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAsset, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAsset2, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeOPTIONAL)
|
||||
))
|
||||
|
||||
/** A ledger object which tracks MPTokenIssuance
|
||||
\sa keylet::mptIssuance
|
||||
*/
|
||||
LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfSequence, soeREQUIRED},
|
||||
{sfTransferFee, soeDEFAULT},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfAssetScale, soeDEFAULT},
|
||||
{sfMaximumAmount, soeOPTIONAL},
|
||||
{sfOutstandingAmount, soeREQUIRED},
|
||||
{sfLockedAmount, soeOPTIONAL},
|
||||
{sfMPTokenMetadata, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
{sfDomainID, soeOPTIONAL},
|
||||
{sfMutableFlags, soeDEFAULT},
|
||||
}))
|
||||
LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfIssuer, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSequence, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfTransferFee, soeDEFAULT)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAssetScale, soeDEFAULT)
|
||||
LEDGER_ENTRY_FIELD(sfMaximumAmount, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfOutstandingAmount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfLockedAmount, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfMPTokenMetadata, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfDomainID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfMutableFlags, soeDEFAULT)
|
||||
))
|
||||
|
||||
/** A ledger object which tracks MPToken
|
||||
\sa keylet::mptoken
|
||||
*/
|
||||
LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({
|
||||
{sfAccount, soeREQUIRED},
|
||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||
{sfMPTAmount, soeDEFAULT},
|
||||
{sfLockedAmount, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfMPTokenIssuanceID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfMPTAmount, soeDEFAULT)
|
||||
LEDGER_ENTRY_FIELD(sfLockedAmount, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which tracks Oracle
|
||||
\sa keylet::oracle
|
||||
*/
|
||||
LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, oracle, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOracleDocumentID, soeOPTIONAL},
|
||||
{sfProvider, soeREQUIRED},
|
||||
{sfPriceDataSeries, soeREQUIRED},
|
||||
{sfAssetClass, soeREQUIRED},
|
||||
{sfLastUpdateTime, soeREQUIRED},
|
||||
{sfURI, soeOPTIONAL},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltORACLE, 0x0080, Oracle, oracle, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfOwner, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOracleDocumentID, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfProvider, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPriceDataSeries, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAssetClass, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfLastUpdateTime, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfURI, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which tracks Credential
|
||||
\sa keylet::credential
|
||||
*/
|
||||
LEDGER_ENTRY(ltCREDENTIAL, 0x0081, Credential, credential, ({
|
||||
{sfSubject, soeREQUIRED},
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
{sfURI, soeOPTIONAL},
|
||||
{sfIssuerNode, soeREQUIRED},
|
||||
{sfSubjectNode, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltCREDENTIAL, 0x0081, Credential, credential, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfSubject, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfIssuer, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfCredentialType, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfExpiration, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfURI, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfIssuerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSubjectNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object which tracks PermissionedDomain
|
||||
\sa keylet::permissionedDomain
|
||||
*/
|
||||
LEDGER_ENTRY(ltPERMISSIONED_DOMAIN, 0x0082, PermissionedDomain, permissioned_domain, ({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfSequence, soeREQUIRED},
|
||||
{sfAcceptedCredentials, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
LEDGER_ENTRY(ltPERMISSIONED_DOMAIN, 0x0082, PermissionedDomain, permissioned_domain, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfOwner, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSequence, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAcceptedCredentials, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(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},
|
||||
}))
|
||||
LEDGER_ENTRY(ltDELEGATE, 0x0083, Delegate, delegate, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAuthorize, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPermissions, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
))
|
||||
|
||||
/** A ledger object representing a single asset vault.
|
||||
\sa keylet::vault
|
||||
*/
|
||||
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},
|
||||
{sfScale, soeDEFAULT},
|
||||
LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, DEFINE_LEDGER_ENTRY_FIELDS(
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfPreviousTxnLgrSeq, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfSequence, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwnerNode, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfOwner, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAccount, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfData, soeOPTIONAL)
|
||||
LEDGER_ENTRY_FIELD(sfAsset, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAssetsTotal, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAssetsAvailable, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfAssetsMaximum, soeDEFAULT)
|
||||
LEDGER_ENTRY_FIELD(sfLossUnrealized, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfShareMPTID, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfWithdrawalPolicy, soeREQUIRED)
|
||||
LEDGER_ENTRY_FIELD(sfScale, soeDEFAULT)
|
||||
// no SharesTotal ever (use MPTIssuance.sfOutstandingAmount)
|
||||
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
|
||||
}))
|
||||
))
|
||||
|
||||
#undef EXPAND
|
||||
#undef LEDGER_ENTRY_DUPLICATE
|
||||
|
||||
LEDGER_ENTRIES_END
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#if !defined(TYPED_SFIELD)
|
||||
#error "undefined macro: TYPED_SFIELD"
|
||||
#endif
|
||||
#if !defined(ARRAY_SFIELD)
|
||||
#error "undefined macro: ARRAY_SFIELD"
|
||||
#endif
|
||||
|
||||
// untyped
|
||||
UNTYPED_SFIELD(sfLedgerEntry, LEDGERENTRY, 257)
|
||||
@@ -174,8 +177,7 @@ 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,
|
||||
SField::sMD_PseudoAccount | SField::sMD_Default)
|
||||
TYPED_SFIELD(sfAMMID, UINT256, 14)
|
||||
|
||||
// 256-bit (uncommon)
|
||||
TYPED_SFIELD(sfBookDirectory, UINT256, 16)
|
||||
@@ -197,8 +199,7 @@ 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(sfVaultID, UINT256, 35)
|
||||
TYPED_SFIELD(sfParentBatchID, UINT256, 36)
|
||||
|
||||
// number (common)
|
||||
@@ -208,12 +209,6 @@ TYPED_SFIELD(sfAssetsMaximum, NUMBER, 3)
|
||||
TYPED_SFIELD(sfAssetsTotal, NUMBER, 4)
|
||||
TYPED_SFIELD(sfLossUnrealized, NUMBER, 5)
|
||||
|
||||
// int32
|
||||
// NOTE: Do not use `sfDummyInt32`. It's so far the only use of INT32
|
||||
// in this file and has been defined here for test only.
|
||||
// TODO: Replace `sfDummyInt32` with actually useful field.
|
||||
TYPED_SFIELD(sfDummyInt32, INT32, 1) // for tests only
|
||||
|
||||
// currency amount (common)
|
||||
TYPED_SFIELD(sfAmount, AMOUNT, 1)
|
||||
TYPED_SFIELD(sfBalance, AMOUNT, 2)
|
||||
@@ -375,33 +370,33 @@ UNTYPED_SFIELD(sfBook, OBJECT, 36)
|
||||
// array of objects (common)
|
||||
// ARRAY/1 is reserved for end of array
|
||||
// sfSigningAccounts has never been used.
|
||||
//UNTYPED_SFIELD(sfSigningAccounts, ARRAY, 2)
|
||||
UNTYPED_SFIELD(sfSigners, ARRAY, 3, SField::sMD_Default, SField::notSigning)
|
||||
UNTYPED_SFIELD(sfSignerEntries, ARRAY, 4)
|
||||
UNTYPED_SFIELD(sfTemplate, ARRAY, 5)
|
||||
UNTYPED_SFIELD(sfNecessary, ARRAY, 6)
|
||||
UNTYPED_SFIELD(sfSufficient, ARRAY, 7)
|
||||
UNTYPED_SFIELD(sfAffectedNodes, ARRAY, 8)
|
||||
UNTYPED_SFIELD(sfMemos, ARRAY, 9)
|
||||
UNTYPED_SFIELD(sfNFTokens, ARRAY, 10)
|
||||
UNTYPED_SFIELD(sfHooks, ARRAY, 11)
|
||||
UNTYPED_SFIELD(sfVoteSlots, ARRAY, 12)
|
||||
UNTYPED_SFIELD(sfAdditionalBooks, ARRAY, 13)
|
||||
//UNTYPED_SFIELD(sfSigningAccounts, sfInvalid, ARRAY, 2)
|
||||
ARRAY_SFIELD(sfSigners, sfSigner, ARRAY, 3, SField::sMD_Default, SField::notSigning)
|
||||
ARRAY_SFIELD(sfSignerEntries, sfSignerEntry, ARRAY, 4)
|
||||
ARRAY_SFIELD(sfTemplate, sfInvalid, ARRAY, 5)
|
||||
ARRAY_SFIELD(sfNecessary, sfInvalid, ARRAY, 6)
|
||||
ARRAY_SFIELD(sfSufficient, sfInvalid, ARRAY, 7)
|
||||
ARRAY_SFIELD(sfAffectedNodes, sfInvalid, ARRAY, 8)
|
||||
ARRAY_SFIELD(sfMemos, sfInvalid, ARRAY, 9)
|
||||
ARRAY_SFIELD(sfNFTokens, sfNFToken, ARRAY, 10)
|
||||
ARRAY_SFIELD(sfHooks, sfInvalid, ARRAY, 11)
|
||||
ARRAY_SFIELD(sfVoteSlots, sfVoteEntry, ARRAY, 12)
|
||||
ARRAY_SFIELD(sfAdditionalBooks, sfInvalid, ARRAY, 13)
|
||||
|
||||
// array of objects (uncommon)
|
||||
UNTYPED_SFIELD(sfMajorities, ARRAY, 16)
|
||||
UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17)
|
||||
UNTYPED_SFIELD(sfHookExecutions, ARRAY, 18)
|
||||
UNTYPED_SFIELD(sfHookParameters, ARRAY, 19)
|
||||
UNTYPED_SFIELD(sfHookGrants, ARRAY, 20)
|
||||
UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22)
|
||||
// 23 unused
|
||||
UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24)
|
||||
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)
|
||||
UNTYPED_SFIELD(sfRawTransactions, ARRAY, 30)
|
||||
UNTYPED_SFIELD(sfBatchSigners, ARRAY, 31, SField::sMD_Default, SField::notSigning)
|
||||
ARRAY_SFIELD(sfMajorities, sfMajority, ARRAY, 16)
|
||||
ARRAY_SFIELD(sfDisabledValidators, sfDisabledValidator, ARRAY, 17)
|
||||
ARRAY_SFIELD(sfHookExecutions, sfInvalid, ARRAY, 18)
|
||||
ARRAY_SFIELD(sfHookParameters, sfInvalid, ARRAY, 19)
|
||||
ARRAY_SFIELD(sfHookGrants, sfInvalid, ARRAY, 20)
|
||||
ARRAY_SFIELD(sfXChainClaimAttestations, sfInvalid, ARRAY, 21)
|
||||
ARRAY_SFIELD(sfXChainCreateAccountAttestations, sfInvalid, ARRAY, 22)
|
||||
// 23 unused
|
||||
ARRAY_SFIELD(sfPriceDataSeries, sfPriceData, ARRAY, 24)
|
||||
ARRAY_SFIELD(sfAuthAccounts, sfAuthAccount, ARRAY, 25)
|
||||
ARRAY_SFIELD(sfAuthorizeCredentials, sfInvalid, ARRAY, 26)
|
||||
ARRAY_SFIELD(sfUnauthorizeCredentials, sfInvalid, ARRAY, 27)
|
||||
ARRAY_SFIELD(sfAcceptedCredentials, sfInvalid, ARRAY, 28)
|
||||
ARRAY_SFIELD(sfPermissions, sfPermission, ARRAY, 29)
|
||||
ARRAY_SFIELD(sfRawTransactions, sfInvalid, ARRAY, 30)
|
||||
ARRAY_SFIELD(sfBatchSigners, sfBatchSigner, ARRAY, 31, SField::sMD_Default, SField::notSigning)
|
||||
|
||||
@@ -22,31 +22,16 @@
|
||||
#endif
|
||||
|
||||
/**
|
||||
* TRANSACTION(tag, value, name, delegatable, amendments, privileges, fields)
|
||||
*
|
||||
* To ease maintenance, you may replace any unneeded values with "..."
|
||||
* e.g. #define TRANSACTION(tag, value, name, ...)
|
||||
* TRANSACTION(tag, value, name, delegatable, amendments, fields)
|
||||
*
|
||||
* You must define a transactor class in the `ripple` namespace named `name`,
|
||||
* 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 defined and used in InvariantCheck.cpp
|
||||
* and include its header in `src/xrpld/app/tx/detail/applySteps.cpp`.
|
||||
*/
|
||||
|
||||
/** This transaction type executes a payment. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Payment.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYMENT, 0, Payment,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
createAcct,
|
||||
({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
@@ -60,13 +45,9 @@ TRANSACTION(ttPAYMENT, 0, Payment,
|
||||
}))
|
||||
|
||||
/** This transaction type creates an escrow object. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Escrow.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
@@ -80,7 +61,6 @@ TRANSACTION(ttESCROW_CREATE, 1, EscrowCreate,
|
||||
TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
@@ -91,13 +71,9 @@ TRANSACTION(ttESCROW_FINISH, 2, EscrowFinish,
|
||||
|
||||
|
||||
/** This transaction type adjusts various account settings. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetAccount.h>
|
||||
#endif
|
||||
TRANSACTION(ttACCOUNT_SET, 3, AccountSet,
|
||||
Delegation::notDelegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfEmailHash, soeOPTIONAL},
|
||||
{sfWalletLocator, soeOPTIONAL},
|
||||
@@ -112,26 +88,18 @@ TRANSACTION(ttACCOUNT_SET, 3, AccountSet,
|
||||
}))
|
||||
|
||||
/** This transaction type cancels an existing escrow. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Escrow.h>
|
||||
#endif
|
||||
TRANSACTION(ttESCROW_CANCEL, 4, EscrowCancel,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type sets or clears an account's "regular key". */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetRegularKey.h>
|
||||
#endif
|
||||
TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey,
|
||||
Delegation::notDelegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfRegularKey, soeOPTIONAL},
|
||||
}))
|
||||
@@ -139,13 +107,9 @@ TRANSACTION(ttREGULAR_KEY_SET, 5, SetRegularKey,
|
||||
// 6 deprecated
|
||||
|
||||
/** This transaction type creates an offer to trade one asset for another. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CreateOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttOFFER_CREATE, 7, OfferCreate,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfTakerPays, soeREQUIRED},
|
||||
{sfTakerGets, soeREQUIRED},
|
||||
@@ -155,13 +119,9 @@ TRANSACTION(ttOFFER_CREATE, 7, OfferCreate,
|
||||
}))
|
||||
|
||||
/** This transaction type cancels existing offers to trade one asset for another. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CancelOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfOfferSequence, soeREQUIRED},
|
||||
}))
|
||||
@@ -169,13 +129,9 @@ TRANSACTION(ttOFFER_CANCEL, 8, OfferCancel,
|
||||
// 9 deprecated
|
||||
|
||||
/** This transaction type creates a new set of tickets. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CreateTicket.h>
|
||||
#endif
|
||||
TRANSACTION(ttTICKET_CREATE, 10, TicketCreate,
|
||||
Delegation::delegatable,
|
||||
featureTicketBatch,
|
||||
noPriv,
|
||||
({
|
||||
{sfTicketCount, soeREQUIRED},
|
||||
}))
|
||||
@@ -185,26 +141,18 @@ 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.
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetSignerList.h>
|
||||
#endif
|
||||
TRANSACTION(ttSIGNER_LIST_SET, 12, SignerListSet,
|
||||
Delegation::notDelegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfSignerQuorum, soeREQUIRED},
|
||||
{sfSignerEntries, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type creates a new unidirectional XRP payment channel. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/PayChan.h>
|
||||
#endif
|
||||
TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
@@ -218,7 +166,6 @@ TRANSACTION(ttPAYCHAN_CREATE, 13, PaymentChannelCreate,
|
||||
TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfChannel, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
@@ -229,7 +176,6 @@ TRANSACTION(ttPAYCHAN_FUND, 14, PaymentChannelFund,
|
||||
TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfChannel, soeREQUIRED},
|
||||
{sfAmount, soeOPTIONAL},
|
||||
@@ -240,13 +186,9 @@ TRANSACTION(ttPAYCHAN_CLAIM, 15, PaymentChannelClaim,
|
||||
}))
|
||||
|
||||
/** This transaction type creates a new check. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CreateCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
|
||||
Delegation::delegatable,
|
||||
featureChecks,
|
||||
noPriv,
|
||||
({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfSendMax, soeREQUIRED},
|
||||
@@ -256,13 +198,9 @@ TRANSACTION(ttCHECK_CREATE, 16, CheckCreate,
|
||||
}))
|
||||
|
||||
/** This transaction type cashes an existing check. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CashCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CASH, 17, CheckCash,
|
||||
Delegation::delegatable,
|
||||
featureChecks,
|
||||
noPriv,
|
||||
({
|
||||
{sfCheckID, soeREQUIRED},
|
||||
{sfAmount, soeOPTIONAL},
|
||||
@@ -270,25 +208,17 @@ TRANSACTION(ttCHECK_CASH, 17, CheckCash,
|
||||
}))
|
||||
|
||||
/** This transaction type cancels an existing check. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/CancelCheck.h>
|
||||
#endif
|
||||
TRANSACTION(ttCHECK_CANCEL, 18, CheckCancel,
|
||||
Delegation::delegatable,
|
||||
featureChecks,
|
||||
noPriv,
|
||||
({
|
||||
{sfCheckID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type grants or revokes authorization to transfer funds. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DepositPreauth.h>
|
||||
#endif
|
||||
TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth,
|
||||
Delegation::delegatable,
|
||||
featureDepositPreauth,
|
||||
noPriv,
|
||||
({
|
||||
{sfAuthorize, soeOPTIONAL},
|
||||
{sfUnauthorize, soeOPTIONAL},
|
||||
@@ -297,13 +227,9 @@ TRANSACTION(ttDEPOSIT_PREAUTH, 19, DepositPreauth,
|
||||
}))
|
||||
|
||||
/** This transaction type modifies a trustline between two accounts. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetTrust.h>
|
||||
#endif
|
||||
TRANSACTION(ttTRUST_SET, 20, TrustSet,
|
||||
Delegation::delegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfLimitAmount, soeOPTIONAL},
|
||||
{sfQualityIn, soeOPTIONAL},
|
||||
@@ -311,13 +237,9 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet,
|
||||
}))
|
||||
|
||||
/** This transaction type deletes an existing account. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DeleteAccount.h>
|
||||
#endif
|
||||
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
|
||||
Delegation::notDelegatable,
|
||||
featureDeletableAccounts,
|
||||
mustDeleteAcct,
|
||||
uint256{},
|
||||
({
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfDestinationTag, soeOPTIONAL},
|
||||
@@ -327,13 +249,9 @@ TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
|
||||
// 22 reserved
|
||||
|
||||
/** This transaction mints a new NFT. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenMint.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint,
|
||||
Delegation::delegatable,
|
||||
featureNonFungibleTokensV1,
|
||||
changeNFTCounts,
|
||||
({
|
||||
{sfNFTokenTaxon, soeREQUIRED},
|
||||
{sfTransferFee, soeOPTIONAL},
|
||||
@@ -345,26 +263,18 @@ TRANSACTION(ttNFTOKEN_MINT, 25, NFTokenMint,
|
||||
}))
|
||||
|
||||
/** This transaction burns (i.e. destroys) an existing NFT. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenBurn.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_BURN, 26, NFTokenBurn,
|
||||
Delegation::delegatable,
|
||||
featureNonFungibleTokensV1,
|
||||
changeNFTCounts,
|
||||
({
|
||||
{sfNFTokenID, soeREQUIRED},
|
||||
{sfOwner, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction creates a new offer to buy or sell an NFT. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenCreateOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer,
|
||||
Delegation::delegatable,
|
||||
featureNonFungibleTokensV1,
|
||||
noPriv,
|
||||
({
|
||||
{sfNFTokenID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED},
|
||||
@@ -374,25 +284,17 @@ TRANSACTION(ttNFTOKEN_CREATE_OFFER, 27, NFTokenCreateOffer,
|
||||
}))
|
||||
|
||||
/** This transaction cancels an existing offer to buy or sell an existing NFT. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenCancelOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_CANCEL_OFFER, 28, NFTokenCancelOffer,
|
||||
Delegation::delegatable,
|
||||
featureNonFungibleTokensV1,
|
||||
noPriv,
|
||||
({
|
||||
{sfNFTokenOffers, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction accepts an existing offer to buy or sell an existing NFT. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenAcceptOffer.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||
Delegation::delegatable,
|
||||
featureNonFungibleTokensV1,
|
||||
noPriv,
|
||||
({
|
||||
{sfNFTokenBuyOffer, soeOPTIONAL},
|
||||
{sfNFTokenSellOffer, soeOPTIONAL},
|
||||
@@ -400,26 +302,18 @@ TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||
}))
|
||||
|
||||
/** This transaction claws back issued tokens. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Clawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttCLAWBACK, 30, Clawback,
|
||||
Delegation::delegatable,
|
||||
featureClawback,
|
||||
noPriv,
|
||||
({
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
{sfHolder, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction claws back tokens from an AMM pool. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback,
|
||||
Delegation::delegatable,
|
||||
featureAMMClawback,
|
||||
mayDeleteAcct | overrideFreeze,
|
||||
({
|
||||
{sfHolder, soeREQUIRED},
|
||||
{sfAsset, soeREQUIRED},
|
||||
@@ -428,13 +322,9 @@ TRANSACTION(ttAMM_CLAWBACK, 31, AMMClawback,
|
||||
}))
|
||||
|
||||
/** This transaction type creates an AMM instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_CREATE, 35, AMMCreate,
|
||||
Delegation::delegatable,
|
||||
featureAMM,
|
||||
createPseudoAcct,
|
||||
({
|
||||
{sfAmount, soeREQUIRED},
|
||||
{sfAmount2, soeREQUIRED},
|
||||
@@ -442,13 +332,9 @@ TRANSACTION(ttAMM_CREATE, 35, AMMCreate,
|
||||
}))
|
||||
|
||||
/** This transaction type deposits into an AMM instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMDeposit.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit,
|
||||
Delegation::delegatable,
|
||||
featureAMM,
|
||||
noPriv,
|
||||
({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
@@ -460,13 +346,9 @@ TRANSACTION(ttAMM_DEPOSIT, 36, AMMDeposit,
|
||||
}))
|
||||
|
||||
/** This transaction type withdraws from an AMM instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMWithdraw.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw,
|
||||
Delegation::delegatable,
|
||||
featureAMM,
|
||||
mayDeleteAcct,
|
||||
({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
@@ -477,13 +359,9 @@ TRANSACTION(ttAMM_WITHDRAW, 37, AMMWithdraw,
|
||||
}))
|
||||
|
||||
/** This transaction type votes for the trading fee */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMVote.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_VOTE, 38, AMMVote,
|
||||
Delegation::delegatable,
|
||||
featureAMM,
|
||||
noPriv,
|
||||
({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
@@ -491,13 +369,9 @@ TRANSACTION(ttAMM_VOTE, 38, AMMVote,
|
||||
}))
|
||||
|
||||
/** This transaction type bids for the auction slot */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMBid.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_BID, 39, AMMBid,
|
||||
Delegation::delegatable,
|
||||
featureAMM,
|
||||
noPriv,
|
||||
({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
@@ -507,26 +381,18 @@ TRANSACTION(ttAMM_BID, 39, AMMBid,
|
||||
}))
|
||||
|
||||
/** This transaction type deletes AMM in the empty state */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/AMMDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMM_DELETE, 40, AMMDelete,
|
||||
Delegation::delegatable,
|
||||
featureAMM,
|
||||
mustDeleteAcct,
|
||||
({
|
||||
{sfAsset, soeREQUIRED},
|
||||
{sfAsset2, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transactions creates a crosschain sequence number */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/XChainBridge.h>
|
||||
#endif
|
||||
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||
Delegation::delegatable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfSignatureReward, soeREQUIRED},
|
||||
@@ -537,7 +403,6 @@ TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||
TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||
Delegation::delegatable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfXChainClaimID, soeREQUIRED},
|
||||
@@ -549,7 +414,6 @@ TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||
TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||
Delegation::delegatable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfXChainClaimID, soeREQUIRED},
|
||||
@@ -562,7 +426,6 @@ TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||
TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||
Delegation::delegatable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfDestination, soeREQUIRED},
|
||||
@@ -574,7 +437,6 @@ TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||
TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation,
|
||||
Delegation::delegatable,
|
||||
featureXChainBridge,
|
||||
createAcct,
|
||||
({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
|
||||
@@ -591,11 +453,9 @@ 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,
|
||||
featureXChainBridge,
|
||||
createAcct,
|
||||
({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
|
||||
@@ -616,7 +476,6 @@ TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46,
|
||||
TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||
Delegation::delegatable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfSignatureReward, soeOPTIONAL},
|
||||
@@ -627,7 +486,6 @@ TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||
TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
Delegation::delegatable,
|
||||
featureXChainBridge,
|
||||
noPriv,
|
||||
({
|
||||
{sfXChainBridge, soeREQUIRED},
|
||||
{sfSignatureReward, soeREQUIRED},
|
||||
@@ -635,13 +493,9 @@ TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
}))
|
||||
|
||||
/** This transaction type creates or updates a DID */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DID.h>
|
||||
#endif
|
||||
TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||
Delegation::delegatable,
|
||||
featureDID,
|
||||
noPriv,
|
||||
({
|
||||
{sfDIDDocument, soeOPTIONAL},
|
||||
{sfURI, soeOPTIONAL},
|
||||
@@ -652,17 +506,12 @@ TRANSACTION(ttDID_SET, 49, DIDSet,
|
||||
TRANSACTION(ttDID_DELETE, 50, DIDDelete,
|
||||
Delegation::delegatable,
|
||||
featureDID,
|
||||
noPriv,
|
||||
({}))
|
||||
|
||||
/** This transaction type creates an Oracle instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/SetOracle.h>
|
||||
#endif
|
||||
TRANSACTION(ttORACLE_SET, 51, OracleSet,
|
||||
Delegation::delegatable,
|
||||
featurePriceOracle,
|
||||
noPriv,
|
||||
({
|
||||
{sfOracleDocumentID, soeREQUIRED},
|
||||
{sfProvider, soeOPTIONAL},
|
||||
@@ -673,38 +522,26 @@ TRANSACTION(ttORACLE_SET, 51, OracleSet,
|
||||
}))
|
||||
|
||||
/** This transaction type deletes an Oracle instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/DeleteOracle.h>
|
||||
#endif
|
||||
TRANSACTION(ttORACLE_DELETE, 52, OracleDelete,
|
||||
Delegation::delegatable,
|
||||
featurePriceOracle,
|
||||
noPriv,
|
||||
({
|
||||
{sfOracleDocumentID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type fixes a problem in the ledger state */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/LedgerStateFix.h>
|
||||
#endif
|
||||
TRANSACTION(ttLEDGER_STATE_FIX, 53, LedgerStateFix,
|
||||
Delegation::delegatable,
|
||||
fixNFTokenPageLinks,
|
||||
noPriv,
|
||||
({
|
||||
{sfLedgerFixType, soeREQUIRED},
|
||||
{sfOwner, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type creates a MPTokensIssuance instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceCreate.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate,
|
||||
Delegation::delegatable,
|
||||
featureMPTokensV1,
|
||||
createMPTIssuance,
|
||||
({
|
||||
{sfAssetScale, soeOPTIONAL},
|
||||
{sfTransferFee, soeOPTIONAL},
|
||||
@@ -715,25 +552,17 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_CREATE, 54, MPTokenIssuanceCreate,
|
||||
}))
|
||||
|
||||
/** This transaction type destroys a MPTokensIssuance instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceDestroy.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_DESTROY, 55, MPTokenIssuanceDestroy,
|
||||
Delegation::delegatable,
|
||||
featureMPTokensV1,
|
||||
destroyMPTIssuance,
|
||||
({
|
||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type sets flags on a MPTokensIssuance or MPToken instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/MPTokenIssuanceSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||
Delegation::delegatable,
|
||||
featureMPTokensV1,
|
||||
noPriv,
|
||||
({
|
||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||
{sfHolder, soeOPTIONAL},
|
||||
@@ -744,26 +573,18 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||
}))
|
||||
|
||||
/** This transaction type authorizes a MPToken instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/MPTokenAuthorize.h>
|
||||
#endif
|
||||
TRANSACTION(ttMPTOKEN_AUTHORIZE, 57, MPTokenAuthorize,
|
||||
Delegation::delegatable,
|
||||
featureMPTokensV1,
|
||||
mustAuthorizeMPT,
|
||||
({
|
||||
{sfMPTokenIssuanceID, soeREQUIRED},
|
||||
{sfHolder, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction type create an Credential instance */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Credentials.h>
|
||||
#endif
|
||||
TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||
Delegation::delegatable,
|
||||
featureCredentials,
|
||||
noPriv,
|
||||
({
|
||||
{sfSubject, soeREQUIRED},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
@@ -775,7 +596,6 @@ TRANSACTION(ttCREDENTIAL_CREATE, 58, CredentialCreate,
|
||||
TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||
Delegation::delegatable,
|
||||
featureCredentials,
|
||||
noPriv,
|
||||
({
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfCredentialType, soeREQUIRED},
|
||||
@@ -785,7 +605,6 @@ TRANSACTION(ttCREDENTIAL_ACCEPT, 59, CredentialAccept,
|
||||
TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete,
|
||||
Delegation::delegatable,
|
||||
featureCredentials,
|
||||
noPriv,
|
||||
({
|
||||
{sfSubject, soeOPTIONAL},
|
||||
{sfIssuer, soeOPTIONAL},
|
||||
@@ -793,13 +612,9 @@ TRANSACTION(ttCREDENTIAL_DELETE, 60, CredentialDelete,
|
||||
}))
|
||||
|
||||
/** This transaction type modify a NFToken */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/NFTokenModify.h>
|
||||
#endif
|
||||
TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify,
|
||||
Delegation::delegatable,
|
||||
featureDynamicNFT,
|
||||
noPriv,
|
||||
({
|
||||
{sfNFTokenID, soeREQUIRED},
|
||||
{sfOwner, soeOPTIONAL},
|
||||
@@ -807,51 +622,35 @@ TRANSACTION(ttNFTOKEN_MODIFY, 61, NFTokenModify,
|
||||
}))
|
||||
|
||||
/** This transaction type creates or modifies a Permissioned Domain */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/PermissionedDomainSet.h>
|
||||
#endif
|
||||
TRANSACTION(ttPERMISSIONED_DOMAIN_SET, 62, PermissionedDomainSet,
|
||||
Delegation::delegatable,
|
||||
featurePermissionedDomains,
|
||||
noPriv,
|
||||
({
|
||||
{sfDomainID, soeOPTIONAL},
|
||||
{sfAcceptedCredentials, soeREQUIRED},
|
||||
}))
|
||||
|
||||
/** This transaction type deletes a Permissioned Domain */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/PermissionedDomainDelete.h>
|
||||
#endif
|
||||
TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete,
|
||||
Delegation::delegatable,
|
||||
featurePermissionedDomains,
|
||||
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,
|
||||
featurePermissionDelegationV1_1,
|
||||
noPriv,
|
||||
featurePermissionDelegation,
|
||||
({
|
||||
{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,
|
||||
featureSingleAssetVault,
|
||||
createPseudoAcct | createMPTIssuance | mustModifyVault,
|
||||
({
|
||||
{sfAsset, soeREQUIRED, soeMPTSupported},
|
||||
{sfAssetsMaximum, soeOPTIONAL},
|
||||
@@ -863,13 +662,9 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
|
||||
}))
|
||||
|
||||
/** 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,
|
||||
featureSingleAssetVault,
|
||||
mustModifyVault,
|
||||
({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfAssetsMaximum, soeOPTIONAL},
|
||||
@@ -878,38 +673,26 @@ TRANSACTION(ttVAULT_SET, 66, VaultSet,
|
||||
}))
|
||||
|
||||
/** 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,
|
||||
featureSingleAssetVault,
|
||||
mustDeleteAcct | destroyMPTIssuance | mustModifyVault,
|
||||
({
|
||||
{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,
|
||||
featureSingleAssetVault,
|
||||
mayAuthorizeMPT | mustModifyVault,
|
||||
({
|
||||
{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,
|
||||
featureSingleAssetVault,
|
||||
mayDeleteMPT | mayAuthorizeMPT | mustModifyVault,
|
||||
({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
@@ -918,13 +701,9 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw,
|
||||
}))
|
||||
|
||||
/** 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,
|
||||
featureSingleAssetVault,
|
||||
mayDeleteMPT | mustModifyVault,
|
||||
({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfHolder, soeREQUIRED},
|
||||
@@ -932,13 +711,9 @@ TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
|
||||
}))
|
||||
|
||||
/** This transaction type batches together transactions. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Batch.h>
|
||||
#endif
|
||||
TRANSACTION(ttBATCH, 71, Batch,
|
||||
Delegation::notDelegatable,
|
||||
featureBatch,
|
||||
noPriv,
|
||||
({
|
||||
{sfRawTransactions, soeREQUIRED},
|
||||
{sfBatchSigners, soeOPTIONAL},
|
||||
@@ -948,13 +723,9 @@ TRANSACTION(ttBATCH, 71, Batch,
|
||||
|
||||
For details, see: https://xrpl.org/amendments.html
|
||||
*/
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpld/app/tx/detail/Change.h>
|
||||
#endif
|
||||
TRANSACTION(ttAMENDMENT, 100, EnableAmendment,
|
||||
Delegation::notDelegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
{sfAmendment, soeREQUIRED},
|
||||
@@ -966,7 +737,6 @@ TRANSACTION(ttAMENDMENT, 100, EnableAmendment,
|
||||
TRANSACTION(ttFEE, 101, SetFee,
|
||||
Delegation::notDelegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfLedgerSequence, soeOPTIONAL},
|
||||
// Old version uses raw numbers
|
||||
@@ -987,7 +757,6 @@ TRANSACTION(ttFEE, 101, SetFee,
|
||||
TRANSACTION(ttUNL_MODIFY, 102, UNLModify,
|
||||
Delegation::notDelegatable,
|
||||
uint256{},
|
||||
noPriv,
|
||||
({
|
||||
{sfUNLModifyDisabling, soeREQUIRED},
|
||||
{sfLedgerSequence, soeREQUIRED},
|
||||
|
||||
@@ -569,7 +569,6 @@ JSS(settle_delay); // out: AccountChannels
|
||||
JSS(severity); // in: LogLevel
|
||||
JSS(shares); // out: VaultInfo
|
||||
JSS(signature); // out: NetworkOPs, ChannelAuthorize
|
||||
JSS(signature_target); // in: TransactionSign
|
||||
JSS(signature_verified); // out: ChannelVerify
|
||||
JSS(signing_key); // out: NetworkOPs
|
||||
JSS(signing_keys); // out: ValidatorList
|
||||
@@ -722,12 +721,24 @@ JSS(write_load); // out: GetCounts
|
||||
#undef LEDGER_ENTRY
|
||||
#pragma push_macro("LEDGER_ENTRY_DUPLICATE")
|
||||
#undef LEDGER_ENTRY_DUPLICATE
|
||||
#pragma push_macro("LEDGER_ENTRY_FIELD")
|
||||
#undef LEDGER_ENTRY_FIELD
|
||||
#pragma push_macro("DEFINE_LEDGER_ENTRY_FIELDS")
|
||||
#undef DEFINE_LEDGER_ENTRY_FIELDS
|
||||
#pragma push_macro("LEDGER_ENTRIES_BEGIN")
|
||||
#undef LEDGER_ENTRIES_BEGIN
|
||||
#pragma push_macro("LEDGER_ENTRIES_END")
|
||||
#undef LEDGER_ENTRIES_END
|
||||
|
||||
#define LEDGER_ENTRY(tag, value, name, rpcName, ...) \
|
||||
JSS(name); \
|
||||
#define LEDGER_ENTRIES_BEGIN
|
||||
#define LEDGER_ENTRIES_END
|
||||
#define DEFINE_LEDGER_ENTRY_FIELDS(...) ({__VA_ARGS__})
|
||||
#define LEDGER_ENTRY_FIELD(...) {__VA_ARGS__},
|
||||
#define LEDGER_ENTRY(tag, value, name, rpcName, fields) \
|
||||
JSS(name); \
|
||||
JSS(rpcName);
|
||||
|
||||
#define LEDGER_ENTRY_DUPLICATE(tag, value, name, rpcName, ...) JSS(rpcName);
|
||||
#define LEDGER_ENTRY_DUPLICATE(tag, value, name, rpcName, fields) JSS(rpcName);
|
||||
|
||||
#include <xrpl/protocol/detail/ledger_entries.macro>
|
||||
|
||||
@@ -735,6 +746,14 @@ JSS(write_load); // out: GetCounts
|
||||
#pragma pop_macro("LEDGER_ENTRY")
|
||||
#undef LEDGER_ENTRY_DUPLICATE
|
||||
#pragma pop_macro("LEDGER_ENTRY_DUPLICATE")
|
||||
#undef LEDGER_ENTRY_FIELD
|
||||
#pragma pop_macro("LEDGER_ENTRY_FIELD")
|
||||
#undef DEFINE_LEDGER_ENTRY_FIELDS
|
||||
#pragma pop_macro("DEFINE_LEDGER_ENTRY_FIELDS")
|
||||
#undef LEDGER_ENTRIES_BEGIN
|
||||
#pragma pop_macro("LEDGER_ENTRIES_BEGIN")
|
||||
#undef LEDGER_ENTRIES_END
|
||||
#pragma pop_macro("LEDGER_ENTRIES_END")
|
||||
|
||||
#undef JSS
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#define RIPPLE_RESOURCE_CONSUMER_H_INCLUDED
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/resource/Charge.h>
|
||||
#include <xrpl/resource/Disposition.h>
|
||||
|
||||
@@ -88,9 +87,6 @@ public:
|
||||
Entry&
|
||||
entry();
|
||||
|
||||
void
|
||||
setPublicKey(PublicKey const& publicKey);
|
||||
|
||||
private:
|
||||
Logic* m_logic;
|
||||
Entry* m_entry;
|
||||
|
||||
@@ -53,7 +53,7 @@ struct Entry : public beast::List<Entry>::Node
|
||||
std::string
|
||||
to_string() const
|
||||
{
|
||||
return getFingerprint(key->address, publicKey);
|
||||
return key->address.to_string();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,9 +82,6 @@ struct Entry : public beast::List<Entry>::Node
|
||||
return local_balance.add(charge, now) + remote_balance;
|
||||
}
|
||||
|
||||
// The public key of the peer
|
||||
std::optional<PublicKey> publicKey;
|
||||
|
||||
// Back pointer to the map key (bit of a hack here)
|
||||
Key const* key;
|
||||
|
||||
|
||||
@@ -436,12 +436,10 @@ public:
|
||||
admin_.erase(admin_.iterator_to(entry));
|
||||
break;
|
||||
default:
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"ripple::Resource::Logic::release : invalid entry "
|
||||
"kind");
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
inactive_.push_back(entry);
|
||||
entry.whenExpires = m_clock.now() + secondsUntilExpiration;
|
||||
|
||||
@@ -30,29 +30,15 @@
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/beast/core/detect_ssl.hpp>
|
||||
#include <boost/beast/core/multi_buffer.hpp>
|
||||
#include <boost/beast/core/tcp_stream.hpp>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/predef.h>
|
||||
|
||||
#if !BOOST_OS_WINDOWS
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -112,27 +98,10 @@ private:
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> strand_;
|
||||
bool ssl_;
|
||||
bool plain_;
|
||||
static constexpr std::chrono::milliseconds INITIAL_ACCEPT_DELAY{50};
|
||||
static constexpr std::chrono::milliseconds MAX_ACCEPT_DELAY{2000};
|
||||
std::chrono::milliseconds accept_delay_{INITIAL_ACCEPT_DELAY};
|
||||
boost::asio::steady_timer backoff_timer_;
|
||||
static constexpr double FREE_FD_THRESHOLD = 0.70;
|
||||
|
||||
struct FDStats
|
||||
{
|
||||
std::uint64_t used{0};
|
||||
std::uint64_t limit{0};
|
||||
};
|
||||
|
||||
void
|
||||
reOpen();
|
||||
|
||||
std::optional<FDStats>
|
||||
query_fd_stats() const;
|
||||
|
||||
bool
|
||||
should_throttle_for_fds();
|
||||
|
||||
public:
|
||||
Door(
|
||||
Handler& handler,
|
||||
@@ -330,7 +299,6 @@ Door<Handler>::Door(
|
||||
, plain_(
|
||||
port_.protocol.count("http") > 0 || port_.protocol.count("ws") > 0 ||
|
||||
port_.protocol.count("ws2"))
|
||||
, backoff_timer_(io_context)
|
||||
{
|
||||
reOpen();
|
||||
}
|
||||
@@ -355,7 +323,6 @@ Door<Handler>::close()
|
||||
return boost::asio::post(
|
||||
strand_,
|
||||
std::bind(&Door<Handler>::close, this->shared_from_this()));
|
||||
backoff_timer_.cancel();
|
||||
error_code ec;
|
||||
acceptor_.close(ec);
|
||||
}
|
||||
@@ -401,17 +368,6 @@ Door<Handler>::do_accept(boost::asio::yield_context do_yield)
|
||||
{
|
||||
while (acceptor_.is_open())
|
||||
{
|
||||
if (should_throttle_for_fds())
|
||||
{
|
||||
backoff_timer_.expires_after(accept_delay_);
|
||||
boost::system::error_code tec;
|
||||
backoff_timer_.async_wait(do_yield[tec]);
|
||||
accept_delay_ = std::min(accept_delay_ * 2, MAX_ACCEPT_DELAY);
|
||||
JLOG(j_.warn()) << "Throttling do_accept for "
|
||||
<< accept_delay_.count() << "ms.";
|
||||
continue;
|
||||
}
|
||||
|
||||
error_code ec;
|
||||
endpoint_type remote_address;
|
||||
stream_type stream(ioc_);
|
||||
@@ -421,28 +377,15 @@ Door<Handler>::do_accept(boost::asio::yield_context do_yield)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
break;
|
||||
|
||||
if (ec == boost::asio::error::no_descriptors ||
|
||||
ec == boost::asio::error::no_buffer_space)
|
||||
JLOG(j_.error()) << "accept: " << ec.message();
|
||||
if (ec == boost::asio::error::no_descriptors)
|
||||
{
|
||||
JLOG(j_.warn()) << "accept: Too many open files. Pausing for "
|
||||
<< accept_delay_.count() << "ms.";
|
||||
|
||||
backoff_timer_.expires_after(accept_delay_);
|
||||
boost::system::error_code tec;
|
||||
backoff_timer_.async_wait(do_yield[tec]);
|
||||
|
||||
accept_delay_ = std::min(accept_delay_ * 2, MAX_ACCEPT_DELAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j_.error()) << "accept error: " << ec.message();
|
||||
JLOG(j_.info()) << "re-opening acceptor";
|
||||
reOpen();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
accept_delay_ = INITIAL_ACCEPT_DELAY;
|
||||
|
||||
if (ssl_ && plain_)
|
||||
{
|
||||
if (auto sp = ios().template emplace<Detector>(
|
||||
@@ -465,60 +408,6 @@ Door<Handler>::do_accept(boost::asio::yield_context do_yield)
|
||||
}
|
||||
}
|
||||
|
||||
template <class Handler>
|
||||
std::optional<typename Door<Handler>::FDStats>
|
||||
Door<Handler>::query_fd_stats() const
|
||||
{
|
||||
#if BOOST_OS_WINDOWS
|
||||
return std::nullopt;
|
||||
#else
|
||||
FDStats s;
|
||||
struct rlimit rl;
|
||||
if (getrlimit(RLIMIT_NOFILE, &rl) != 0 || rl.rlim_cur == RLIM_INFINITY)
|
||||
return std::nullopt;
|
||||
s.limit = static_cast<std::uint64_t>(rl.rlim_cur);
|
||||
#if BOOST_OS_LINUX
|
||||
constexpr char const* kFdDir = "/proc/self/fd";
|
||||
#else
|
||||
constexpr char const* kFdDir = "/dev/fd";
|
||||
#endif
|
||||
if (DIR* d = ::opendir(kFdDir))
|
||||
{
|
||||
std::uint64_t cnt = 0;
|
||||
while (::readdir(d) != nullptr)
|
||||
++cnt;
|
||||
::closedir(d);
|
||||
// readdir counts '.', '..', and the DIR* itself shows in the list
|
||||
s.used = (cnt >= 3) ? (cnt - 3) : 0;
|
||||
return s;
|
||||
}
|
||||
return std::nullopt;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Handler>
|
||||
bool
|
||||
Door<Handler>::should_throttle_for_fds()
|
||||
{
|
||||
#if BOOST_OS_WINDOWS
|
||||
return false;
|
||||
#else
|
||||
auto const stats = query_fd_stats();
|
||||
if (!stats || stats->limit == 0)
|
||||
return false;
|
||||
|
||||
auto const& s = *stats;
|
||||
auto const free = (s.limit > s.used) ? (s.limit - s.used) : 0ull;
|
||||
double const free_ratio =
|
||||
static_cast<double>(free) / static_cast<double>(s.limit);
|
||||
if (free_ratio < FREE_FD_THRESHOLD)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
|
||||
@@ -239,11 +239,9 @@ Logs::fromSeverity(beast::severities::Severity level)
|
||||
case kError:
|
||||
return lsERROR;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("ripple::Logs::fromSeverity : invalid severity");
|
||||
[[fallthrough]];
|
||||
// LCOV_EXCL_STOP
|
||||
case kFatal:
|
||||
break;
|
||||
}
|
||||
@@ -267,11 +265,9 @@ Logs::toSeverity(LogSeverity level)
|
||||
return kWarning;
|
||||
case lsERROR:
|
||||
return kError;
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("ripple::Logs::toSeverity : invalid severity");
|
||||
[[fallthrough]];
|
||||
// LCOV_EXCL_STOP
|
||||
case lsFATAL:
|
||||
break;
|
||||
}
|
||||
@@ -296,11 +292,9 @@ Logs::toString(LogSeverity s)
|
||||
return "Error";
|
||||
case lsFATAL:
|
||||
return "Fatal";
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("ripple::Logs::toString : invalid severity");
|
||||
return "Unknown";
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,11 +356,9 @@ Logs::format(
|
||||
case kError:
|
||||
output += "ERR ";
|
||||
break;
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("ripple::Logs::format : invalid severity");
|
||||
[[fallthrough]];
|
||||
// LCOV_EXCL_STOP
|
||||
case kFatal:
|
||||
output += "FTL ";
|
||||
break;
|
||||
|
||||
@@ -36,7 +36,6 @@ LogThrow(std::string const& title)
|
||||
[[noreturn]] void
|
||||
LogicError(std::string const& s) noexcept
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(debugLog().fatal()) << s;
|
||||
std::cerr << "Logic error: " << s << std::endl;
|
||||
// Use a non-standard contract naming here (without namespace) because
|
||||
@@ -46,7 +45,6 @@ LogicError(std::string const& s) noexcept
|
||||
// For the above reasons, we want this contract to stand out.
|
||||
UNREACHABLE("LogicError", {{"message", s}});
|
||||
std::abort();
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -174,7 +174,7 @@ Array::append(Json::Value const& v)
|
||||
return;
|
||||
}
|
||||
}
|
||||
UNREACHABLE("Json::Array::append : invalid type"); // LCOV_EXCL_LINE
|
||||
UNREACHABLE("Json::Array::append : invalid type");
|
||||
}
|
||||
|
||||
void
|
||||
@@ -209,7 +209,7 @@ Object::set(std::string const& k, Json::Value const& v)
|
||||
return;
|
||||
}
|
||||
}
|
||||
UNREACHABLE("Json::Object::set : invalid type"); // LCOV_EXCL_LINE
|
||||
UNREACHABLE("Json::Object::set : invalid type");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -213,10 +213,8 @@ Value::Value(ValueType type) : type_(type), allocated_(0)
|
||||
value_.bool_ = false;
|
||||
break;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::Value(ValueType) : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,10 +290,8 @@ Value::Value(Value const& other) : type_(other.type_)
|
||||
value_.map_ = new ObjectValues(*other.value_.map_);
|
||||
break;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::Value(Value const&) : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,10 +318,8 @@ Value::~Value()
|
||||
delete value_.map_;
|
||||
break;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::~Value : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,10 +419,8 @@ operator<(Value const& x, Value const& y)
|
||||
return *x.value_.map_ < *y.value_.map_;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::operator<(Value, Value) : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return 0; // unreachable
|
||||
@@ -473,10 +465,8 @@ operator==(Value const& x, Value const& y)
|
||||
return x.value_.map_->size() == y.value_.map_->size() &&
|
||||
*x.value_.map_ == *y.value_.map_;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::operator==(Value, Value) : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return 0; // unreachable
|
||||
@@ -516,10 +506,8 @@ Value::asString() const
|
||||
case objectValue:
|
||||
JSON_ASSERT_MESSAGE(false, "Type is not convertible to string");
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::asString : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return ""; // unreachable
|
||||
@@ -560,10 +548,8 @@ Value::asInt() const
|
||||
case objectValue:
|
||||
JSON_ASSERT_MESSAGE(false, "Type is not convertible to int");
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::asInt : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return 0; // unreachable;
|
||||
@@ -604,10 +590,8 @@ Value::asUInt() const
|
||||
case objectValue:
|
||||
JSON_ASSERT_MESSAGE(false, "Type is not convertible to uint");
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::asUInt : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return 0; // unreachable;
|
||||
@@ -638,10 +622,8 @@ Value::asDouble() const
|
||||
case objectValue:
|
||||
JSON_ASSERT_MESSAGE(false, "Type is not convertible to double");
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::asDouble : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return 0; // unreachable;
|
||||
@@ -672,10 +654,8 @@ Value::asBool() const
|
||||
case objectValue:
|
||||
return value_.map_->size() != 0;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::asBool : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return false; // unreachable;
|
||||
@@ -730,10 +710,8 @@ Value::isConvertibleTo(ValueType other) const
|
||||
return other == objectValue ||
|
||||
(other == nullValue && value_.map_->size() == 0);
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::isConvertible : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return false; // unreachable;
|
||||
@@ -766,10 +744,8 @@ Value::size() const
|
||||
case objectValue:
|
||||
return Int(value_.map_->size());
|
||||
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
UNREACHABLE("Json::Value::size : invalid type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return 0; // unreachable;
|
||||
|
||||
@@ -126,10 +126,10 @@ ApplyStateTable::apply(
|
||||
std::optional<TxMeta> metadata;
|
||||
if (!to.open() || isDryRun)
|
||||
{
|
||||
TxMeta meta(tx.getTransactionID(), to.seq());
|
||||
TxMeta meta(tx.getTransactionID(), to.seq(), parentBatchId);
|
||||
|
||||
meta.setDeliveredAmount(deliver);
|
||||
meta.setParentBatchID(parentBatchId);
|
||||
if (deliver)
|
||||
meta.setDeliveredAmount(*deliver);
|
||||
|
||||
Mods newMod;
|
||||
for (auto& item : items_)
|
||||
@@ -259,11 +259,9 @@ ApplyStateTable::apply(
|
||||
}
|
||||
else
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"ripple::detail::ApplyStateTable::apply : unsupported "
|
||||
"operation type");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,6 +680,12 @@ ApplyStateTable::threadOwners(
|
||||
if (auto const optSleAcct{(*sle)[~sfAccount]})
|
||||
threadTx(base, meta, *optSleAcct, mods, j);
|
||||
|
||||
// Don't thread a check's sfDestination unless the amendment is
|
||||
// enabled
|
||||
if (ledgerType == ltCHECK &&
|
||||
!base.rules().enabled(fixCheckThreading))
|
||||
break;
|
||||
|
||||
// If sfDestination is present, thread to that account
|
||||
if (auto const optSleDest{(*sle)[~sfDestination]})
|
||||
threadTx(base, meta, *optSleDest, mods, j);
|
||||
|
||||
@@ -22,9 +22,6 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::optional<std::uint64_t>
|
||||
@@ -94,21 +91,8 @@ ApplyView::dirAdd(
|
||||
return page;
|
||||
}
|
||||
|
||||
// We rely on modulo arithmetic of unsigned integers (guaranteed in
|
||||
// [basic.fundamental] paragraph 2) to detect page representation overflow.
|
||||
// For signed integers this would be UB, hence static_assert here.
|
||||
static_assert(std::is_unsigned_v<decltype(page)>);
|
||||
// Defensive check against breaking changes in compiler.
|
||||
static_assert([]<typename T>(std::type_identity<T>) constexpr -> T {
|
||||
T tmp = std::numeric_limits<T>::max();
|
||||
return ++tmp;
|
||||
}(std::type_identity<decltype(page)>{}) == 0);
|
||||
++page;
|
||||
// Check whether we're out of pages.
|
||||
if (page == 0)
|
||||
return std::nullopt;
|
||||
if (!rules().enabled(fixDirectoryLimit) &&
|
||||
page >= dirNodeMaxPages) // Old pages limit
|
||||
if (++page >= dirNodeMaxPages)
|
||||
return std::nullopt;
|
||||
|
||||
// We are about to create a new node; we'll link it to
|
||||
@@ -149,10 +133,8 @@ ApplyView::emptyDirDelete(Keylet const& directory)
|
||||
if (directory.type != ltDIR_NODE ||
|
||||
node->getFieldH256(sfRootIndex) != directory.key)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("ripple::ApplyView::emptyDirDelete : invalid node type");
|
||||
return false;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
// The directory still contains entries and so it cannot be removed
|
||||
|
||||
@@ -36,9 +36,7 @@ BookDirs::BookDirs(ReadView const& view, Book const& book)
|
||||
{
|
||||
if (!cdirFirst(*view_, key_, sle_, entry_, index_))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("ripple::BookDirs::BookDirs : directory is empty");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,11 +110,9 @@ BookDirs::const_iterator::operator++()
|
||||
}
|
||||
else if (!cdirFirst(*view_, cur_key_, sle_, entry_, index_))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"ripple::BookDirs::const_iterator::operator++ : directory is "
|
||||
"empty");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,23 +77,19 @@ deleteSLE(
|
||||
AccountID const& account, SField const& node, bool isOwner) -> TER {
|
||||
auto const sleAccount = view.peek(keylet::account(account));
|
||||
if (!sleAccount)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
{ // LCOV_EXCL_START
|
||||
JLOG(j.fatal()) << "Internal error: can't retrieve Owner account.";
|
||||
return tecINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
// Remove object from owner directory
|
||||
std::uint64_t const page = sleCredential->getFieldU64(node);
|
||||
if (!view.dirRemove(
|
||||
keylet::ownerDir(account), page, sleCredential->key(), false))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
{ // LCOV_EXCL_START
|
||||
JLOG(j.fatal()) << "Unable to delete Credential from owner.";
|
||||
return tefBAD_LEDGER;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
if (isOwner)
|
||||
adjustOwnerCount(view, sleAccount, -1, j);
|
||||
|
||||
@@ -324,12 +324,10 @@ isVaultPseudoAccountFrozen(
|
||||
auto const issuer = mptIssuance->getAccountID(sfIssuer);
|
||||
auto const mptIssuer = view.read(keylet::account(issuer));
|
||||
if (mptIssuer == nullptr)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
{ // LCOV_EXCL_START
|
||||
UNREACHABLE("ripple::isVaultPseudoAccountFrozen : null MPToken issuer");
|
||||
return false;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
if (!mptIssuer->isFieldPresent(sfVaultID))
|
||||
return false; // not a Vault pseudo-account, common case
|
||||
@@ -340,8 +338,7 @@ isVaultPseudoAccountFrozen(
|
||||
{ // LCOV_EXCL_START
|
||||
UNREACHABLE("ripple::isVaultPseudoAccountFrozen : null vault");
|
||||
return false;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
return isAnyFrozen(view, {issuer, account}, vault->at(sfAsset), depth + 1);
|
||||
}
|
||||
@@ -629,8 +626,8 @@ xrpLiquid(
|
||||
std::uint32_t const ownerCount = confineOwnerCount(
|
||||
view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj);
|
||||
|
||||
// Pseudo-accounts have no reserve requirement
|
||||
auto const reserve = isPseudoAccount(sle)
|
||||
// AMMs have no reserve requirement
|
||||
auto const reserve = sle->isFieldPresent(sfAMMID)
|
||||
? XRPAmount{0}
|
||||
: view.fees().accountReserve(ownerCount);
|
||||
|
||||
@@ -1042,7 +1039,7 @@ adjustOwnerCount(
|
||||
AccountID const id = (*sle)[sfAccount];
|
||||
std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j);
|
||||
view.adjustOwnerCountHook(id, current, adjusted);
|
||||
sle->at(sfOwnerCount) = adjusted;
|
||||
sle->setFieldU32(sfOwnerCount, adjusted);
|
||||
view.update(sle);
|
||||
}
|
||||
|
||||
@@ -1082,51 +1079,15 @@ pseudoAccountAddress(ReadView const& view, uint256 const& pseudoOwnerKey)
|
||||
return beast::zero;
|
||||
}
|
||||
|
||||
// Pseudo-account designator fields MUST be maintained by including the
|
||||
// SField::sMD_PseudoAccount flag in the SField definition. (Don't forget to
|
||||
// "| SField::sMD_Default"!) The fields do NOT need to be amendment-gated,
|
||||
// since a non-active amendment will not set any field, by definition.
|
||||
// Specific properties of a pseudo-account are NOT checked here, that's what
|
||||
// Note, the list of the pseudo-account designator fields below MUST be
|
||||
// maintained but it does NOT need to be amendment-gated, since a
|
||||
// non-active amendment will not set any field, by definition. Specific
|
||||
// properties of a pseudo-account are NOT checked here, that's what
|
||||
// InvariantCheck is for.
|
||||
[[nodiscard]] std::vector<SField const*> const&
|
||||
getPseudoAccountFields()
|
||||
{
|
||||
static std::vector<SField const*> const pseudoFields = []() {
|
||||
auto const ar = LedgerFormats::getInstance().findByType(ltACCOUNT_ROOT);
|
||||
if (!ar)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
LogicError(
|
||||
"ripple::isPseudoAccount : unable to find account root ledger "
|
||||
"format");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
auto const& soTemplate = ar->getSOTemplate();
|
||||
|
||||
std::vector<SField const*> pseudoFields;
|
||||
for (auto const& field : soTemplate)
|
||||
{
|
||||
if (field.sField().shouldMeta(SField::sMD_PseudoAccount))
|
||||
pseudoFields.emplace_back(&field.sField());
|
||||
}
|
||||
return pseudoFields;
|
||||
}();
|
||||
return pseudoFields;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isPseudoAccount(std::shared_ptr<SLE const> sleAcct)
|
||||
{
|
||||
auto const& fields = getPseudoAccountFields();
|
||||
|
||||
// Intentionally use defensive coding here because it's cheap and makes the
|
||||
// semantics of true return value clean.
|
||||
return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT &&
|
||||
std::count_if(
|
||||
fields.begin(), fields.end(), [&sleAcct](SField const* sf) -> bool {
|
||||
return sleAcct->isFieldPresent(*sf);
|
||||
}) > 0;
|
||||
}
|
||||
static std::array<SField const*, 2> const pseudoAccountOwnerFields = {
|
||||
&sfAMMID, //
|
||||
&sfVaultID, //
|
||||
};
|
||||
|
||||
Expected<std::shared_ptr<SLE>, TER>
|
||||
createPseudoAccount(
|
||||
@@ -1134,11 +1095,10 @@ createPseudoAccount(
|
||||
uint256 const& pseudoOwnerKey,
|
||||
SField const& ownerField)
|
||||
{
|
||||
[[maybe_unused]] auto const& fields = getPseudoAccountFields();
|
||||
XRPL_ASSERT(
|
||||
std::count_if(
|
||||
fields.begin(),
|
||||
fields.end(),
|
||||
pseudoAccountOwnerFields.begin(),
|
||||
pseudoAccountOwnerFields.end(),
|
||||
[&ownerField](SField const* sf) -> bool {
|
||||
return *sf == ownerField;
|
||||
}) == 1,
|
||||
@@ -1174,42 +1134,18 @@ createPseudoAccount(
|
||||
return account;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
canAddHolding(ReadView const& view, Issue const& issue)
|
||||
[[nodiscard]] bool
|
||||
isPseudoAccount(std::shared_ptr<SLE const> sleAcct)
|
||||
{
|
||||
if (issue.native())
|
||||
return tesSUCCESS; // No special checks for XRP
|
||||
|
||||
auto const issuer = view.read(keylet::account(issue.getIssuer()));
|
||||
if (!issuer)
|
||||
return terNO_ACCOUNT;
|
||||
else if (!issuer->isFlag(lsfDefaultRipple))
|
||||
return terNO_RIPPLE;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
canAddHolding(ReadView const& view, MPTIssue const& mptIssue)
|
||||
{
|
||||
auto mptID = mptIssue.getMptID();
|
||||
auto issuance = view.read(keylet::mptIssuance(mptID));
|
||||
if (!issuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
if (!issuance->isFlag(lsfMPTCanTransfer))
|
||||
return tecNO_AUTH;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
canAddHolding(ReadView const& view, Asset const& asset)
|
||||
{
|
||||
return std::visit(
|
||||
[&]<ValidIssueType TIss>(TIss const& issue) -> TER {
|
||||
return canAddHolding(view, issue);
|
||||
},
|
||||
asset.value());
|
||||
// Intentionally use defensive coding here because it's cheap and makes the
|
||||
// semantics of true return value clean.
|
||||
return sleAcct && sleAcct->getType() == ltACCOUNT_ROOT &&
|
||||
std::count_if(
|
||||
pseudoAccountOwnerFields.begin(),
|
||||
pseudoAccountOwnerFields.end(),
|
||||
[&sleAcct](SField const* sf) -> bool {
|
||||
return sleAcct->isFieldPresent(*sf);
|
||||
}) > 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
@@ -1242,12 +1178,6 @@ addEmptyHolding(
|
||||
// If the line already exists, don't create it again.
|
||||
if (view.read(index))
|
||||
return tecDUPLICATE;
|
||||
|
||||
// Can the account cover the trust line reserve ?
|
||||
std::uint32_t const ownerCount = sleDst->at(sfOwnerCount);
|
||||
if (priorBalance < view.fees().accountReserve(ownerCount + 1))
|
||||
return tecNO_LINE_INSUF_RESERVE;
|
||||
|
||||
return trustCreate(
|
||||
view,
|
||||
high,
|
||||
@@ -1298,7 +1228,7 @@ authorizeMPToken(
|
||||
{
|
||||
auto const sleAcct = view.peek(keylet::account(account));
|
||||
if (!sleAcct)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
|
||||
// If the account that submitted the tx is a holder
|
||||
// Note: `account_` is holder's account
|
||||
@@ -1363,17 +1293,17 @@ authorizeMPToken(
|
||||
|
||||
auto const sleMptIssuance = view.read(keylet::mptIssuance(mptIssuanceID));
|
||||
if (!sleMptIssuance)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
|
||||
// If the account that submitted this tx is the issuer of the MPT
|
||||
// Note: `account_` is issuer's account
|
||||
// `holderID` is holder's account
|
||||
if (account != (*sleMptIssuance)[sfIssuer])
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
|
||||
auto const sleMpt = view.peek(keylet::mptoken(mptIssuanceID, *holderID));
|
||||
if (!sleMpt)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
|
||||
std::uint32_t const flagsIn = sleMpt->getFieldU32(sfFlags);
|
||||
std::uint32_t flagsOut = flagsIn;
|
||||
@@ -1430,7 +1360,7 @@ trustCreate(
|
||||
describeOwnerDir(uLowAccountID));
|
||||
|
||||
if (!lowNode)
|
||||
return tecDIR_FULL; // LCOV_EXCL_LINE
|
||||
return tecDIR_FULL;
|
||||
|
||||
auto highNode = view.dirInsert(
|
||||
keylet::ownerDir(uHighAccountID),
|
||||
@@ -1438,14 +1368,14 @@ trustCreate(
|
||||
describeOwnerDir(uHighAccountID));
|
||||
|
||||
if (!highNode)
|
||||
return tecDIR_FULL; // LCOV_EXCL_LINE
|
||||
return tecDIR_FULL;
|
||||
|
||||
bool const bSetDst = saLimit.getIssuer() == uDstAccountID;
|
||||
bool const bSetHigh = bSrcHigh ^ bSetDst;
|
||||
|
||||
XRPL_ASSERT(sleAccount, "ripple::trustCreate : non-null SLE");
|
||||
if (!sleAccount)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
return tefINTERNAL;
|
||||
|
||||
XRPL_ASSERT(
|
||||
sleAccount->getAccountID(sfAccount) ==
|
||||
@@ -1524,12 +1454,10 @@ removeEmptyHolding(
|
||||
{
|
||||
auto const sle = view.read(keylet::account(accountID));
|
||||
if (!sle)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
return tecINTERNAL;
|
||||
auto const balance = sle->getFieldAmount(sfBalance);
|
||||
if (balance.xrp() != 0)
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -1547,8 +1475,7 @@ removeEmptyHolding(
|
||||
auto sleLowAccount =
|
||||
view.peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
|
||||
if (!sleLowAccount)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
return tecINTERNAL;
|
||||
adjustOwnerCount(view, sleLowAccount, -1, journal);
|
||||
// It's not really necessary to clear the reserve flag, since the line
|
||||
// is about to be deleted, but this will make the metadata reflect an
|
||||
@@ -1562,8 +1489,7 @@ removeEmptyHolding(
|
||||
auto sleHighAccount =
|
||||
view.peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
|
||||
if (!sleHighAccount)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
return tecINTERNAL;
|
||||
adjustOwnerCount(view, sleHighAccount, -1, journal);
|
||||
// It's not really necessary to clear the reserve flag, since the line
|
||||
// is about to be deleted, but this will make the metadata reflect an
|
||||
@@ -1623,7 +1549,7 @@ trustDelete(
|
||||
sleRippleState->key(),
|
||||
false))
|
||||
{
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
JLOG(j.trace()) << "trustDelete: Deleting ripple line: high";
|
||||
@@ -1634,7 +1560,7 @@ trustDelete(
|
||||
sleRippleState->key(),
|
||||
false))
|
||||
{
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
JLOG(j.trace()) << "trustDelete: Deleting ripple line: state";
|
||||
@@ -1660,7 +1586,7 @@ offerDelete(ApplyView& view, std::shared_ptr<SLE> const& sle, beast::Journal j)
|
||||
offerIndex,
|
||||
false))
|
||||
{
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
if (!view.dirRemove(
|
||||
@@ -1669,7 +1595,7 @@ offerDelete(ApplyView& view, std::shared_ptr<SLE> const& sle, beast::Journal j)
|
||||
offerIndex,
|
||||
false))
|
||||
{
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
return tefBAD_LEDGER;
|
||||
}
|
||||
|
||||
if (sle->isFieldPresent(sfAdditionalBooks))
|
||||
@@ -1833,7 +1759,7 @@ rippleCreditIOU(
|
||||
|
||||
auto const sleAccount = view.peek(keylet::account(uReceiverID));
|
||||
if (!sleAccount)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
return tefINTERNAL;
|
||||
|
||||
bool const noRipple = (sleAccount->getFlags() & lsfDefaultRipple) == 0;
|
||||
|
||||
@@ -1923,16 +1849,14 @@ accountSendIOU(
|
||||
{
|
||||
if (saAmount < beast::zero || saAmount.holds<MPTIssue>())
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
XRPL_ASSERT(
|
||||
saAmount >= beast::zero && !saAmount.holds<MPTIssue>(),
|
||||
"ripple::accountSendIOU : minimum amount and not MPT");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
/* If we aren't sending anything or if the sender is the same as the
|
||||
@@ -1989,10 +1913,8 @@ accountSendIOU(
|
||||
{
|
||||
// VFALCO Its laborious to have to mutate the
|
||||
// TER based on params everywhere
|
||||
// LCOV_EXCL_START
|
||||
terResult = view.open() ? TER{telFAILED_PROCESSING}
|
||||
: TER{tecFAILED_PROCESSING};
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2079,7 +2001,7 @@ rippleCreditMPT(
|
||||
view.update(sleIssuance);
|
||||
}
|
||||
else
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2339,7 +2261,7 @@ issueIOU(
|
||||
|
||||
auto const receiverAccount = view.peek(keylet::account(account));
|
||||
if (!receiverAccount)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
return tefINTERNAL;
|
||||
|
||||
bool noRipple = (receiverAccount->getFlags() & lsfDefaultRipple) == 0;
|
||||
|
||||
@@ -2427,13 +2349,11 @@ redeemIOU(
|
||||
// In order to hold an IOU, a trust line *MUST* exist to track the
|
||||
// balance. If it doesn't, then something is very wrong. Don't try
|
||||
// to continue.
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.fatal()) << "redeemIOU: " << to_string(account)
|
||||
<< " attempts to redeem " << amount.getFullText()
|
||||
<< " but no trust line exists!";
|
||||
|
||||
return tefINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
TER
|
||||
@@ -2453,7 +2373,7 @@ transferXRP(
|
||||
SLE::pointer const sender = view.peek(keylet::account(from));
|
||||
SLE::pointer const receiver = view.peek(keylet::account(to));
|
||||
if (!sender || !receiver)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
return tefINTERNAL;
|
||||
|
||||
JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> "
|
||||
<< to_string(to) << ") : " << amount.getFullText();
|
||||
@@ -2463,10 +2383,8 @@ transferXRP(
|
||||
// VFALCO Its unfortunate we have to keep
|
||||
// mutating these TER everywhere
|
||||
// FIXME: this logic should be moved to callers maybe?
|
||||
// LCOV_EXCL_START
|
||||
return view.open() ? TER{telFAILED_PROCESSING}
|
||||
: TER{tecFAILED_PROCESSING};
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
// Decrement XRP balance.
|
||||
@@ -2697,8 +2615,7 @@ enforceMPTokenAuthorization(
|
||||
UNREACHABLE(
|
||||
"ripple::enforceMPTokenAuthorization : condition list is incomplete");
|
||||
return tefINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
TER
|
||||
canTransfer(
|
||||
@@ -2747,13 +2664,11 @@ cleanupOnAccountDelete(
|
||||
if (!sleItem)
|
||||
{
|
||||
// Directory node has an invalid index. Bail out.
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.fatal())
|
||||
<< "DeleteAccount: Directory node in ledger " << view.seq()
|
||||
<< " has index to object that is missing: "
|
||||
<< to_string(dirEntry);
|
||||
return tefBAD_LEDGER;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
LedgerEntryType const nodeType{safe_cast<LedgerEntryType>(
|
||||
@@ -2786,11 +2701,9 @@ cleanupOnAccountDelete(
|
||||
"ripple::cleanupOnAccountDelete : minimum dir entries");
|
||||
if (uDirEntry == 0)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.error())
|
||||
<< "DeleteAccount iterator re-validation failed.";
|
||||
return tefBAD_LEDGER;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
if (skipEntry == SkipEntry::No)
|
||||
uDirEntry--;
|
||||
@@ -2810,7 +2723,7 @@ deleteAMMTrustLine(
|
||||
beast::Journal j)
|
||||
{
|
||||
if (!sleState || sleState->getType() != ltRIPPLE_STATE)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
|
||||
auto const& [low, high] = std::minmax(
|
||||
sleState->getFieldAmount(sfLowLimit).getIssuer(),
|
||||
@@ -2818,14 +2731,13 @@ deleteAMMTrustLine(
|
||||
auto sleLow = view.peek(keylet::account(low));
|
||||
auto sleHigh = view.peek(keylet::account(high));
|
||||
if (!sleLow || !sleHigh)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
return tecINTERNAL;
|
||||
bool const ammLow = sleLow->isFieldPresent(sfAMMID);
|
||||
bool const ammHigh = sleHigh->isFieldPresent(sfAMMID);
|
||||
|
||||
// can't both be AMM
|
||||
if (ammLow && ammHigh)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
|
||||
// at least one must be
|
||||
if (!ammLow && !ammHigh)
|
||||
@@ -2845,7 +2757,7 @@ deleteAMMTrustLine(
|
||||
|
||||
auto const uFlags = !ammLow ? lsfLowReserve : lsfHighReserve;
|
||||
if (!(sleState->getFlags() & uFlags))
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
return tecINTERNAL;
|
||||
|
||||
adjustOwnerCount(view, !ammLow ? sleLow : sleHigh, -1, j);
|
||||
|
||||
@@ -3153,7 +3065,7 @@ rippleUnlockEscrowMPT(
|
||||
{ // LCOV_EXCL_START
|
||||
JLOG(j.error())
|
||||
<< "rippleUnlockEscrowMPT: MPToken not found for " << receiver;
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
return tecOBJECT_NOT_FOUND; // LCOV_EXCL_LINE
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
auto current = sle->getFieldU64(sfMPTAmount);
|
||||
|
||||
@@ -383,7 +383,7 @@ public:
|
||||
static boost::regex reStatus{
|
||||
"\\`HTTP/1\\S+ (\\d{3}) .*\\'"}; // HTTP/1.1 200 OK
|
||||
static boost::regex reSize{
|
||||
"\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'", boost::regex::icase};
|
||||
"\\`.*\\r\\nContent-Length:\\s+([0-9]+).*\\'"};
|
||||
static boost::regex reBody{"\\`.*\\r\\n\\r\\n(.*)\\'"};
|
||||
|
||||
boost::smatch smMatch;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace BuildInfo {
|
||||
// and follow the format described at http://semver.org/
|
||||
//------------------------------------------------------------------------------
|
||||
// clang-format off
|
||||
char const* const versionString = "3.0.0-b1"
|
||||
char const* const versionString = "2.6.0"
|
||||
// clang-format on
|
||||
|
||||
#if defined(DEBUG) || defined(SANITIZER)
|
||||
|
||||
@@ -132,7 +132,7 @@ getBookBase(Book const& book)
|
||||
book.out.account);
|
||||
|
||||
// Return with quality 0.
|
||||
auto k = keylet::quality({ltDIR_NODE, index}, 0);
|
||||
auto k = keylet::quality({index}, 0);
|
||||
|
||||
return k.key;
|
||||
}
|
||||
@@ -180,10 +180,10 @@ makeMptID(std::uint32_t sequence, AccountID const& account)
|
||||
|
||||
namespace keylet {
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltACCOUNT_ROOT>
|
||||
account(AccountID const& id) noexcept
|
||||
{
|
||||
return Keylet{ltACCOUNT_ROOT, indexHash(LedgerNameSpace::ACCOUNT, id)};
|
||||
return TypedKeylet<ltACCOUNT_ROOT>{indexHash(LedgerNameSpace::ACCOUNT, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -192,55 +192,53 @@ child(uint256 const& key) noexcept
|
||||
return {ltCHILD, key};
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
TypedKeylet<ltLEDGER_HASHES> const&
|
||||
skip() noexcept
|
||||
{
|
||||
static Keylet const ret{
|
||||
ltLEDGER_HASHES, indexHash(LedgerNameSpace::SKIP_LIST)};
|
||||
static TypedKeylet<ltLEDGER_HASHES> const ret{
|
||||
indexHash(LedgerNameSpace::SKIP_LIST)};
|
||||
return ret;
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltLEDGER_HASHES>
|
||||
skip(LedgerIndex ledger) noexcept
|
||||
{
|
||||
return {
|
||||
ltLEDGER_HASHES,
|
||||
indexHash(
|
||||
LedgerNameSpace::SKIP_LIST,
|
||||
std::uint32_t(static_cast<std::uint32_t>(ledger) >> 16))};
|
||||
return {indexHash(
|
||||
LedgerNameSpace::SKIP_LIST,
|
||||
std::uint32_t(static_cast<std::uint32_t>(ledger) >> 16))};
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
TypedKeylet<ltAMENDMENTS> const&
|
||||
amendments() noexcept
|
||||
{
|
||||
static Keylet const ret{
|
||||
ltAMENDMENTS, indexHash(LedgerNameSpace::AMENDMENTS)};
|
||||
static TypedKeylet<ltAMENDMENTS> const ret{
|
||||
indexHash(LedgerNameSpace::AMENDMENTS)};
|
||||
return ret;
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
TypedKeylet<ltFEE_SETTINGS> const&
|
||||
fees() noexcept
|
||||
{
|
||||
static Keylet const ret{
|
||||
ltFEE_SETTINGS, indexHash(LedgerNameSpace::FEE_SETTINGS)};
|
||||
static TypedKeylet<ltFEE_SETTINGS> const ret{
|
||||
indexHash(LedgerNameSpace::FEE_SETTINGS)};
|
||||
return ret;
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
TypedKeylet<ltNEGATIVE_UNL> const&
|
||||
negativeUNL() noexcept
|
||||
{
|
||||
static Keylet const ret{
|
||||
ltNEGATIVE_UNL, indexHash(LedgerNameSpace::NEGATIVE_UNL)};
|
||||
static TypedKeylet<ltNEGATIVE_UNL> const ret{
|
||||
indexHash(LedgerNameSpace::NEGATIVE_UNL)};
|
||||
return ret;
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
book_t::operator()(Book const& b) const
|
||||
{
|
||||
return {ltDIR_NODE, getBookBase(b)};
|
||||
return {getBookBase(b)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltRIPPLE_STATE>
|
||||
line(
|
||||
AccountID const& id0,
|
||||
AccountID const& id1,
|
||||
@@ -261,27 +259,22 @@ line(
|
||||
// two accounts (smallest then largest) and hash them in that order:
|
||||
auto const accounts = std::minmax(id0, id1);
|
||||
|
||||
return {
|
||||
ltRIPPLE_STATE,
|
||||
indexHash(
|
||||
LedgerNameSpace::TRUST_LINE,
|
||||
accounts.first,
|
||||
accounts.second,
|
||||
currency)};
|
||||
return {indexHash(
|
||||
LedgerNameSpace::TRUST_LINE,
|
||||
accounts.first,
|
||||
accounts.second,
|
||||
currency)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltOFFER>
|
||||
offer(AccountID const& id, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltOFFER, indexHash(LedgerNameSpace::OFFER, id, seq)};
|
||||
return {indexHash(LedgerNameSpace::OFFER, id, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
quality(Keylet const& k, std::uint64_t q) noexcept
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
quality(TypedKeylet<ltDIR_NODE> const& k, std::uint64_t q) noexcept
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
k.type == ltDIR_NODE, "ripple::keylet::quality : valid input type");
|
||||
|
||||
// Indexes are stored in big endian format: they print as hex as stored.
|
||||
// Most significant bytes are first and the least significant bytes
|
||||
// represent adjacent entries. We place the quality, in big endian format,
|
||||
@@ -292,62 +285,57 @@ quality(Keylet const& k, std::uint64_t q) noexcept
|
||||
// FIXME This is ugly and we can and should do better...
|
||||
((std::uint64_t*)x.end())[-1] = boost::endian::native_to_big(q);
|
||||
|
||||
return {ltDIR_NODE, x};
|
||||
return {x};
|
||||
}
|
||||
|
||||
Keylet
|
||||
next_t::operator()(Keylet const& k) const
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
next_t::operator()(TypedKeylet<ltDIR_NODE> const& k) const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
k.type == ltDIR_NODE,
|
||||
"ripple::keylet::next_t::operator() : valid input type");
|
||||
return {ltDIR_NODE, getQualityNext(k.key)};
|
||||
return {getQualityNext(k.key)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltTICKET>
|
||||
ticket_t::operator()(AccountID const& id, std::uint32_t ticketSeq) const
|
||||
{
|
||||
return {ltTICKET, getTicketIndex(id, ticketSeq)};
|
||||
return {getTicketIndex(id, ticketSeq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltTICKET>
|
||||
ticket_t::operator()(AccountID const& id, SeqProxy ticketSeq) const
|
||||
{
|
||||
return {ltTICKET, getTicketIndex(id, ticketSeq)};
|
||||
return {getTicketIndex(id, ticketSeq)};
|
||||
}
|
||||
|
||||
// This function is presently static, since it's never accessed from anywhere
|
||||
// else. If we ever support multiple pages of signer lists, this would be the
|
||||
// keylet used to locate them.
|
||||
static Keylet
|
||||
static TypedKeylet<ltSIGNER_LIST>
|
||||
signers(AccountID const& account, std::uint32_t page) noexcept
|
||||
{
|
||||
return {
|
||||
ltSIGNER_LIST, indexHash(LedgerNameSpace::SIGNER_LIST, account, page)};
|
||||
return {indexHash(LedgerNameSpace::SIGNER_LIST, account, page)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltSIGNER_LIST>
|
||||
signers(AccountID const& account) noexcept
|
||||
{
|
||||
return signers(account, 0);
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltCHECK>
|
||||
check(AccountID const& id, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltCHECK, indexHash(LedgerNameSpace::CHECK, id, seq)};
|
||||
return TypedKeylet<ltCHECK>{indexHash(LedgerNameSpace::CHECK, id, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDEPOSIT_PREAUTH>
|
||||
depositPreauth(AccountID const& owner, AccountID const& preauthorized) noexcept
|
||||
{
|
||||
return {
|
||||
ltDEPOSIT_PREAUTH,
|
||||
return TypedKeylet<ltDEPOSIT_PREAUTH>{
|
||||
indexHash(LedgerNameSpace::DEPOSIT_PREAUTH, owner, preauthorized)};
|
||||
}
|
||||
|
||||
// Credentials should be sorted here, use credentials::makeSorted
|
||||
Keylet
|
||||
TypedKeylet<ltDEPOSIT_PREAUTH>
|
||||
depositPreauth(
|
||||
AccountID const& owner,
|
||||
std::set<std::pair<AccountID, Slice>> const& authCreds) noexcept
|
||||
@@ -357,8 +345,7 @@ depositPreauth(
|
||||
for (auto const& o : authCreds)
|
||||
hashes.emplace_back(sha512Half(o.first, o.second));
|
||||
|
||||
return {
|
||||
ltDEPOSIT_PREAUTH,
|
||||
return TypedKeylet<ltDEPOSIT_PREAUTH>{
|
||||
indexHash(LedgerNameSpace::DEPOSIT_PREAUTH_CREDENTIALS, owner, hashes)};
|
||||
}
|
||||
|
||||
@@ -367,82 +354,82 @@ depositPreauth(
|
||||
Keylet
|
||||
unchecked(uint256 const& key) noexcept
|
||||
{
|
||||
return {ltANY, key};
|
||||
return Keylet{ltANY, key};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
ownerDir(AccountID const& id) noexcept
|
||||
{
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::OWNER_DIR, id)};
|
||||
return TypedKeylet<ltDIR_NODE>{indexHash(LedgerNameSpace::OWNER_DIR, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
page(uint256 const& key, std::uint64_t index) noexcept
|
||||
{
|
||||
if (index == 0)
|
||||
return {ltDIR_NODE, key};
|
||||
return TypedKeylet<ltDIR_NODE>{key};
|
||||
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::DIR_NODE, key, index)};
|
||||
return TypedKeylet<ltDIR_NODE>{
|
||||
indexHash(LedgerNameSpace::DIR_NODE, key, index)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltESCROW>
|
||||
escrow(AccountID const& src, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltESCROW, indexHash(LedgerNameSpace::ESCROW, src, seq)};
|
||||
return TypedKeylet<ltESCROW>{indexHash(LedgerNameSpace::ESCROW, src, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltPAYCHAN>
|
||||
payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {
|
||||
ltPAYCHAN,
|
||||
return TypedKeylet<ltPAYCHAN>{
|
||||
indexHash(LedgerNameSpace::XRP_PAYMENT_CHANNEL, src, dst, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltNFTOKEN_PAGE>
|
||||
nftpage_min(AccountID const& owner)
|
||||
{
|
||||
std::array<std::uint8_t, 32> buf{};
|
||||
std::memcpy(buf.data(), owner.data(), owner.size());
|
||||
return {ltNFTOKEN_PAGE, uint256{buf}};
|
||||
return TypedKeylet<ltNFTOKEN_PAGE>{uint256{buf}};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltNFTOKEN_PAGE>
|
||||
nftpage_max(AccountID const& owner)
|
||||
{
|
||||
uint256 id = nft::pageMask;
|
||||
std::memcpy(id.data(), owner.data(), owner.size());
|
||||
return {ltNFTOKEN_PAGE, id};
|
||||
return TypedKeylet<ltNFTOKEN_PAGE>{id};
|
||||
}
|
||||
|
||||
Keylet
|
||||
nftpage(Keylet const& k, uint256 const& token)
|
||||
TypedKeylet<ltNFTOKEN_PAGE>
|
||||
nftpage(TypedKeylet<ltNFTOKEN_PAGE> const& k, uint256 const& token)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
k.type == ltNFTOKEN_PAGE, "ripple::keylet::nftpage : valid input type");
|
||||
return {ltNFTOKEN_PAGE, (k.key & ~nft::pageMask) + (token & nft::pageMask)};
|
||||
return {(k.key & ~nft::pageMask) + (token & nft::pageMask)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltNFTOKEN_OFFER>
|
||||
nftoffer(AccountID const& owner, std::uint32_t seq)
|
||||
{
|
||||
return {
|
||||
ltNFTOKEN_OFFER, indexHash(LedgerNameSpace::NFTOKEN_OFFER, owner, seq)};
|
||||
return TypedKeylet<ltNFTOKEN_OFFER>{
|
||||
indexHash(LedgerNameSpace::NFTOKEN_OFFER, owner, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
nft_buys(uint256 const& id) noexcept
|
||||
{
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::NFTOKEN_BUY_OFFERS, id)};
|
||||
return TypedKeylet<ltDIR_NODE>{
|
||||
indexHash(LedgerNameSpace::NFTOKEN_BUY_OFFERS, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDIR_NODE>
|
||||
nft_sells(uint256 const& id) noexcept
|
||||
{
|
||||
return {ltDIR_NODE, indexHash(LedgerNameSpace::NFTOKEN_SELL_OFFERS, id)};
|
||||
return TypedKeylet<ltDIR_NODE>{
|
||||
indexHash(LedgerNameSpace::NFTOKEN_SELL_OFFERS, id)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltAMM>
|
||||
amm(Asset const& issue1, Asset const& issue2) noexcept
|
||||
{
|
||||
auto const& [minI, maxI] =
|
||||
@@ -455,129 +442,120 @@ amm(Asset const& issue1, Asset const& issue2) noexcept
|
||||
maxI.currency));
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltAMM>
|
||||
amm(uint256 const& id) noexcept
|
||||
{
|
||||
return {ltAMM, id};
|
||||
return TypedKeylet<ltAMM>{id};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDELEGATE>
|
||||
delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept
|
||||
{
|
||||
return {
|
||||
ltDELEGATE,
|
||||
return TypedKeylet<ltDELEGATE>{
|
||||
indexHash(LedgerNameSpace::DELEGATE, account, authorizedAccount)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltBRIDGE>
|
||||
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType)
|
||||
{
|
||||
// A door account can support multiple bridges. On the locking chain
|
||||
// there can only be one bridge per lockingChainCurrency. On the issuing
|
||||
// chain there can only be one bridge per issuingChainCurrency.
|
||||
auto const& issue = bridge.issue(chainType);
|
||||
return {
|
||||
ltBRIDGE,
|
||||
indexHash(
|
||||
LedgerNameSpace::BRIDGE, bridge.door(chainType), issue.currency)};
|
||||
return TypedKeylet<ltBRIDGE>{indexHash(
|
||||
LedgerNameSpace::BRIDGE, bridge.door(chainType), issue.currency)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltXCHAIN_OWNED_CLAIM_ID>
|
||||
xChainClaimID(STXChainBridge const& bridge, std::uint64_t seq)
|
||||
{
|
||||
return {
|
||||
ltXCHAIN_OWNED_CLAIM_ID,
|
||||
indexHash(
|
||||
LedgerNameSpace::XCHAIN_CLAIM_ID,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
bridge.issuingChainIssue(),
|
||||
seq)};
|
||||
return TypedKeylet<ltXCHAIN_OWNED_CLAIM_ID>{indexHash(
|
||||
LedgerNameSpace::XCHAIN_CLAIM_ID,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
bridge.issuingChainIssue(),
|
||||
seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID>
|
||||
xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t seq)
|
||||
{
|
||||
return {
|
||||
ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID,
|
||||
indexHash(
|
||||
LedgerNameSpace::XCHAIN_CREATE_ACCOUNT_CLAIM_ID,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
bridge.issuingChainIssue(),
|
||||
seq)};
|
||||
return TypedKeylet<ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID>{indexHash(
|
||||
LedgerNameSpace::XCHAIN_CREATE_ACCOUNT_CLAIM_ID,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
bridge.issuingChainIssue(),
|
||||
seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltDID>
|
||||
did(AccountID const& account) noexcept
|
||||
{
|
||||
return {ltDID, indexHash(LedgerNameSpace::DID, account)};
|
||||
return TypedKeylet<ltDID>{indexHash(LedgerNameSpace::DID, account)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltORACLE>
|
||||
oracle(AccountID const& account, std::uint32_t const& documentID) noexcept
|
||||
{
|
||||
return {ltORACLE, indexHash(LedgerNameSpace::ORACLE, account, documentID)};
|
||||
return TypedKeylet<ltORACLE>{
|
||||
indexHash(LedgerNameSpace::ORACLE, account, documentID)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltMPTOKEN_ISSUANCE>
|
||||
mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept
|
||||
{
|
||||
return mptIssuance(makeMptID(seq, issuer));
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltMPTOKEN_ISSUANCE>
|
||||
mptIssuance(MPTID const& issuanceID) noexcept
|
||||
{
|
||||
return {
|
||||
ltMPTOKEN_ISSUANCE,
|
||||
return TypedKeylet<ltMPTOKEN_ISSUANCE>{
|
||||
indexHash(LedgerNameSpace::MPTOKEN_ISSUANCE, issuanceID)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltMPTOKEN>
|
||||
mptoken(MPTID const& issuanceID, AccountID const& holder) noexcept
|
||||
{
|
||||
return mptoken(mptIssuance(issuanceID).key, holder);
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltMPTOKEN>
|
||||
mptoken(uint256 const& issuanceKey, AccountID const& holder) noexcept
|
||||
{
|
||||
return {
|
||||
ltMPTOKEN, indexHash(LedgerNameSpace::MPTOKEN, issuanceKey, holder)};
|
||||
return TypedKeylet<ltMPTOKEN>{
|
||||
indexHash(LedgerNameSpace::MPTOKEN, issuanceKey, holder)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltCREDENTIAL>
|
||||
credential(
|
||||
AccountID const& subject,
|
||||
AccountID const& issuer,
|
||||
Slice const& credType) noexcept
|
||||
{
|
||||
return {
|
||||
ltCREDENTIAL,
|
||||
return TypedKeylet<ltCREDENTIAL>{
|
||||
indexHash(LedgerNameSpace::CREDENTIAL, subject, issuer, credType)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltVAULT>
|
||||
vault(AccountID const& owner, std::uint32_t seq) noexcept
|
||||
{
|
||||
return vault(indexHash(LedgerNameSpace::VAULT, owner, seq));
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltPERMISSIONED_DOMAIN>
|
||||
permissionedDomain(AccountID const& account, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {
|
||||
ltPERMISSIONED_DOMAIN,
|
||||
return TypedKeylet<ltPERMISSIONED_DOMAIN>{
|
||||
indexHash(LedgerNameSpace::PERMISSIONED_DOMAIN, account, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
TypedKeylet<ltPERMISSIONED_DOMAIN>
|
||||
permissionedDomain(uint256 const& domainID) noexcept
|
||||
{
|
||||
return {ltPERMISSIONED_DOMAIN, domainID};
|
||||
return TypedKeylet<ltPERMISSIONED_DOMAIN>{domainID};
|
||||
}
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
@@ -39,8 +39,20 @@ LedgerFormats::LedgerFormats()
|
||||
#undef UNWRAP
|
||||
#pragma push_macro("LEDGER_ENTRY")
|
||||
#undef LEDGER_ENTRY
|
||||
#pragma push_macro("LEDGER_ENTRY_FIELD")
|
||||
#undef LEDGER_ENTRY_FIELD
|
||||
#pragma push_macro("DEFINE_LEDGER_ENTRY_FIELDS")
|
||||
#undef DEFINE_LEDGER_ENTRY_FIELDS
|
||||
#pragma push_macro("LEDGER_ENTRIES_BEGIN")
|
||||
#undef LEDGER_ENTRIES_BEGIN
|
||||
#pragma push_macro("LEDGER_ENTRIES_END")
|
||||
#undef LEDGER_ENTRIES_END
|
||||
|
||||
#define LEDGER_ENTRIES_BEGIN
|
||||
#define LEDGER_ENTRIES_END
|
||||
#define DEFINE_LEDGER_ENTRY_FIELDS(...) ({__VA_ARGS__})
|
||||
#define UNWRAP(...) __VA_ARGS__
|
||||
#define LEDGER_ENTRY_FIELD(...) {__VA_ARGS__},
|
||||
#define LEDGER_ENTRY(tag, value, name, rpcName, fields) \
|
||||
add(jss::name, tag, UNWRAP fields, commonFields);
|
||||
|
||||
@@ -48,6 +60,14 @@ LedgerFormats::LedgerFormats()
|
||||
|
||||
#undef LEDGER_ENTRY
|
||||
#pragma pop_macro("LEDGER_ENTRY")
|
||||
#undef LEDGER_ENTRY_FIELD
|
||||
#pragma pop_macro("LEDGER_ENTRY_FIELD")
|
||||
#undef DEFINE_LEDGER_ENTRY_FIELDS
|
||||
#pragma pop_macro("DEFINE_LEDGER_ENTRY_FIELDS")
|
||||
#undef LEDGER_ENTRIES_BEGIN
|
||||
#pragma pop_macro("LEDGER_ENTRIES_BEGIN")
|
||||
#undef LEDGER_ENTRIES_END
|
||||
#pragma pop_macro("LEDGER_ENTRIES_END")
|
||||
#undef UNWRAP
|
||||
#pragma pop_macro("UNWRAP")
|
||||
}
|
||||
|
||||
@@ -101,22 +101,6 @@ Permission::getInstance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
Permission::getPermissionName(std::uint32_t const value) const
|
||||
{
|
||||
auto const permissionValue = static_cast<GranularPermissionType>(value);
|
||||
if (auto const granular = getGranularName(permissionValue))
|
||||
return *granular;
|
||||
|
||||
// not a granular permission, check if it maps to a transaction type
|
||||
auto const txType = permissionToTxType(value);
|
||||
if (auto const* item = TxFormats::getInstance().findByType(txType);
|
||||
item != nullptr)
|
||||
return item->getName();
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::uint32_t>
|
||||
Permission::getGranularValue(std::string const& name) const
|
||||
{
|
||||
@@ -147,19 +131,6 @@ Permission::getGranularTxType(GranularPermissionType const& gpType) const
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::reference_wrapper<uint256 const>> const
|
||||
Permission::getTxFeature(TxType txType) const
|
||||
{
|
||||
auto const txFeaturesIt = txFeatureMap_.find(txType);
|
||||
XRPL_ASSERT(
|
||||
txFeaturesIt != txFeatureMap_.end(),
|
||||
"ripple::Permissions::getTxFeature : tx exists in txFeatureMap_");
|
||||
|
||||
if (txFeaturesIt->second == uint256{})
|
||||
return std::nullopt;
|
||||
return txFeaturesIt->second;
|
||||
}
|
||||
|
||||
bool
|
||||
Permission::isDelegatable(
|
||||
std::uint32_t const& permissionValue,
|
||||
@@ -174,22 +145,25 @@ Permission::isDelegatable(
|
||||
auto const txType = permissionToTxType(permissionValue);
|
||||
auto const it = delegatableTx_.find(txType);
|
||||
|
||||
if (it == delegatableTx_.end())
|
||||
return false;
|
||||
if (rules.enabled(fixDelegateV1_1))
|
||||
{
|
||||
if (it == delegatableTx_.end())
|
||||
return false;
|
||||
|
||||
auto const txFeaturesIt = txFeatureMap_.find(txType);
|
||||
XRPL_ASSERT(
|
||||
txFeaturesIt != txFeatureMap_.end(),
|
||||
"ripple::Permissions::isDelegatable : tx exists in txFeatureMap_");
|
||||
auto const txFeaturesIt = txFeatureMap_.find(txType);
|
||||
XRPL_ASSERT(
|
||||
txFeaturesIt != txFeatureMap_.end(),
|
||||
"ripple::Permissions::isDelegatable : tx exists in txFeatureMap_");
|
||||
|
||||
// Delegation is only allowed if the required amendment for the transaction
|
||||
// is enabled. For transactions that do not require an amendment, delegation
|
||||
// is always allowed.
|
||||
if (txFeaturesIt->second != uint256{} &&
|
||||
!rules.enabled(txFeaturesIt->second))
|
||||
return false;
|
||||
// fixDelegateV1_1: Delegation is only allowed if the required amendment
|
||||
// for the transaction is enabled. For transactions that do not require
|
||||
// an amendment, delegation is always allowed.
|
||||
if (txFeaturesIt->second != uint256{} &&
|
||||
!rules.enabled(txFeaturesIt->second))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (it->second == Delegation::notDelegatable)
|
||||
if (it != delegatableTx_.end() && it->second == Delegation::notDelegatable)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
|
||||
#include <map>
|
||||
@@ -28,8 +27,7 @@ namespace ripple {
|
||||
// Storage for static const members.
|
||||
SField::IsSigning const SField::notSigning;
|
||||
int SField::num = 0;
|
||||
std::unordered_map<int, SField const*> SField::knownCodeToField;
|
||||
std::unordered_map<std::string, SField const*> SField::knownNameToField;
|
||||
std::map<int, SField const*> SField::knownCodeToField;
|
||||
|
||||
// Give only this translation unit permission to construct SFields
|
||||
struct SField::private_access_tag_t
|
||||
@@ -47,13 +45,15 @@ TypedField<T>::TypedField(private_access_tag_t pat, Args&&... args)
|
||||
}
|
||||
|
||||
// Construct all compile-time SFields, and register them in the knownCodeToField
|
||||
// and knownNameToField databases:
|
||||
// database:
|
||||
|
||||
// Use macros for most SField construction to enforce naming conventions.
|
||||
#pragma push_macro("UNTYPED_SFIELD")
|
||||
#undef UNTYPED_SFIELD
|
||||
#pragma push_macro("TYPED_SFIELD")
|
||||
#undef TYPED_SFIELD
|
||||
#pragma push_macro("ARRAY_SFIELD")
|
||||
#undef ARRAY_SFIELD
|
||||
|
||||
#define UNTYPED_SFIELD(sfName, stiSuffix, fieldValue, ...) \
|
||||
SField const sfName( \
|
||||
@@ -69,10 +69,17 @@ TypedField<T>::TypedField(private_access_tag_t pat, Args&&... args)
|
||||
fieldValue, \
|
||||
std::string_view(#sfName).substr(2).data(), \
|
||||
##__VA_ARGS__);
|
||||
#define ARRAY_SFIELD(sfName, sfItemName, stiSuffix, fieldValue, ...) \
|
||||
SField const sfName( \
|
||||
access, \
|
||||
STI_##stiSuffix, \
|
||||
fieldValue, \
|
||||
std::string_view(#sfName).substr(2).data(), \
|
||||
##__VA_ARGS__);
|
||||
|
||||
// SFields which, for historical reasons, do not follow naming conventions.
|
||||
SField const sfInvalid(access, -1, "");
|
||||
SField const sfGeneric(access, 0, "Generic");
|
||||
SField const sfInvalid(access, -1);
|
||||
SField const sfGeneric(access, 0);
|
||||
// The following two fields aren't used anywhere, but they break tests/have
|
||||
// downstream effects.
|
||||
SField const sfHash(access, STI_UINT256, 257, "hash");
|
||||
@@ -84,6 +91,8 @@ SField const sfIndex(access, STI_UINT256, 258, "index");
|
||||
#pragma pop_macro("TYPED_SFIELD")
|
||||
#undef UNTYPED_SFIELD
|
||||
#pragma pop_macro("UNTYPED_SFIELD")
|
||||
#undef ARRAY_SFIELD
|
||||
#pragma pop_macro("ARRAY_SFIELD")
|
||||
|
||||
SField::SField(
|
||||
private_access_tag_t,
|
||||
@@ -101,34 +110,19 @@ 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, char const* fn)
|
||||
SField::SField(private_access_tag_t, int fc)
|
||||
: fieldCode(fc)
|
||||
, fieldType(STI_UNKNOWN)
|
||||
, fieldValue(0)
|
||||
, fieldName(fn)
|
||||
, fieldMeta(sMD_Never)
|
||||
, fieldNum(++num)
|
||||
, signingField(IsSigning::yes)
|
||||
, jsonName(fieldName.c_str())
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
!knownCodeToField.contains(fieldCode),
|
||||
"ripple::SField::SField(fc,fn) : fieldCode is unique");
|
||||
XRPL_ASSERT(
|
||||
!knownNameToField.contains(fieldName),
|
||||
"ripple::SField::SField(fc,fn) : fieldName is unique");
|
||||
knownCodeToField[fieldCode] = this;
|
||||
knownNameToField[fieldName] = this;
|
||||
}
|
||||
|
||||
SField const&
|
||||
@@ -162,11 +156,11 @@ SField::compare(SField const& f1, SField const& f2)
|
||||
SField const&
|
||||
SField::getField(std::string const& fieldName)
|
||||
{
|
||||
auto it = knownNameToField.find(fieldName);
|
||||
|
||||
if (it != knownNameToField.end())
|
||||
for (auto const& [_, f] : knownCodeToField)
|
||||
{
|
||||
return *(it->second);
|
||||
(void)_;
|
||||
if (f->fieldName == fieldName)
|
||||
return *f;
|
||||
}
|
||||
return sfInvalid;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,29 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace {
|
||||
|
||||
// Use a static inside a function to help prevent order-of-initialzation issues
|
||||
LocalValue<bool>&
|
||||
getStaticSTAmountCanonicalizeSwitchover()
|
||||
{
|
||||
static LocalValue<bool> r{true};
|
||||
return r;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool
|
||||
getSTAmountCanonicalizeSwitchover()
|
||||
{
|
||||
return *getStaticSTAmountCanonicalizeSwitchover();
|
||||
}
|
||||
|
||||
void
|
||||
setSTAmountCanonicalizeSwitchover(bool v)
|
||||
{
|
||||
*getStaticSTAmountCanonicalizeSwitchover() = v;
|
||||
}
|
||||
|
||||
static std::uint64_t const tenTo14 = 100000000000000ull;
|
||||
static std::uint64_t const tenTo14m1 = tenTo14 - 1;
|
||||
static std::uint64_t const tenTo17 = tenTo14 * 1000;
|
||||
@@ -861,14 +884,18 @@ STAmount::canonicalize()
|
||||
return;
|
||||
}
|
||||
|
||||
// log(cMaxNativeN, 10) == 17
|
||||
if (native() && mOffset > 17)
|
||||
Throw<std::runtime_error>("Native currency amount out of range");
|
||||
// log(maxMPTokenAmount, 10) ~ 18.96
|
||||
if (mAsset.holds<MPTIssue>() && mOffset > 18)
|
||||
Throw<std::runtime_error>("MPT amount out of range");
|
||||
if (getSTAmountCanonicalizeSwitchover())
|
||||
{
|
||||
// log(cMaxNativeN, 10) == 17
|
||||
if (native() && mOffset > 17)
|
||||
Throw<std::runtime_error>(
|
||||
"Native currency amount out of range");
|
||||
// log(maxMPTokenAmount, 10) ~ 18.96
|
||||
if (mAsset.holds<MPTIssue>() && mOffset > 18)
|
||||
Throw<std::runtime_error>("MPT amount out of range");
|
||||
}
|
||||
|
||||
if (getSTNumberSwitchover())
|
||||
if (getSTNumberSwitchover() && getSTAmountCanonicalizeSwitchover())
|
||||
{
|
||||
Number num(
|
||||
mIsNegative ? -mValue : mValue, mOffset, Number::unchecked{});
|
||||
@@ -892,14 +919,16 @@ STAmount::canonicalize()
|
||||
|
||||
while (mOffset > 0)
|
||||
{
|
||||
// N.B. do not move the overflow check to after the
|
||||
// multiplication
|
||||
if (native() && mValue > cMaxNativeN)
|
||||
Throw<std::runtime_error>(
|
||||
"Native currency amount out of range");
|
||||
else if (!native() && mValue > maxMPTokenAmount)
|
||||
Throw<std::runtime_error>("MPT amount out of range");
|
||||
|
||||
if (getSTAmountCanonicalizeSwitchover())
|
||||
{
|
||||
// N.B. do not move the overflow check to after the
|
||||
// multiplication
|
||||
if (native() && mValue > cMaxNativeN)
|
||||
Throw<std::runtime_error>(
|
||||
"Native currency amount out of range");
|
||||
else if (!native() && mValue > maxMPTokenAmount)
|
||||
Throw<std::runtime_error>("MPT amount out of range");
|
||||
}
|
||||
mValue *= 10;
|
||||
--mOffset;
|
||||
}
|
||||
|
||||
@@ -112,9 +112,7 @@ void
|
||||
STBase::add(Serializer& s) const
|
||||
{
|
||||
// Should never be called
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("ripple::STBase::add : not implemented");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -62,10 +62,8 @@ STUInt8::getText() const
|
||||
if (transResultInfo(TER::fromInt(value_), token, human))
|
||||
return human;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
JLOG(debugLog().error())
|
||||
<< "Unknown result code in metadata: " << value_;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return std::to_string(value_);
|
||||
@@ -82,10 +80,8 @@ STUInt8::getJson(JsonOptions) const
|
||||
if (transResultInfo(TER::fromInt(value_), token, human))
|
||||
return token;
|
||||
|
||||
// LCOV_EXCL_START
|
||||
JLOG(debugLog().error())
|
||||
<< "Unknown result code in metadata: " << value_;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return value_;
|
||||
@@ -175,13 +171,6 @@ template <>
|
||||
std::string
|
||||
STUInt32::getText() const
|
||||
{
|
||||
if (getFName() == sfPermissionValue)
|
||||
{
|
||||
auto const permissionName =
|
||||
Permission::getInstance().getPermissionName(value_);
|
||||
if (permissionName)
|
||||
return *permissionName;
|
||||
}
|
||||
return std::to_string(value_);
|
||||
}
|
||||
|
||||
@@ -191,10 +180,23 @@ STUInt32::getJson(JsonOptions) const
|
||||
{
|
||||
if (getFName() == sfPermissionValue)
|
||||
{
|
||||
auto const permissionName =
|
||||
Permission::getInstance().getPermissionName(value_);
|
||||
if (permissionName)
|
||||
return *permissionName;
|
||||
auto const permissionValue =
|
||||
static_cast<GranularPermissionType>(value_);
|
||||
auto const granular =
|
||||
Permission::getInstance().getGranularName(permissionValue);
|
||||
|
||||
if (granular)
|
||||
{
|
||||
return *granular;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const txType =
|
||||
Permission::getInstance().permissionToTxType(value_);
|
||||
auto item = TxFormats::getInstance().findByType(txType);
|
||||
if (item != nullptr)
|
||||
return item->getName();
|
||||
}
|
||||
}
|
||||
|
||||
return value_;
|
||||
@@ -249,33 +251,4 @@ STUInt64::getJson(JsonOptions) const
|
||||
return convertToString(value_, 16); // Convert to base 16
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <>
|
||||
STInteger<std::int32_t>::STInteger(SerialIter& sit, SField const& name)
|
||||
: STInteger(name, sit.get32())
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STInt32::getSType() const
|
||||
{
|
||||
return STI_INT32;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
STInt32::getText() const
|
||||
{
|
||||
return std::to_string(value_);
|
||||
}
|
||||
|
||||
template <>
|
||||
Json::Value
|
||||
STInt32::getJson(JsonOptions) const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -647,12 +647,6 @@ STObject::getFieldH256(SField const& field) const
|
||||
return getFieldByValue<STUInt256>(field);
|
||||
}
|
||||
|
||||
std::int32_t
|
||||
STObject::getFieldI32(SField const& field) const
|
||||
{
|
||||
return getFieldByValue<STInt32>(field);
|
||||
}
|
||||
|
||||
AccountID
|
||||
STObject::getAccountID(SField const& field) const
|
||||
{
|
||||
@@ -688,16 +682,6 @@ STObject::getFieldV256(SField const& field) const
|
||||
return getFieldByConstRef<STVector256>(field, empty);
|
||||
}
|
||||
|
||||
STObject
|
||||
STObject::getFieldObject(SField const& field) const
|
||||
{
|
||||
STObject const empty{field};
|
||||
auto ret = getFieldByConstRef<STObject>(field, empty);
|
||||
if (ret != empty)
|
||||
ret.applyTemplateFromSField(field);
|
||||
return ret;
|
||||
}
|
||||
|
||||
STArray const&
|
||||
STObject::getFieldArray(SField const& field) const
|
||||
{
|
||||
@@ -777,12 +761,6 @@ STObject::setFieldH256(SField const& field, uint256 const& v)
|
||||
setFieldUsingSetValue<STUInt256>(field, v);
|
||||
}
|
||||
|
||||
void
|
||||
STObject::setFieldI32(SField const& field, std::int32_t v)
|
||||
{
|
||||
setFieldUsingSetValue<STInt32>(field, v);
|
||||
}
|
||||
|
||||
void
|
||||
STObject::setFieldV256(SField const& field, STVector256 const& v)
|
||||
{
|
||||
@@ -843,12 +821,6 @@ STObject::setFieldArray(SField const& field, STArray const& v)
|
||||
setFieldUsingAssignment(field, v);
|
||||
}
|
||||
|
||||
void
|
||||
STObject::setFieldObject(SField const& field, STObject const& v)
|
||||
{
|
||||
setFieldUsingAssignment(field, v);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
STObject::getJson(JsonOptions options) const
|
||||
{
|
||||
|
||||
@@ -83,8 +83,7 @@ constexpr std::
|
||||
return static_cast<U1>(value);
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
static inline std::string
|
||||
static std::string
|
||||
make_name(std::string const& object, std::string const& field)
|
||||
{
|
||||
if (field.empty())
|
||||
@@ -93,7 +92,7 @@ make_name(std::string const& object, std::string const& field)
|
||||
return object + "." + field;
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
not_an_object(std::string const& object, std::string const& field)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -101,20 +100,20 @@ not_an_object(std::string const& object, std::string const& field)
|
||||
"Field '" + make_name(object, field) + "' is not a JSON object.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
not_an_object(std::string const& object)
|
||||
{
|
||||
return not_an_object(object, "");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
not_an_array(std::string const& object)
|
||||
{
|
||||
return RPC::make_error(
|
||||
rpcINVALID_PARAMS, "Field '" + object + "' is not a JSON array.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
unknown_field(std::string const& object, std::string const& field)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -122,7 +121,7 @@ unknown_field(std::string const& object, std::string const& field)
|
||||
"Field '" + make_name(object, field) + "' is unknown.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
out_of_range(std::string const& object, std::string const& field)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -130,7 +129,7 @@ out_of_range(std::string const& object, std::string const& field)
|
||||
"Field '" + make_name(object, field) + "' is out of range.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
bad_type(std::string const& object, std::string const& field)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -138,7 +137,7 @@ bad_type(std::string const& object, std::string const& field)
|
||||
"Field '" + make_name(object, field) + "' has bad type.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
invalid_data(std::string const& object, std::string const& field)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -146,13 +145,13 @@ invalid_data(std::string const& object, std::string const& field)
|
||||
"Field '" + make_name(object, field) + "' has invalid data.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
invalid_data(std::string const& object)
|
||||
{
|
||||
return invalid_data(object, "");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
array_expected(std::string const& object, std::string const& field)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -160,7 +159,7 @@ array_expected(std::string const& object, std::string const& field)
|
||||
"Field '" + make_name(object, field) + "' must be a JSON array.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
string_expected(std::string const& object, std::string const& field)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -168,7 +167,7 @@ string_expected(std::string const& object, std::string const& field)
|
||||
"Field '" + make_name(object, field) + "' must be a string.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
too_deep(std::string const& object)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -176,7 +175,7 @@ too_deep(std::string const& object)
|
||||
"Field '" + object + "' exceeds nesting depth limit.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
singleton_expected(std::string const& object, unsigned int index)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -185,7 +184,7 @@ singleton_expected(std::string const& object, unsigned int index)
|
||||
"]' must be an object with a single key/object value.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
template_mismatch(SField const& sField)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -194,7 +193,7 @@ template_mismatch(SField const& sField)
|
||||
"' contents did not meet requirements for that type.");
|
||||
}
|
||||
|
||||
static inline Json::Value
|
||||
static Json::Value
|
||||
non_object_in_array(std::string const& item, Json::UInt index)
|
||||
{
|
||||
return RPC::make_error(
|
||||
@@ -202,176 +201,6 @@ non_object_in_array(std::string const& item, Json::UInt index)
|
||||
"Item '" + item + "' at index " + std::to_string(index) +
|
||||
" is not an object. Arrays may only contain objects.");
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
template <class STResult, class Integer>
|
||||
static std::optional<detail::STVar>
|
||||
parseUnsigned(
|
||||
SField const& field,
|
||||
std::string const& json_name,
|
||||
std::string const& fieldName,
|
||||
SField const* name,
|
||||
Json::Value const& value,
|
||||
Json::Value& error)
|
||||
{
|
||||
std::optional<detail::STVar> ret;
|
||||
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
safe_cast<typename STResult::value_type>(
|
||||
beast::lexicalCastThrow<Integer>(value.asString())));
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
to_unsigned<typename STResult::value_type>(value.asInt()));
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
to_unsigned<typename STResult::value_type>(value.asUInt()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class STResult, class Integer = std::uint16_t>
|
||||
static std::optional<detail::STVar>
|
||||
parseUint16(
|
||||
SField const& field,
|
||||
std::string const& json_name,
|
||||
std::string const& fieldName,
|
||||
SField const* name,
|
||||
Json::Value const& value,
|
||||
Json::Value& error)
|
||||
{
|
||||
std::optional<detail::STVar> ret;
|
||||
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
std::string const strValue = value.asString();
|
||||
|
||||
if (!strValue.empty() &&
|
||||
((strValue[0] < '0') || (strValue[0] > '9')))
|
||||
{
|
||||
if (field == sfTransactionType)
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
safe_cast<typename STResult::value_type>(
|
||||
static_cast<Integer>(
|
||||
TxFormats::getInstance().findTypeByName(
|
||||
strValue))));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfTransaction;
|
||||
}
|
||||
else if (field == sfLedgerEntryType)
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
safe_cast<typename STResult::value_type>(
|
||||
static_cast<Integer>(
|
||||
LedgerFormats::getInstance().findTypeByName(
|
||||
strValue))));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfLedgerEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
return parseUnsigned<STResult, Integer>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class STResult, class Integer = std::uint32_t>
|
||||
static std::optional<detail::STVar>
|
||||
parseUint32(
|
||||
SField const& field,
|
||||
std::string const& json_name,
|
||||
std::string const& fieldName,
|
||||
SField const* name,
|
||||
Json::Value const& value,
|
||||
Json::Value& error)
|
||||
{
|
||||
std::optional<detail::STVar> ret;
|
||||
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
if (field == sfPermissionValue)
|
||||
{
|
||||
std::string const strValue = value.asString();
|
||||
auto const granularPermission =
|
||||
Permission::getInstance().getGranularValue(strValue);
|
||||
if (granularPermission)
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field, *granularPermission);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const& txType =
|
||||
TxFormats::getInstance().findTypeByName(strValue);
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
Permission::getInstance().txToPermissionType(txType));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = detail::make_stvar<STResult>(
|
||||
field,
|
||||
safe_cast<typename STResult::value_type>(
|
||||
beast::lexicalCastThrow<Integer>(value.asString())));
|
||||
}
|
||||
}
|
||||
if (!ret)
|
||||
return parseUnsigned<STResult, Integer>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This function is used by parseObject to parse any JSON type that doesn't
|
||||
// recurse. Everything represented here is a leaf-type.
|
||||
@@ -387,13 +216,10 @@ parseLeaf(
|
||||
|
||||
auto const& field = SField::getField(fieldName);
|
||||
|
||||
// checked in parseObject
|
||||
if (field == sfInvalid)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
error = unknown_field(json_name, fieldName);
|
||||
return ret;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
switch (field.fieldType)
|
||||
@@ -476,18 +302,130 @@ parseLeaf(
|
||||
break;
|
||||
|
||||
case STI_UINT16:
|
||||
ret = parseUint16<STUInt16>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
if (!ret)
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
std::string const strValue = value.asString();
|
||||
|
||||
if (!strValue.empty() &&
|
||||
((strValue[0] < '0') || (strValue[0] > '9')))
|
||||
{
|
||||
if (field == sfTransactionType)
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field,
|
||||
static_cast<std::uint16_t>(
|
||||
TxFormats::getInstance().findTypeByName(
|
||||
strValue)));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfTransaction;
|
||||
}
|
||||
else if (field == sfLedgerEntryType)
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field,
|
||||
static_cast<std::uint16_t>(
|
||||
LedgerFormats::getInstance().findTypeByName(
|
||||
strValue)));
|
||||
|
||||
if (*name == sfGeneric)
|
||||
name = &sfLedgerEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field,
|
||||
beast::lexicalCastThrow<std::uint16_t>(strValue));
|
||||
}
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field, to_unsigned<std::uint16_t>(value.asInt()));
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt16>(
|
||||
field, to_unsigned<std::uint16_t>(value.asUInt()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_UINT32:
|
||||
ret = parseUint32<STUInt32>(
|
||||
field, json_name, fieldName, name, value, error);
|
||||
if (!ret)
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
if (field == sfPermissionValue)
|
||||
{
|
||||
std::string const strValue = value.asString();
|
||||
auto const granularPermission =
|
||||
Permission::getInstance().getGranularValue(
|
||||
strValue);
|
||||
if (granularPermission)
|
||||
{
|
||||
ret = detail::make_stvar<STUInt32>(
|
||||
field, *granularPermission);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const& txType =
|
||||
TxFormats::getInstance().findTypeByName(
|
||||
strValue);
|
||||
ret = detail::make_stvar<STUInt32>(
|
||||
field,
|
||||
Permission::getInstance().txToPermissionType(
|
||||
txType));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = detail::make_stvar<STUInt32>(
|
||||
field,
|
||||
beast::lexicalCastThrow<std::uint32_t>(
|
||||
value.asString()));
|
||||
}
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt32>(
|
||||
field, to_unsigned<std::uint32_t>(value.asInt()));
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
ret = detail::make_stvar<STUInt32>(
|
||||
field, safe_cast<std::uint32_t>(value.asUInt()));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -563,30 +501,6 @@ parseLeaf(
|
||||
break;
|
||||
}
|
||||
|
||||
case STI_UINT160: {
|
||||
if (!value.isString())
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint160 num;
|
||||
|
||||
if (auto const s = value.asString(); !num.parseHex(s))
|
||||
{
|
||||
if (!s.empty())
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
num.zero();
|
||||
}
|
||||
|
||||
ret = detail::make_stvar<STUInt160>(field, num);
|
||||
break;
|
||||
}
|
||||
|
||||
case STI_UINT192: {
|
||||
if (!value.isString())
|
||||
{
|
||||
@@ -611,6 +525,30 @@ parseLeaf(
|
||||
break;
|
||||
}
|
||||
|
||||
case STI_UINT160: {
|
||||
if (!value.isString())
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint160 num;
|
||||
|
||||
if (auto const s = value.asString(); !num.parseHex(s))
|
||||
{
|
||||
if (!s.empty())
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
num.zero();
|
||||
}
|
||||
|
||||
ret = detail::make_stvar<STUInt160>(field, num);
|
||||
break;
|
||||
}
|
||||
|
||||
case STI_UINT256: {
|
||||
if (!value.isString())
|
||||
{
|
||||
@@ -635,52 +573,6 @@ parseLeaf(
|
||||
break;
|
||||
}
|
||||
|
||||
case STI_INT32:
|
||||
try
|
||||
{
|
||||
if (value.isString())
|
||||
{
|
||||
ret = detail::make_stvar<STInt32>(
|
||||
field,
|
||||
beast::lexicalCastThrow<std::int32_t>(
|
||||
value.asString()));
|
||||
}
|
||||
else if (value.isInt())
|
||||
{
|
||||
// future-proofing - a static assert failure if the JSON
|
||||
// library ever supports larger ints
|
||||
// In such case, we will need additional bounds checks here
|
||||
static_assert(
|
||||
std::is_same_v<decltype(value.asInt()), std::int32_t>);
|
||||
ret = detail::make_stvar<STInt32>(field, value.asInt());
|
||||
}
|
||||
else if (value.isUInt())
|
||||
{
|
||||
auto const uintValue = value.asUInt();
|
||||
if (uintValue >
|
||||
static_cast<std::uint32_t>(
|
||||
std::numeric_limits<std::int32_t>::max()))
|
||||
{
|
||||
error = out_of_range(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
ret = detail::make_stvar<STInt32>(
|
||||
field, static_cast<std::int32_t>(uintValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
error = bad_type(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalid_data(json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STI_VL:
|
||||
if (!value.isString())
|
||||
{
|
||||
@@ -811,12 +703,6 @@ parseLeaf(
|
||||
AccountID uAccount, uIssuer;
|
||||
Currency uCurrency;
|
||||
|
||||
if (!account && !currency && !issuer)
|
||||
{
|
||||
error = invalid_data(element_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (account)
|
||||
{
|
||||
// human account id
|
||||
@@ -1166,7 +1052,8 @@ parseArray(
|
||||
Json::Value const objectFields(json[i][objectName]);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << json_name << "." << "[" << i << "]." << objectName;
|
||||
ss << json_name << "."
|
||||
<< "[" << i << "]." << objectName;
|
||||
|
||||
auto ret = parseObject(
|
||||
ss.str(), objectFields, nameField, depth + 1, error);
|
||||
@@ -1209,4 +1096,24 @@ STParsedJSONObject::STParsedJSONObject(
|
||||
object = parseObject(name, json, sfGeneric, 0, error);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STParsedJSONArray::STParsedJSONArray(
|
||||
std::string const& name,
|
||||
Json::Value const& json)
|
||||
{
|
||||
using namespace STParsedJSONDetail;
|
||||
auto arr = parseArray(name, json, sfGeneric, 0, error);
|
||||
if (!arr)
|
||||
array.reset();
|
||||
else
|
||||
{
|
||||
auto p = dynamic_cast<STArray*>(&arr->get());
|
||||
if (p == nullptr)
|
||||
array.reset();
|
||||
else
|
||||
array = std::move(*p);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user