mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 19:25:51 +00:00
Compare commits
32 Commits
pratik/Rem
...
Bronek/Int
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55d5655ff3 | ||
|
|
25c5e3b17f | ||
|
|
8eb233c2ea | ||
|
|
50fc93f742 | ||
|
|
ab45a8a737 | ||
|
|
dfafb141cc | ||
|
|
4e32d2ed98 | ||
|
|
fa69918124 | ||
|
|
cbbb2b1be0 | ||
|
|
cf2d763fa1 | ||
|
|
2dd1d682ac | ||
|
|
4cb1084c02 | ||
|
|
8d1b3b3994 | ||
|
|
b39d7a6519 | ||
|
|
b0910e359e | ||
|
|
44e027e516 | ||
|
|
a10f42a3aa | ||
|
|
efd4c1b95d | ||
|
|
f8b4f692f1 | ||
|
|
80a3ae6386 | ||
|
|
48d38c1e2c | ||
|
|
553fb5be3b | ||
|
|
efa917d9f3 | ||
|
|
bd3bc917f8 | ||
|
|
ed5d6f3e22 | ||
|
|
a8e4da0b11 | ||
|
|
1dd60242de | ||
|
|
76611c3f46 | ||
|
|
5efaf0c328 | ||
|
|
0aa23933ea | ||
|
|
21f3c12d85 | ||
|
|
7d5ed0cd8d |
19
.github/actions/build-deps/action.yml
vendored
19
.github/actions/build-deps/action.yml
vendored
@@ -4,20 +4,23 @@ description: "Install Conan dependencies, optionally forcing a rebuild of all de
|
||||
# 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:
|
||||
verbosity:
|
||||
description: "The build verbosity."
|
||||
required: false
|
||||
default: "verbose"
|
||||
build_dir:
|
||||
description: "The directory where to build."
|
||||
required: true
|
||||
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
|
||||
@@ -26,9 +29,10 @@ runs:
|
||||
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 }}
|
||||
VERBOSITY: ${{ inputs.verbosity }}
|
||||
LOG_VERBOSITY: ${{ inputs.log_verbosity }}
|
||||
run: |
|
||||
echo 'Installing dependencies.'
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
@@ -39,6 +43,7 @@ runs:
|
||||
--options:host='&:tests=True' \
|
||||
--options:host='&:xrpld=True' \
|
||||
--settings:all build_type="${BUILD_TYPE}" \
|
||||
--conf:all tools.build:verbosity="${VERBOSITY}" \
|
||||
--conf:all tools.compilation:verbosity="${VERBOSITY}" \
|
||||
--conf:all tools.build:jobs=${BUILD_NPROC} \
|
||||
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
|
||||
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
|
||||
..
|
||||
|
||||
@@ -17,7 +17,7 @@ Loop: xrpld.app xrpld.rpc
|
||||
xrpld.rpc > xrpld.app
|
||||
|
||||
Loop: xrpld.app xrpld.shamap
|
||||
xrpld.app > xrpld.shamap
|
||||
xrpld.shamap ~= xrpld.app
|
||||
|
||||
Loop: xrpld.core xrpld.perflog
|
||||
xrpld.perflog == xrpld.core
|
||||
|
||||
@@ -8,6 +8,10 @@ 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
|
||||
@@ -18,6 +22,9 @@ 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
|
||||
@@ -25,11 +32,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
|
||||
@@ -86,8 +93,7 @@ test.nodestore > test.toplevel
|
||||
test.nodestore > test.unit_test
|
||||
test.nodestore > xrpl.basics
|
||||
test.nodestore > xrpld.core
|
||||
test.nodestore > xrpld.nodestore
|
||||
test.nodestore > xrpld.unity
|
||||
test.nodestore > xrpl.nodestore
|
||||
test.overlay > test.jtx
|
||||
test.overlay > test.toplevel
|
||||
test.overlay > test.unit_test
|
||||
@@ -95,8 +101,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
|
||||
@@ -131,9 +137,9 @@ test.server > xrpl.json
|
||||
test.server > xrpl.server
|
||||
test.shamap > test.unit_test
|
||||
test.shamap > xrpl.basics
|
||||
test.shamap > xrpld.nodestore
|
||||
test.shamap > xrpld.shamap
|
||||
test.shamap > xrpl.nodestore
|
||||
test.shamap > xrpl.protocol
|
||||
test.shamap > xrpl.shamap
|
||||
test.toplevel > test.csf
|
||||
test.toplevel > xrpl.json
|
||||
test.unit_test > xrpl.basics
|
||||
@@ -144,6 +150,8 @@ 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
|
||||
@@ -152,17 +160,21 @@ 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
|
||||
@@ -172,11 +184,6 @@ 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
|
||||
@@ -192,13 +199,11 @@ 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.basics
|
||||
xrpld.shamap > xrpld.nodestore
|
||||
xrpld.shamap > xrpl.protocol
|
||||
xrpld.shamap > xrpl.shamap
|
||||
|
||||
7
.github/workflows/on-trigger.yml
vendored
7
.github/workflows/on-trigger.yml
vendored
@@ -50,7 +50,12 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
# 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 }}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
|
||||
14
.github/workflows/publish-docs.yml
vendored
14
.github/workflows/publish-docs.yml
vendored
@@ -23,6 +23,7 @@ defaults:
|
||||
|
||||
env:
|
||||
BUILD_DIR: .build
|
||||
NPROC_SUBTRACT: 2
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
@@ -33,6 +34,13 @@ jobs:
|
||||
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.'
|
||||
@@ -46,12 +54,16 @@ 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}"
|
||||
cmake -Donly_docs=ON ..
|
||||
cmake --build . --target docs --parallel $(nproc)
|
||||
cmake --build . --target docs --parallel ${BUILD_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
|
||||
|
||||
@@ -39,6 +39,12 @@ on:
|
||||
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."
|
||||
@@ -55,6 +61,7 @@ jobs:
|
||||
runs_on: ${{ inputs.runs_on }}
|
||||
image: ${{ inputs.image }}
|
||||
config_name: ${{ inputs.config_name }}
|
||||
nproc_subtract: ${{ inputs.nproc_subtract }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -67,3 +74,4 @@ jobs:
|
||||
runs_on: ${{ inputs.runs_on }}
|
||||
image: ${{ inputs.image }}
|
||||
config_name: ${{ inputs.config_name }}
|
||||
nproc_subtract: ${{ inputs.nproc_subtract }}
|
||||
|
||||
22
.github/workflows/reusable-build.yml
vendored
22
.github/workflows/reusable-build.yml
vendored
@@ -34,6 +34,11 @@ on:
|
||||
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."
|
||||
@@ -58,13 +63,19 @@ jobs:
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@638e0dc11ea230f91bd26622fb542116bb5254d5
|
||||
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
|
||||
|
||||
@@ -72,7 +83,11 @@ jobs:
|
||||
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
|
||||
@@ -92,13 +107,14 @@ jobs:
|
||||
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 $(nproc) \
|
||||
--parallel ${BUILD_NPROC} \
|
||||
--target "${CMAKE_TARGET}"
|
||||
|
||||
- name: Put built binaries in one location
|
||||
@@ -126,7 +142,7 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ inputs.cmake_target == 'coverage' }}
|
||||
if: ${{ github.repository_owner == 'XRPLF' && inputs.cmake_target == 'coverage' }}
|
||||
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
|
||||
with:
|
||||
disable_search: true
|
||||
|
||||
24
.github/workflows/reusable-test.yml
vendored
24
.github/workflows/reusable-test.yml
vendored
@@ -26,6 +26,11 @@ on:
|
||||
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 }}
|
||||
@@ -37,6 +42,12 @@ jobs:
|
||||
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:
|
||||
@@ -69,8 +80,10 @@ jobs:
|
||||
- name: Run the embedded tests
|
||||
if: ${{ inputs.run_tests }}
|
||||
shell: bash
|
||||
env:
|
||||
BUILD_NPROC: ${{ steps.nproc.outputs.nproc }}
|
||||
run: |
|
||||
./rippled --unittest --unittest-jobs $(nproc)
|
||||
./rippled --unittest --unittest-jobs ${BUILD_NPROC}
|
||||
|
||||
- name: Run the separate tests
|
||||
if: ${{ inputs.run_tests }}
|
||||
@@ -87,3 +100,12 @@ jobs:
|
||||
"$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
|
||||
|
||||
27
.github/workflows/upload-conan-deps.yml
vendored
27
.github/workflows/upload-conan-deps.yml
vendored
@@ -34,6 +34,7 @@ on:
|
||||
env:
|
||||
CONAN_REMOTE_NAME: xrplf
|
||||
CONAN_REMOTE_URL: https://conan.ripplex.io
|
||||
NPROC_SUBTRACT: 2
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -61,12 +62,23 @@ jobs:
|
||||
if: ${{ runner.os == 'macOS' }}
|
||||
uses: XRPLF/actions/.github/actions/cleanup-workspace@3f044c7478548e3c32ff68980eeb36ece02b364e
|
||||
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/.github/actions/prepare-runner@638e0dc11ea230f91bd26622fb542116bb5254d5
|
||||
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: ${{ env.NPROC_SUBTRACT }}
|
||||
|
||||
- name: Setup Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
with:
|
||||
@@ -77,18 +89,19 @@ 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' }}
|
||||
# The verbosity is set to "quiet" for Windows to avoid an excessive amount of logs, while it
|
||||
# is set to "verbose" otherwise to provide more information during the build process.
|
||||
verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
|
||||
# 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 != 'pull_request' }}
|
||||
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 }}"
|
||||
|
||||
- name: Upload Conan packages
|
||||
if: ${{ github.repository_owner == 'XRPLF' && github.event_name != 'pull_request' && github.event_name != 'schedule' }}
|
||||
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}
|
||||
|
||||
@@ -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 1.1.1 REQUIRED)
|
||||
find_dependency (OpenSSL REQUIRED)
|
||||
find_dependency (ZLIB)
|
||||
find_dependency (date)
|
||||
if (TARGET ZLIB::ZLIB)
|
||||
|
||||
@@ -53,14 +53,15 @@ add_library(xrpl.imports.main INTERFACE)
|
||||
|
||||
target_link_libraries(xrpl.imports.main
|
||||
INTERFACE
|
||||
LibArchive::LibArchive
|
||||
OpenSSL::Crypto
|
||||
Ripple::boost
|
||||
Ripple::opts
|
||||
Ripple::syslibs
|
||||
absl::random_random
|
||||
date::date
|
||||
ed25519::ed25519
|
||||
LibArchive::LibArchive
|
||||
OpenSSL::Crypto
|
||||
Ripple::boost
|
||||
Ripple::libs
|
||||
Ripple::opts
|
||||
Ripple::syslibs
|
||||
secp256k1::secp256k1
|
||||
xrpl.libpb
|
||||
xxHash::xxhash
|
||||
@@ -111,6 +112,21 @@ 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
|
||||
@@ -136,6 +152,8 @@ target_link_modules(xrpl PUBLIC
|
||||
protocol
|
||||
resource
|
||||
server
|
||||
nodestore
|
||||
shamap
|
||||
net
|
||||
ledger
|
||||
)
|
||||
|
||||
@@ -8,20 +8,23 @@ install (
|
||||
TARGETS
|
||||
common
|
||||
opts
|
||||
ripple_syslibs
|
||||
ripple_boost
|
||||
ripple_libs
|
||||
ripple_syslibs
|
||||
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.net
|
||||
xrpl.libxrpl
|
||||
xrpl.libxrpl.shamap
|
||||
antithesis-sdk-cpp
|
||||
EXPORT RippleExports
|
||||
LIBRARY DESTINATION lib
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Global configuration for Conan. This is used to set the number of parallel
|
||||
# downloads, uploads, and build jobs.
|
||||
# downloads and uploads.
|
||||
core:non_interactive=True
|
||||
core.download:parallel={{ os.cpu_count() }}
|
||||
core.upload:parallel={{ os.cpu_count() }}
|
||||
tools.build:jobs={{ os.cpu_count() - 1 }}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_NODESTORE_BACKEND_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_BACKEND_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Types.h>
|
||||
#include <xrpl/nodestore/Types.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -20,13 +20,12 @@
|
||||
#ifndef RIPPLE_NODESTORE_DATABASE_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_DATABASE_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Backend.h>
|
||||
#include <xrpld/nodestore/NodeObject.h>
|
||||
#include <xrpld/nodestore/Scheduler.h>
|
||||
|
||||
#include <xrpl/basics/BasicConfig.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/TaggedCache.ipp>
|
||||
#include <xrpl/nodestore/Backend.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
#include <xrpl/nodestore/Scheduler.h>
|
||||
#include <xrpl/protocol/SystemParameters.h>
|
||||
|
||||
#include <condition_variable>
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_DATABASEROTATING_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Database.h>
|
||||
#include <xrpl/nodestore/Database.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_DUMMYSCHEDULER_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Scheduler.h>
|
||||
#include <xrpl/nodestore/Scheduler.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -20,11 +20,10 @@
|
||||
#ifndef RIPPLE_NODESTORE_FACTORY_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_FACTORY_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Backend.h>
|
||||
#include <xrpld/nodestore/Scheduler.h>
|
||||
|
||||
#include <xrpl/basics/BasicConfig.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/nodestore/Backend.h>
|
||||
#include <xrpl/nodestore/Scheduler.h>
|
||||
|
||||
#include <nudb/store.hpp>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef RIPPLE_NODESTORE_MANAGER_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_MANAGER_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/DatabaseRotating.h>
|
||||
#include <xrpld/nodestore/Factory.h>
|
||||
#include <xrpl/nodestore/DatabaseRotating.h>
|
||||
#include <xrpl/nodestore/Factory.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_SCHEDULER_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Task.h>
|
||||
#include <xrpl/nodestore/Task.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_NODESTORE_TYPES_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_TYPES_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/NodeObject.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
#ifndef RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_BATCHWRITER_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Scheduler.h>
|
||||
#include <xrpld/nodestore/Task.h>
|
||||
#include <xrpld/nodestore/Types.h>
|
||||
#include <xrpl/nodestore/Scheduler.h>
|
||||
#include <xrpl/nodestore/Task.h>
|
||||
#include <xrpl/nodestore/Types.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
@@ -20,10 +20,9 @@
|
||||
#ifndef RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_DATABASENODEIMP_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Database.h>
|
||||
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/nodestore/Database.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_DATABASEROTATINGIMP_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/DatabaseRotating.h>
|
||||
#include <xrpl/nodestore/DatabaseRotating.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_DECODEDBLOB_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/NodeObject.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -20,9 +20,8 @@
|
||||
#ifndef RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_ENCODEDBLOB_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/NodeObject.h>
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
|
||||
#include <boost/align/align_up.hpp>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED
|
||||
#define RIPPLE_NODESTORE_MANAGERIMP_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Manager.h>
|
||||
#include <xrpl/nodestore/Manager.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
static void
|
||||
missing_backend();
|
||||
|
||||
ManagerImp() = default;
|
||||
ManagerImp();
|
||||
|
||||
~ManagerImp() = default;
|
||||
|
||||
@@ -23,11 +23,10 @@
|
||||
// Disable lz4 deprecation warning due to incompatibility with clang attributes
|
||||
#define LZ4_DISABLE_DEPRECATE_WARNINGS
|
||||
|
||||
#include <xrpld/nodestore/NodeObject.h>
|
||||
#include <xrpld/nodestore/detail/varint.h>
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
#include <xrpl/nodestore/detail/varint.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
|
||||
#include <nudb/detail/field.hpp>
|
||||
@@ -55,7 +55,10 @@ 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 */
|
||||
/** The maximum number of pages allowed in a directory
|
||||
|
||||
Made obsolete by fixDirectoryLimit amendment.
|
||||
*/
|
||||
std::uint64_t constexpr dirNodeMaxPages = 262144;
|
||||
|
||||
/** The maximum number of items in an NFT page */
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#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>
|
||||
@@ -264,6 +265,24 @@ 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
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -709,37 +709,6 @@ 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
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -244,6 +244,9 @@ 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&
|
||||
@@ -390,6 +393,8 @@ 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
|
||||
|
||||
@@ -87,8 +87,14 @@ public:
|
||||
getFullText() const override;
|
||||
|
||||
// Outer transaction functions / signature functions.
|
||||
static Blob
|
||||
getSignature(STObject const& sigObject);
|
||||
|
||||
Blob
|
||||
getSignature() const;
|
||||
getSignature() const
|
||||
{
|
||||
return getSignature(*this);
|
||||
}
|
||||
|
||||
uint256
|
||||
getSigningHash() const;
|
||||
@@ -119,13 +125,20 @@ public:
|
||||
getJson(JsonOptions options, bool binary) const;
|
||||
|
||||
void
|
||||
sign(PublicKey const& publicKey, SecretKey const& secretKey);
|
||||
sign(
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
std::optional<std::reference_wrapper<SField const>> signatureTarget =
|
||||
{});
|
||||
|
||||
/** Check the signature.
|
||||
@return `true` if valid signature. If invalid, the error message string.
|
||||
*/
|
||||
enum class RequireFullyCanonicalSig : bool { no, yes };
|
||||
|
||||
/** Check the signature.
|
||||
@param requireCanonicalSig If `true`, check that the signature is fully
|
||||
canonical. If `false`, only check that the signature is valid.
|
||||
@param rules The current ledger rules.
|
||||
@return `true` if valid signature. If invalid, the error message string.
|
||||
*/
|
||||
Expected<void, std::string>
|
||||
checkSign(RequireFullyCanonicalSig requireCanonicalSig, Rules const& rules)
|
||||
const;
|
||||
@@ -150,17 +163,34 @@ public:
|
||||
char status,
|
||||
std::string const& escapedMetaData) const;
|
||||
|
||||
std::vector<uint256>
|
||||
std::vector<uint256> const&
|
||||
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>
|
||||
checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig) const;
|
||||
checkSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules,
|
||||
STObject const& sigObject) const;
|
||||
|
||||
Expected<void, std::string>
|
||||
checkSingleSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
STObject const& sigObject) const;
|
||||
|
||||
Expected<void, std::string>
|
||||
checkMultiSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules) const;
|
||||
Rules const& rules,
|
||||
STObject const& sigObject) const;
|
||||
|
||||
Expected<void, std::string>
|
||||
checkBatchSingleSign(
|
||||
@@ -179,7 +209,7 @@ private:
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend class detail::STVar;
|
||||
mutable std::vector<uint256> batch_txn_ids_;
|
||||
mutable std::vector<uint256> batchTxnIds_;
|
||||
};
|
||||
|
||||
bool
|
||||
|
||||
@@ -73,14 +73,8 @@ 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.
|
||||
|
||||
@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 support an amendment should have. */
|
||||
constexpr std::ratio<80, 100> amendmentMajorityCalcThreshold;
|
||||
|
||||
/** The minimum amount of time an amendment must hold a majority */
|
||||
constexpr std::chrono::seconds const defaultAmendmentMajorityTime = weeks{2};
|
||||
|
||||
@@ -225,8 +225,9 @@ 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
|
||||
terADDRESS_COLLISION, // Failed to allocate AccountID when trying to
|
||||
// create a pseudo-account
|
||||
terNO_DELEGATE_PERMISSION, // Delegate does not have permission
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -361,6 +362,9 @@ 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,
|
||||
};
|
||||
|
||||
|
||||
@@ -33,51 +33,35 @@ 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,
|
||||
std::optional<uint256> parentBatchId = std::nullopt);
|
||||
TxMeta(uint256 const& transactionID, std::uint32_t ledger);
|
||||
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 mTransactionID;
|
||||
return transactionID_;
|
||||
}
|
||||
std::uint32_t
|
||||
getLgrSeq() const
|
||||
{
|
||||
return mLedger;
|
||||
return ledgerSeq_;
|
||||
}
|
||||
int
|
||||
getResult() const
|
||||
{
|
||||
return mResult;
|
||||
return result_;
|
||||
}
|
||||
TER
|
||||
getResultTER() const
|
||||
{
|
||||
return TER::fromInt(mResult);
|
||||
return TER::fromInt(result_);
|
||||
}
|
||||
std::uint32_t
|
||||
getIndex() const
|
||||
{
|
||||
return mIndex;
|
||||
return index_;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -104,66 +88,52 @@ public:
|
||||
STArray&
|
||||
getNodes()
|
||||
{
|
||||
return (mNodes);
|
||||
return nodes_;
|
||||
}
|
||||
STArray const&
|
||||
getNodes() const
|
||||
{
|
||||
return (mNodes);
|
||||
return nodes_;
|
||||
}
|
||||
|
||||
void
|
||||
setDeliveredAmount(STAmount const& delivered)
|
||||
setAdditionalFields(STObject const& obj)
|
||||
{
|
||||
mDelivered = delivered;
|
||||
if (obj.isFieldPresent(sfDeliveredAmount))
|
||||
deliveredAmount_ = obj.getFieldAmount(sfDeliveredAmount);
|
||||
|
||||
if (obj.isFieldPresent(sfParentBatchID))
|
||||
parentBatchID_ = obj.getFieldH256(sfParentBatchID);
|
||||
}
|
||||
|
||||
STAmount
|
||||
std::optional<STAmount> const&
|
||||
getDeliveredAmount() const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
hasDeliveredAmount(),
|
||||
"ripple::TxMeta::getDeliveredAmount : non-null delivered amount");
|
||||
return *mDelivered;
|
||||
}
|
||||
|
||||
bool
|
||||
hasDeliveredAmount() const
|
||||
{
|
||||
return static_cast<bool>(mDelivered);
|
||||
return deliveredAmount_;
|
||||
}
|
||||
|
||||
void
|
||||
setParentBatchId(uint256 const& parentBatchId)
|
||||
setDeliveredAmount(std::optional<STAmount> const& amount)
|
||||
{
|
||||
mParentBatchId = parentBatchId;
|
||||
deliveredAmount_ = amount;
|
||||
}
|
||||
|
||||
uint256
|
||||
getParentBatchId() const
|
||||
void
|
||||
setParentBatchID(std::optional<uint256> const& id)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
hasParentBatchId(),
|
||||
"ripple::TxMeta::getParentBatchId : non-null batch id");
|
||||
return *mParentBatchId;
|
||||
}
|
||||
|
||||
bool
|
||||
hasParentBatchId() const
|
||||
{
|
||||
return static_cast<bool>(mParentBatchId);
|
||||
parentBatchID_ = id;
|
||||
}
|
||||
|
||||
private:
|
||||
uint256 mTransactionID;
|
||||
std::uint32_t mLedger;
|
||||
std::uint32_t mIndex;
|
||||
int mResult;
|
||||
uint256 transactionID_;
|
||||
std::uint32_t ledgerSeq_;
|
||||
std::uint32_t index_;
|
||||
int result_;
|
||||
|
||||
std::optional<STAmount> mDelivered;
|
||||
std::optional<uint256> mParentBatchId;
|
||||
std::optional<STAmount> deliveredAmount_;
|
||||
std::optional<uint256> parentBatchID_;
|
||||
|
||||
STArray mNodes;
|
||||
STArray nodes_;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -29,13 +29,12 @@
|
||||
|
||||
// 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_FEATURE(DynamicMPT, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (TokenEscrowV1, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (DelegateV1_1, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PriceOracleOrder, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (MPTDeliveredAmount, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMClawbackRounding, Supported::yes, VoteBehavior::DefaultNo)
|
||||
@@ -45,7 +44,6 @@ 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::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PayChanCancelAfter, Supported::yes, VoteBehavior::DefaultNo)
|
||||
// Check flags in Credential transactions
|
||||
XRPL_FIX (InvalidTxFlags, Supported::yes, VoteBehavior::DefaultNo)
|
||||
@@ -79,7 +77,6 @@ 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)
|
||||
@@ -91,27 +88,15 @@ 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)
|
||||
XRPL_FEATURE(DepositPreauth, Supported::yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (1623, 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_FEATURE(Flow, Supported::yes, VoteBehavior::DefaultYes)
|
||||
@@ -134,24 +119,38 @@ 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
|
||||
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)
|
||||
// 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)
|
||||
XRPL_RETIRE(fix1368)
|
||||
XRPL_RETIRE(fix1373)
|
||||
XRPL_RETIRE(fix1512)
|
||||
XRPL_RETIRE(fix1523)
|
||||
XRPL_RETIRE(fix1528)
|
||||
XRPL_RETIRE(FlowCross)
|
||||
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)
|
||||
|
||||
@@ -457,7 +457,7 @@ LEDGER_ENTRY(ltCREDENTIAL, 0x0081, Credential, credential, ({
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
{sfURI, soeOPTIONAL},
|
||||
{sfIssuerNode, soeREQUIRED},
|
||||
{sfSubjectNode, soeREQUIRED},
|
||||
{sfSubjectNode, soeOPTIONAL},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED},
|
||||
}))
|
||||
|
||||
@@ -316,7 +316,7 @@ TRANSACTION(ttTRUST_SET, 20, TrustSet,
|
||||
#endif
|
||||
TRANSACTION(ttACCOUNT_DELETE, 21, AccountDelete,
|
||||
Delegation::notDelegatable,
|
||||
uint256{},
|
||||
featureDeletableAccounts,
|
||||
mustDeleteAcct,
|
||||
({
|
||||
{sfDestination, soeREQUIRED},
|
||||
@@ -837,7 +837,7 @@ TRANSACTION(ttPERMISSIONED_DOMAIN_DELETE, 63, PermissionedDomainDelete,
|
||||
#endif
|
||||
TRANSACTION(ttDELEGATE_SET, 64, DelegateSet,
|
||||
Delegation::notDelegatable,
|
||||
featurePermissionDelegation,
|
||||
featurePermissionDelegationV1_1,
|
||||
noPriv,
|
||||
({
|
||||
{sfAuthorize, soeREQUIRED},
|
||||
|
||||
@@ -569,6 +569,7 @@ 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
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#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>
|
||||
|
||||
@@ -87,6 +88,9 @@ 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 key->address.to_string();
|
||||
return getFingerprint(key->address, publicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,6 +82,9 @@ 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;
|
||||
|
||||
|
||||
@@ -20,11 +20,10 @@
|
||||
#ifndef RIPPLE_SHAMAP_FAMILY_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_FAMILY_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Database.h>
|
||||
#include <xrpld/shamap/FullBelowCache.h>
|
||||
#include <xrpld/shamap/TreeNodeCache.h>
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/nodestore/Database.h>
|
||||
#include <xrpl/shamap/FullBelowCache.h>
|
||||
#include <xrpl/shamap/TreeNodeCache.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -20,21 +20,19 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAP_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAP_H_INCLUDED
|
||||
|
||||
#include <xrpld/nodestore/Database.h>
|
||||
#include <xrpld/nodestore/NodeObject.h>
|
||||
#include <xrpld/shamap/Family.h>
|
||||
#include <xrpld/shamap/SHAMapAddNode.h>
|
||||
#include <xrpld/shamap/SHAMapInnerNode.h>
|
||||
#include <xrpld/shamap/SHAMapItem.h>
|
||||
#include <xrpld/shamap/SHAMapLeafNode.h>
|
||||
#include <xrpld/shamap/SHAMapMissingNode.h>
|
||||
#include <xrpld/shamap/SHAMapTreeNode.h>
|
||||
#include <xrpld/shamap/TreeNodeCache.h>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.h>
|
||||
#include <xrpl/basics/UnorderedContainers.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/nodestore/Database.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
#include <xrpl/shamap/Family.h>
|
||||
#include <xrpl/shamap/SHAMapAddNode.h>
|
||||
#include <xrpl/shamap/SHAMapInnerNode.h>
|
||||
#include <xrpl/shamap/SHAMapItem.h>
|
||||
#include <xrpl/shamap/SHAMapLeafNode.h>
|
||||
#include <xrpl/shamap/SHAMapMissingNode.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <set>
|
||||
#include <stack>
|
||||
@@ -20,12 +20,11 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAPACCOUNTSTATELEAFNODE_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapItem.h>
|
||||
#include <xrpld/shamap/SHAMapLeafNode.h>
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/shamap/SHAMapItem.h>
|
||||
#include <xrpl/shamap/SHAMapLeafNode.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAPINNERNODE_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapNodeID.h>
|
||||
#include <xrpld/shamap/detail/TaggedPointer.h>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.h>
|
||||
#include <xrpl/shamap/SHAMapNodeID.h>
|
||||
#include <xrpl/shamap/detail/TaggedPointer.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
@@ -20,8 +20,8 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAPLEAFNODE_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapItem.h>
|
||||
#include <xrpld/shamap/SHAMapTreeNode.h>
|
||||
#include <xrpl/shamap/SHAMapItem.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAPMISSINGNODE_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <stdexcept>
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAPSYNCFILTER_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapTreeNode.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
@@ -20,13 +20,12 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAPTREENODE_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapItem.h>
|
||||
#include <xrpld/shamap/SHAMapNodeID.h>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.h>
|
||||
#include <xrpl/basics/IntrusiveRefCounts.h>
|
||||
#include <xrpl/basics/SHAMapHash.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/shamap/SHAMapItem.h>
|
||||
#include <xrpl/shamap/SHAMapNodeID.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
@@ -20,12 +20,11 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAPTXLEAFNODE_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapItem.h>
|
||||
#include <xrpld/shamap/SHAMapLeafNode.h>
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/shamap/SHAMapItem.h>
|
||||
#include <xrpl/shamap/SHAMapLeafNode.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -20,12 +20,11 @@
|
||||
#ifndef RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_SHAMAPLEAFTXPLUSMETANODE_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapItem.h>
|
||||
#include <xrpld/shamap/SHAMapLeafNode.h>
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/shamap/SHAMapItem.h>
|
||||
#include <xrpl/shamap/SHAMapLeafNode.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -20,10 +20,9 @@
|
||||
#ifndef RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_TREENODECACHE_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.h>
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
#ifndef RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED
|
||||
#define RIPPLE_SHAMAP_TAGGEDPOINTER_H_INCLUDED
|
||||
|
||||
#include <xrpld/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -17,10 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/shamap/SHAMapInnerNode.h>
|
||||
#include <xrpld/shamap/detail/TaggedPointer.h>
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/shamap/SHAMapInnerNode.h>
|
||||
#include <xrpl/shamap/detail/TaggedPointer.h>
|
||||
|
||||
#include <boost/pool/pool_alloc.hpp>
|
||||
|
||||
@@ -126,10 +126,10 @@ ApplyStateTable::apply(
|
||||
std::optional<TxMeta> metadata;
|
||||
if (!to.open() || isDryRun)
|
||||
{
|
||||
TxMeta meta(tx.getTransactionID(), to.seq(), parentBatchId);
|
||||
TxMeta meta(tx.getTransactionID(), to.seq());
|
||||
|
||||
if (deliver)
|
||||
meta.setDeliveredAmount(*deliver);
|
||||
meta.setDeliveredAmount(deliver);
|
||||
meta.setParentBatchID(parentBatchId);
|
||||
|
||||
Mods newMod;
|
||||
for (auto& item : items_)
|
||||
@@ -682,12 +682,6 @@ 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,6 +22,9 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::optional<std::uint64_t>
|
||||
@@ -91,8 +94,21 @@ 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 >= dirNodeMaxPages)
|
||||
if (page == 0)
|
||||
return std::nullopt;
|
||||
if (!rules().enabled(fixDirectoryLimit) &&
|
||||
page >= dirNodeMaxPages) // Old pages limit
|
||||
return std::nullopt;
|
||||
|
||||
// We are about to create a new node; we'll link it to
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/detail/BatchWriter.h>
|
||||
#include <xrpl/nodestore/detail/BatchWriter.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -17,11 +17,10 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/Database.h>
|
||||
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/nodestore/Database.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/detail/DatabaseNodeImp.h>
|
||||
#include <xrpl/nodestore/detail/DatabaseNodeImp.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/detail/DatabaseRotatingImp.h>
|
||||
#include <xrpl/nodestore/detail/DatabaseRotatingImp.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -17,10 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/detail/DecodedBlob.h>
|
||||
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/nodestore/detail/DecodedBlob.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/DummyScheduler.h>
|
||||
#include <xrpl/nodestore/DummyScheduler.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace NodeStore {
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/detail/DatabaseNodeImp.h>
|
||||
#include <xrpld/nodestore/detail/ManagerImp.h>
|
||||
#include <xrpl/nodestore/detail/DatabaseNodeImp.h>
|
||||
#include <xrpl/nodestore/detail/ManagerImp.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
@@ -41,6 +41,27 @@ ManagerImp::missing_backend()
|
||||
"please see the rippled-example.cfg file!");
|
||||
}
|
||||
|
||||
// We shouldn't rely on global variables for lifetime management because their
|
||||
// lifetime is not well-defined. ManagerImp may get destroyed before the Factory
|
||||
// classes, and then, calling Manager::instance().erase() in the destructors of
|
||||
// the Factory classes is an undefined behaviour.
|
||||
void
|
||||
registerNuDBFactory(Manager& manager);
|
||||
void
|
||||
registerRocksDBFactory(Manager& manager);
|
||||
void
|
||||
registerNullFactory(Manager& manager);
|
||||
void
|
||||
registerMemoryFactory(Manager& manager);
|
||||
|
||||
ManagerImp::ManagerImp()
|
||||
{
|
||||
registerNuDBFactory(*this);
|
||||
registerRocksDBFactory(*this);
|
||||
registerNullFactory(*this);
|
||||
registerMemoryFactory(*this);
|
||||
}
|
||||
|
||||
std::unique_ptr<Backend>
|
||||
ManagerImp::make_Backend(
|
||||
Section const& parameters,
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/NodeObject.h>
|
||||
#include <xrpl/nodestore/NodeObject.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/Factory.h>
|
||||
#include <xrpld/nodestore/Manager.h>
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/nodestore/Factory.h>
|
||||
#include <xrpl/nodestore/Manager.h>
|
||||
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
@@ -46,10 +45,10 @@ class MemoryFactory : public Factory
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::map<std::string, MemoryDB, boost::beast::iless> map_;
|
||||
Manager& manager_;
|
||||
|
||||
public:
|
||||
MemoryFactory();
|
||||
~MemoryFactory() override;
|
||||
explicit MemoryFactory(Manager& manager);
|
||||
|
||||
std::string
|
||||
getName() const override;
|
||||
@@ -75,7 +74,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static MemoryFactory memoryFactory;
|
||||
MemoryFactory* memoryFactory = nullptr;
|
||||
|
||||
void
|
||||
registerMemoryFactory(Manager& manager)
|
||||
{
|
||||
static MemoryFactory instance{manager};
|
||||
memoryFactory = &instance;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -112,9 +118,9 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
open(bool createIfMissing) override
|
||||
open(bool) override
|
||||
{
|
||||
db_ = &memoryFactory.open(name_);
|
||||
db_ = &memoryFactory->open(name_);
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -219,14 +225,9 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
MemoryFactory::MemoryFactory()
|
||||
MemoryFactory::MemoryFactory(Manager& manager) : manager_(manager)
|
||||
{
|
||||
Manager::instance().insert(*this);
|
||||
}
|
||||
|
||||
MemoryFactory::~MemoryFactory()
|
||||
{
|
||||
Manager::instance().erase(*this);
|
||||
manager_.insert(*this);
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -17,15 +17,14 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/Factory.h>
|
||||
#include <xrpld/nodestore/Manager.h>
|
||||
#include <xrpld/nodestore/detail/DecodedBlob.h>
|
||||
#include <xrpld/nodestore/detail/EncodedBlob.h>
|
||||
#include <xrpld/nodestore/detail/codec.h>
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/core/LexicalCast.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/nodestore/Factory.h>
|
||||
#include <xrpl/nodestore/Manager.h>
|
||||
#include <xrpl/nodestore/detail/DecodedBlob.h>
|
||||
#include <xrpl/nodestore/detail/EncodedBlob.h>
|
||||
#include <xrpl/nodestore/detail/codec.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
@@ -427,15 +426,13 @@ private:
|
||||
|
||||
class NuDBFactory : public Factory
|
||||
{
|
||||
public:
|
||||
NuDBFactory()
|
||||
{
|
||||
Manager::instance().insert(*this);
|
||||
}
|
||||
private:
|
||||
Manager& manager_;
|
||||
|
||||
~NuDBFactory() override
|
||||
public:
|
||||
explicit NuDBFactory(Manager& manager) : manager_(manager)
|
||||
{
|
||||
Manager::instance().erase(*this);
|
||||
manager_.insert(*this);
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -470,7 +467,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static NuDBFactory nuDBFactory;
|
||||
void
|
||||
registerNuDBFactory(Manager& manager)
|
||||
{
|
||||
static NuDBFactory instance{manager};
|
||||
}
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/nodestore/Factory.h>
|
||||
#include <xrpld/nodestore/Manager.h>
|
||||
#include <xrpl/nodestore/Factory.h>
|
||||
#include <xrpl/nodestore/Manager.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -111,15 +111,13 @@ private:
|
||||
|
||||
class NullFactory : public Factory
|
||||
{
|
||||
public:
|
||||
NullFactory()
|
||||
{
|
||||
Manager::instance().insert(*this);
|
||||
}
|
||||
private:
|
||||
Manager& manager_;
|
||||
|
||||
~NullFactory() override
|
||||
public:
|
||||
explicit NullFactory(Manager& manager) : manager_(manager)
|
||||
{
|
||||
Manager::instance().erase(*this);
|
||||
manager_.insert(*this);
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -140,7 +138,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static NullFactory nullFactory;
|
||||
void
|
||||
registerNullFactory(Manager& manager)
|
||||
{
|
||||
static NullFactory instance{manager};
|
||||
}
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
@@ -17,20 +17,18 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/unity/rocksdb.h>
|
||||
#include <xrpl/basics/rocksdb.h>
|
||||
|
||||
#if RIPPLE_ROCKSDB_AVAILABLE
|
||||
#include <xrpld/core/Config.h> // VFALCO Bad dependency
|
||||
#include <xrpld/nodestore/Factory.h>
|
||||
#include <xrpld/nodestore/Manager.h>
|
||||
#include <xrpld/nodestore/detail/BatchWriter.h>
|
||||
#include <xrpld/nodestore/detail/DecodedBlob.h>
|
||||
#include <xrpld/nodestore/detail/EncodedBlob.h>
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||
#include <xrpl/nodestore/Factory.h>
|
||||
#include <xrpl/nodestore/Manager.h>
|
||||
#include <xrpl/nodestore/detail/BatchWriter.h>
|
||||
#include <xrpl/nodestore/detail/DecodedBlob.h>
|
||||
#include <xrpl/nodestore/detail/EncodedBlob.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
@@ -461,17 +459,15 @@ public:
|
||||
|
||||
class RocksDBFactory : public Factory
|
||||
{
|
||||
private:
|
||||
Manager& manager_;
|
||||
|
||||
public:
|
||||
RocksDBEnv m_env;
|
||||
|
||||
RocksDBFactory()
|
||||
RocksDBFactory(Manager& manager) : manager_(manager)
|
||||
{
|
||||
Manager::instance().insert(*this);
|
||||
}
|
||||
|
||||
~RocksDBFactory() override
|
||||
{
|
||||
Manager::instance().erase(*this);
|
||||
manager_.insert(*this);
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -493,7 +489,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
static RocksDBFactory rocksDBFactory;
|
||||
void
|
||||
registerRocksDBFactory(Manager& manager)
|
||||
{
|
||||
static RocksDBFactory instance{manager};
|
||||
}
|
||||
|
||||
} // namespace NodeStore
|
||||
} // namespace ripple
|
||||
@@ -174,21 +174,22 @@ Permission::isDelegatable(
|
||||
auto const txType = permissionToTxType(permissionValue);
|
||||
auto const it = delegatableTx_.find(txType);
|
||||
|
||||
if (rules.enabled(fixDelegateV1_1))
|
||||
{
|
||||
if (it == delegatableTx_.end())
|
||||
return false;
|
||||
if (it == delegatableTx_.end())
|
||||
return false;
|
||||
|
||||
auto const feature = getTxFeature(txType);
|
||||
auto const txFeaturesIt = txFeatureMap_.find(txType);
|
||||
XRPL_ASSERT(
|
||||
txFeaturesIt != txFeatureMap_.end(),
|
||||
"ripple::Permissions::isDelegatable : tx exists in txFeatureMap_");
|
||||
|
||||
// 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 (feature && !rules.enabled(*feature))
|
||||
return false;
|
||||
}
|
||||
// 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 != delegatableTx_.end() && it->second == Delegation::notDelegatable)
|
||||
if (it->second == Delegation::notDelegatable)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -63,34 +63,12 @@
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
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;
|
||||
@@ -884,18 +862,14 @@ STAmount::canonicalize()
|
||||
return;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
// 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() && getSTAmountCanonicalizeSwitchover())
|
||||
if (getSTNumberSwitchover())
|
||||
{
|
||||
Number num(
|
||||
mIsNegative ? -mValue : mValue, mOffset, Number::unchecked{});
|
||||
@@ -919,16 +893,14 @@ STAmount::canonicalize()
|
||||
|
||||
while (mOffset > 0)
|
||||
{
|
||||
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");
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
@@ -1135,7 +1107,8 @@ amountFromJson(SField const& name, Json::Value const& v)
|
||||
}
|
||||
else
|
||||
{
|
||||
parts.mantissa = -value.asInt();
|
||||
std::int64_t const temp = value.asInt();
|
||||
parts.mantissa = -temp;
|
||||
parts.negative = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,10 @@
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
@@ -188,7 +190,8 @@ numberFromJson(SField const& field, Json::Value const& value)
|
||||
}
|
||||
else
|
||||
{
|
||||
parts.mantissa = -value.asInt();
|
||||
std::int64_t const temp = value.asInt();
|
||||
parts.mantissa = -temp;
|
||||
parts.negative = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,6 +688,16 @@ 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
|
||||
{
|
||||
@@ -833,6 +843,12 @@ 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
|
||||
{
|
||||
|
||||
@@ -200,11 +200,11 @@ STTx::getSigningHash() const
|
||||
}
|
||||
|
||||
Blob
|
||||
STTx::getSignature() const
|
||||
STTx::getSignature(STObject const& sigObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
return getFieldVL(sfTxnSignature);
|
||||
return sigObject.getFieldVL(sfTxnSignature);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
@@ -234,35 +234,68 @@ STTx::getSeqValue() const
|
||||
}
|
||||
|
||||
void
|
||||
STTx::sign(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
STTx::sign(
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
std::optional<std::reference_wrapper<SField const>> signatureTarget)
|
||||
{
|
||||
auto const data = getSigningData(*this);
|
||||
|
||||
auto const sig = ripple::sign(publicKey, secretKey, makeSlice(data));
|
||||
|
||||
setFieldVL(sfTxnSignature, sig);
|
||||
if (signatureTarget)
|
||||
{
|
||||
auto& target = peekFieldObject(*signatureTarget);
|
||||
target.setFieldVL(sfTxnSignature, sig);
|
||||
}
|
||||
else
|
||||
{
|
||||
setFieldVL(sfTxnSignature, sig);
|
||||
}
|
||||
tid_ = getHash(HashPrefix::transactionID);
|
||||
}
|
||||
|
||||
Expected<void, std::string>
|
||||
STTx::checkSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules,
|
||||
STObject const& sigObject) const
|
||||
{
|
||||
try
|
||||
{
|
||||
// Determine whether we're single- or multi-signing by looking
|
||||
// at the SigningPubKey. If it's empty we must be
|
||||
// multi-signing. Otherwise we're single-signing.
|
||||
|
||||
Blob const& signingPubKey = sigObject.getFieldVL(sfSigningPubKey);
|
||||
return signingPubKey.empty()
|
||||
? checkMultiSign(requireCanonicalSig, rules, sigObject)
|
||||
: checkSingleSign(requireCanonicalSig, sigObject);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
}
|
||||
return Unexpected("Internal signature check failure.");
|
||||
}
|
||||
|
||||
Expected<void, std::string>
|
||||
STTx::checkSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules) const
|
||||
{
|
||||
try
|
||||
if (auto const ret = checkSign(requireCanonicalSig, rules, *this); !ret)
|
||||
return ret;
|
||||
|
||||
/* Placeholder for field that will be added by Lending Protocol
|
||||
if (isFieldPresent(sfCounterpartySignature))
|
||||
{
|
||||
// Determine whether we're single- or multi-signing by looking
|
||||
// at the SigningPubKey. If it's empty we must be
|
||||
// multi-signing. Otherwise we're single-signing.
|
||||
Blob const& signingPubKey = getFieldVL(sfSigningPubKey);
|
||||
return signingPubKey.empty()
|
||||
? checkMultiSign(requireCanonicalSig, rules)
|
||||
: checkSingleSign(requireCanonicalSig);
|
||||
auto const counterSig = getFieldObject(sfCounterpartySignature);
|
||||
if (auto const ret = checkSign(requireCanonicalSig, rules, counterSig);
|
||||
!ret)
|
||||
return Unexpected("Counterparty: " + ret.error());
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
}
|
||||
return Unexpected("Internal signature check failure.");
|
||||
*/
|
||||
return {};
|
||||
}
|
||||
|
||||
Expected<void, std::string>
|
||||
@@ -382,23 +415,23 @@ STTx::getMetaSQL(
|
||||
|
||||
static Expected<void, std::string>
|
||||
singleSignHelper(
|
||||
STObject const& signer,
|
||||
STObject const& sigObject,
|
||||
Slice const& data,
|
||||
bool const fullyCanonical)
|
||||
{
|
||||
// We don't allow both a non-empty sfSigningPubKey and an sfSigners.
|
||||
// That would allow the transaction to be signed two ways. So if both
|
||||
// fields are present the signature is invalid.
|
||||
if (signer.isFieldPresent(sfSigners))
|
||||
if (sigObject.isFieldPresent(sfSigners))
|
||||
return Unexpected("Cannot both single- and multi-sign.");
|
||||
|
||||
bool validSig = false;
|
||||
try
|
||||
{
|
||||
auto const spk = signer.getFieldVL(sfSigningPubKey);
|
||||
auto const spk = sigObject.getFieldVL(sfSigningPubKey);
|
||||
if (publicKeyType(makeSlice(spk)))
|
||||
{
|
||||
Blob const signature = signer.getFieldVL(sfTxnSignature);
|
||||
Blob const signature = sigObject.getFieldVL(sfTxnSignature);
|
||||
validSig = verify(
|
||||
PublicKey(makeSlice(spk)),
|
||||
data,
|
||||
@@ -418,12 +451,14 @@ singleSignHelper(
|
||||
}
|
||||
|
||||
Expected<void, std::string>
|
||||
STTx::checkSingleSign(RequireFullyCanonicalSig requireCanonicalSig) const
|
||||
STTx::checkSingleSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
STObject const& sigObject) const
|
||||
{
|
||||
auto const data = getSigningData(*this);
|
||||
bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig) ||
|
||||
(requireCanonicalSig == STTx::RequireFullyCanonicalSig::yes);
|
||||
return singleSignHelper(*this, makeSlice(data), fullyCanonical);
|
||||
return singleSignHelper(sigObject, makeSlice(data), fullyCanonical);
|
||||
}
|
||||
|
||||
Expected<void, std::string>
|
||||
@@ -440,31 +475,29 @@ STTx::checkBatchSingleSign(
|
||||
|
||||
Expected<void, std::string>
|
||||
multiSignHelper(
|
||||
STObject const& signerObj,
|
||||
STObject const& sigObject,
|
||||
std::optional<AccountID> txnAccountID,
|
||||
bool const fullyCanonical,
|
||||
std::function<Serializer(AccountID const&)> makeMsg,
|
||||
Rules const& rules)
|
||||
{
|
||||
// Make sure the MultiSigners are present. Otherwise they are not
|
||||
// attempting multi-signing and we just have a bad SigningPubKey.
|
||||
if (!signerObj.isFieldPresent(sfSigners))
|
||||
if (!sigObject.isFieldPresent(sfSigners))
|
||||
return Unexpected("Empty SigningPubKey.");
|
||||
|
||||
// We don't allow both an sfSigners and an sfTxnSignature. Both fields
|
||||
// being present would indicate that the transaction is signed both ways.
|
||||
if (signerObj.isFieldPresent(sfTxnSignature))
|
||||
if (sigObject.isFieldPresent(sfTxnSignature))
|
||||
return Unexpected("Cannot both single- and multi-sign.");
|
||||
|
||||
STArray const& signers{signerObj.getFieldArray(sfSigners)};
|
||||
STArray const& signers{sigObject.getFieldArray(sfSigners)};
|
||||
|
||||
// There are well known bounds that the number of signers must be within.
|
||||
if (signers.size() < STTx::minMultiSigners ||
|
||||
signers.size() > STTx::maxMultiSigners(&rules))
|
||||
return Unexpected("Invalid Signers array size.");
|
||||
|
||||
// We also use the sfAccount field inside the loop. Get it once.
|
||||
auto const txnAccountID = signerObj.getAccountID(sfAccount);
|
||||
|
||||
// Signers must be in sorted order by AccountID.
|
||||
AccountID lastAccountID(beast::zero);
|
||||
|
||||
@@ -472,8 +505,10 @@ multiSignHelper(
|
||||
{
|
||||
auto const accountID = signer.getAccountID(sfAccount);
|
||||
|
||||
// The account owner may not multisign for themselves.
|
||||
if (accountID == txnAccountID)
|
||||
// The account owner may not usually multisign for themselves.
|
||||
// If they can, txnAccountID will be unseated, which is not equal to any
|
||||
// value.
|
||||
if (txnAccountID == accountID)
|
||||
return Unexpected("Invalid multisigner.");
|
||||
|
||||
// No duplicate signers allowed.
|
||||
@@ -489,6 +524,7 @@ multiSignHelper(
|
||||
|
||||
// Verify the signature.
|
||||
bool validSig = false;
|
||||
std::optional<std::string> errorWhat;
|
||||
try
|
||||
{
|
||||
auto spk = signer.getFieldVL(sfSigningPubKey);
|
||||
@@ -502,15 +538,16 @@ multiSignHelper(
|
||||
fullyCanonical);
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
// We assume any problem lies with the signature.
|
||||
validSig = false;
|
||||
errorWhat = e.what();
|
||||
}
|
||||
if (!validSig)
|
||||
return Unexpected(
|
||||
std::string("Invalid signature on account ") +
|
||||
toBase58(accountID) + ".");
|
||||
toBase58(accountID) + errorWhat.value_or("") + ".");
|
||||
}
|
||||
// All signatures verified.
|
||||
return {};
|
||||
@@ -532,8 +569,9 @@ STTx::checkBatchMultiSign(
|
||||
serializeBatch(dataStart, getFlags(), getBatchTransactionIDs());
|
||||
return multiSignHelper(
|
||||
batchSigner,
|
||||
std::nullopt,
|
||||
fullyCanonical,
|
||||
[&dataStart](AccountID const& accountID) mutable -> Serializer {
|
||||
[&dataStart](AccountID const& accountID) -> Serializer {
|
||||
Serializer s = dataStart;
|
||||
finishMultiSigningData(accountID, s);
|
||||
return s;
|
||||
@@ -544,19 +582,27 @@ STTx::checkBatchMultiSign(
|
||||
Expected<void, std::string>
|
||||
STTx::checkMultiSign(
|
||||
RequireFullyCanonicalSig requireCanonicalSig,
|
||||
Rules const& rules) const
|
||||
Rules const& rules,
|
||||
STObject const& sigObject) const
|
||||
{
|
||||
bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig) ||
|
||||
(requireCanonicalSig == RequireFullyCanonicalSig::yes);
|
||||
|
||||
// Used inside the loop in multiSignHelper to enforce that
|
||||
// the account owner may not multisign for themselves.
|
||||
auto const txnAccountID = &sigObject != this
|
||||
? std::nullopt
|
||||
: std::optional<AccountID>(getAccountID(sfAccount));
|
||||
|
||||
// We can ease the computational load inside the loop a bit by
|
||||
// pre-constructing part of the data that we hash. Fill a Serializer
|
||||
// with the stuff that stays constant from signature to signature.
|
||||
Serializer dataStart = startMultiSigningData(*this);
|
||||
return multiSignHelper(
|
||||
*this,
|
||||
sigObject,
|
||||
txnAccountID,
|
||||
fullyCanonical,
|
||||
[&dataStart](AccountID const& accountID) mutable -> Serializer {
|
||||
[&dataStart](AccountID const& accountID) -> Serializer {
|
||||
Serializer s = dataStart;
|
||||
finishMultiSigningData(accountID, s);
|
||||
return s;
|
||||
@@ -569,7 +615,7 @@ STTx::checkMultiSign(
|
||||
*
|
||||
* This function returns a vector of transaction IDs by extracting them from
|
||||
* the field array `sfRawTransactions` within the STTx. If the batch
|
||||
* transaction IDs have already been computed and cached in `batch_txn_ids_`,
|
||||
* transaction IDs have already been computed and cached in `batchTxnIds_`,
|
||||
* it returns the cached vector. Otherwise, it computes the transaction IDs,
|
||||
* caches them, and then returns the vector.
|
||||
*
|
||||
@@ -579,7 +625,7 @@ STTx::checkMultiSign(
|
||||
* empty and that the size of the computed batch transaction IDs matches the
|
||||
* size of the `sfRawTransactions` field array.
|
||||
*/
|
||||
std::vector<uint256>
|
||||
std::vector<uint256> const&
|
||||
STTx::getBatchTransactionIDs() const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
@@ -588,16 +634,20 @@ STTx::getBatchTransactionIDs() const
|
||||
XRPL_ASSERT(
|
||||
getFieldArray(sfRawTransactions).size() != 0,
|
||||
"STTx::getBatchTransactionIDs : empty raw transactions");
|
||||
if (batch_txn_ids_.size() != 0)
|
||||
return batch_txn_ids_;
|
||||
|
||||
for (STObject const& rb : getFieldArray(sfRawTransactions))
|
||||
batch_txn_ids_.push_back(rb.getHash(HashPrefix::transactionID));
|
||||
// The list of inner ids is built once, then reused on subsequent calls.
|
||||
// After the list is built, it must always have the same size as the array
|
||||
// `sfRawTransactions`. The assert below verifies that.
|
||||
if (batchTxnIds_.size() == 0)
|
||||
{
|
||||
for (STObject const& rb : getFieldArray(sfRawTransactions))
|
||||
batchTxnIds_.push_back(rb.getHash(HashPrefix::transactionID));
|
||||
}
|
||||
|
||||
XRPL_ASSERT(
|
||||
batch_txn_ids_.size() == getFieldArray(sfRawTransactions).size(),
|
||||
batchTxnIds_.size() == getFieldArray(sfRawTransactions).size(),
|
||||
"STTx::getBatchTransactionIDs : batch transaction IDs size mismatch");
|
||||
return batch_txn_ids_;
|
||||
return batchTxnIds_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -127,7 +127,6 @@ transResults()
|
||||
MAKE_ERROR(tecLIMIT_EXCEEDED, "Limit exceeded."),
|
||||
MAKE_ERROR(tecPSEUDO_ACCOUNT, "This operation is not allowed against a pseudo-account."),
|
||||
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
|
||||
MAKE_ERROR(tecNO_DELEGATE_PERMISSION, "Delegated account lacks permission to perform this transaction."),
|
||||
|
||||
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
||||
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||
@@ -235,6 +234,7 @@ transResults()
|
||||
MAKE_ERROR(terPRE_TICKET, "Ticket is not yet in ledger."),
|
||||
MAKE_ERROR(terNO_AMM, "AMM doesn't exist for the asset pair."),
|
||||
MAKE_ERROR(terADDRESS_COLLISION, "Failed to allocate an unique account address."),
|
||||
MAKE_ERROR(terNO_DELEGATE_PERMISSION, "Delegated account lacks permission to perform this transaction."),
|
||||
|
||||
MAKE_ERROR(tesSUCCESS, "The transaction was applied. Only final in a validated ledger."),
|
||||
};
|
||||
|
||||
@@ -39,35 +39,13 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
template <class T>
|
||||
TxMeta::TxMeta(
|
||||
uint256 const& txid,
|
||||
std::uint32_t ledger,
|
||||
T const& data,
|
||||
CtorHelper)
|
||||
: mTransactionID(txid), mLedger(ledger), mNodes(sfAffectedNodes, 32)
|
||||
{
|
||||
SerialIter sit(makeSlice(data));
|
||||
|
||||
STObject obj(sit, sfMetadata);
|
||||
mResult = obj.getFieldU8(sfTransactionResult);
|
||||
mIndex = obj.getFieldU32(sfTransactionIndex);
|
||||
mNodes = *dynamic_cast<STArray*>(&obj.getField(sfAffectedNodes));
|
||||
|
||||
if (obj.isFieldPresent(sfDeliveredAmount))
|
||||
setDeliveredAmount(obj.getFieldAmount(sfDeliveredAmount));
|
||||
|
||||
if (obj.isFieldPresent(sfParentBatchID))
|
||||
setParentBatchId(obj.getFieldH256(sfParentBatchID));
|
||||
}
|
||||
|
||||
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
|
||||
: mTransactionID(txid)
|
||||
, mLedger(ledger)
|
||||
, mNodes(obj.getFieldArray(sfAffectedNodes))
|
||||
: transactionID_(txid)
|
||||
, ledgerSeq_(ledger)
|
||||
, nodes_(obj.getFieldArray(sfAffectedNodes))
|
||||
{
|
||||
mResult = obj.getFieldU8(sfTransactionResult);
|
||||
mIndex = obj.getFieldU32(sfTransactionIndex);
|
||||
result_ = obj.getFieldU8(sfTransactionResult);
|
||||
index_ = obj.getFieldU32(sfTransactionIndex);
|
||||
|
||||
auto affectedNodes =
|
||||
dynamic_cast<STArray const*>(obj.peekAtPField(sfAffectedNodes));
|
||||
@@ -75,40 +53,32 @@ TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, STObject const& obj)
|
||||
affectedNodes,
|
||||
"ripple::TxMeta::TxMeta(STObject) : type cast succeeded");
|
||||
if (affectedNodes)
|
||||
mNodes = *affectedNodes;
|
||||
nodes_ = *affectedNodes;
|
||||
|
||||
if (obj.isFieldPresent(sfDeliveredAmount))
|
||||
setDeliveredAmount(obj.getFieldAmount(sfDeliveredAmount));
|
||||
|
||||
if (obj.isFieldPresent(sfParentBatchID))
|
||||
setParentBatchId(obj.getFieldH256(sfParentBatchID));
|
||||
setAdditionalFields(obj);
|
||||
}
|
||||
|
||||
TxMeta::TxMeta(uint256 const& txid, std::uint32_t ledger, Blob const& vec)
|
||||
: TxMeta(txid, ledger, vec, CtorHelper())
|
||||
: transactionID_(txid), ledgerSeq_(ledger), nodes_(sfAffectedNodes, 32)
|
||||
{
|
||||
SerialIter sit(makeSlice(vec));
|
||||
|
||||
STObject obj(sit, sfMetadata);
|
||||
result_ = obj.getFieldU8(sfTransactionResult);
|
||||
index_ = obj.getFieldU32(sfTransactionIndex);
|
||||
nodes_ = obj.getFieldArray(sfAffectedNodes);
|
||||
|
||||
setAdditionalFields(obj);
|
||||
}
|
||||
|
||||
TxMeta::TxMeta(
|
||||
uint256 const& txid,
|
||||
std::uint32_t ledger,
|
||||
std::string const& data)
|
||||
: TxMeta(txid, ledger, data, CtorHelper())
|
||||
TxMeta::TxMeta(uint256 const& transactionID, std::uint32_t ledger)
|
||||
: transactionID_(transactionID)
|
||||
, ledgerSeq_(ledger)
|
||||
, index_(std::numeric_limits<std::uint32_t>::max())
|
||||
, result_(255)
|
||||
, nodes_(sfAffectedNodes)
|
||||
{
|
||||
}
|
||||
|
||||
TxMeta::TxMeta(
|
||||
uint256 const& transactionID,
|
||||
std::uint32_t ledger,
|
||||
std::optional<uint256> parentBatchId)
|
||||
: mTransactionID(transactionID)
|
||||
, mLedger(ledger)
|
||||
, mIndex(static_cast<std::uint32_t>(-1))
|
||||
, mResult(255)
|
||||
, mParentBatchId(parentBatchId)
|
||||
, mNodes(sfAffectedNodes)
|
||||
{
|
||||
mNodes.reserve(32);
|
||||
nodes_.reserve(32);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -118,7 +88,7 @@ TxMeta::setAffectedNode(
|
||||
std::uint16_t nodeType)
|
||||
{
|
||||
// make sure the node exists and force its type
|
||||
for (auto& n : mNodes)
|
||||
for (auto& n : nodes_)
|
||||
{
|
||||
if (n.getFieldH256(sfLedgerIndex) == node)
|
||||
{
|
||||
@@ -128,8 +98,8 @@ TxMeta::setAffectedNode(
|
||||
}
|
||||
}
|
||||
|
||||
mNodes.push_back(STObject(type));
|
||||
STObject& obj = mNodes.back();
|
||||
nodes_.push_back(STObject(type));
|
||||
STObject& obj = nodes_.back();
|
||||
|
||||
XRPL_ASSERT(
|
||||
obj.getFName() == type,
|
||||
@@ -146,14 +116,15 @@ TxMeta::getAffectedAccounts() const
|
||||
|
||||
// This code should match the behavior of the JS method:
|
||||
// Meta#getAffectedAccounts
|
||||
for (auto const& it : mNodes)
|
||||
for (auto const& node : nodes_)
|
||||
{
|
||||
int index = it.getFieldIndex(
|
||||
(it.getFName() == sfCreatedNode) ? sfNewFields : sfFinalFields);
|
||||
int index = node.getFieldIndex(
|
||||
(node.getFName() == sfCreatedNode) ? sfNewFields : sfFinalFields);
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
auto inner = dynamic_cast<STObject const*>(&it.peekAtIndex(index));
|
||||
auto const* inner =
|
||||
dynamic_cast<STObject const*>(&node.peekAtIndex(index));
|
||||
XRPL_ASSERT(
|
||||
inner,
|
||||
"ripple::getAffectedAccounts : STObject type cast succeeded");
|
||||
@@ -213,13 +184,13 @@ STObject&
|
||||
TxMeta::getAffectedNode(SLE::ref node, SField const& type)
|
||||
{
|
||||
uint256 index = node->key();
|
||||
for (auto& n : mNodes)
|
||||
for (auto& n : nodes_)
|
||||
{
|
||||
if (n.getFieldH256(sfLedgerIndex) == index)
|
||||
return n;
|
||||
}
|
||||
mNodes.push_back(STObject(type));
|
||||
STObject& obj = mNodes.back();
|
||||
nodes_.push_back(STObject(type));
|
||||
STObject& obj = nodes_.back();
|
||||
|
||||
XRPL_ASSERT(
|
||||
obj.getFName() == type,
|
||||
@@ -233,7 +204,7 @@ TxMeta::getAffectedNode(SLE::ref node, SField const& type)
|
||||
STObject&
|
||||
TxMeta::getAffectedNode(uint256 const& node)
|
||||
{
|
||||
for (auto& n : mNodes)
|
||||
for (auto& n : nodes_)
|
||||
{
|
||||
if (n.getFieldH256(sfLedgerIndex) == node)
|
||||
return n;
|
||||
@@ -241,7 +212,7 @@ TxMeta::getAffectedNode(uint256 const& node)
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("ripple::TxMeta::getAffectedNode(uint256) : node not found");
|
||||
Throw<std::runtime_error>("Affected node not found");
|
||||
return *(mNodes.begin()); // Silence compiler warning.
|
||||
return *(nodes_.begin()); // Silence compiler warning.
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
@@ -249,15 +220,15 @@ STObject
|
||||
TxMeta::getAsObject() const
|
||||
{
|
||||
STObject metaData(sfTransactionMetaData);
|
||||
XRPL_ASSERT(mResult != 255, "ripple::TxMeta::getAsObject : result is set");
|
||||
metaData.setFieldU8(sfTransactionResult, mResult);
|
||||
metaData.setFieldU32(sfTransactionIndex, mIndex);
|
||||
metaData.emplace_back(mNodes);
|
||||
if (hasDeliveredAmount())
|
||||
metaData.setFieldAmount(sfDeliveredAmount, getDeliveredAmount());
|
||||
XRPL_ASSERT(result_ != 255, "ripple::TxMeta::getAsObject : result_ is set");
|
||||
metaData.setFieldU8(sfTransactionResult, result_);
|
||||
metaData.setFieldU32(sfTransactionIndex, index_);
|
||||
metaData.emplace_back(nodes_);
|
||||
if (deliveredAmount_.has_value())
|
||||
metaData.setFieldAmount(sfDeliveredAmount, *deliveredAmount_);
|
||||
|
||||
if (hasParentBatchId())
|
||||
metaData.setFieldH256(sfParentBatchID, getParentBatchId());
|
||||
if (parentBatchID_.has_value())
|
||||
metaData.setFieldH256(sfParentBatchID, *parentBatchID_);
|
||||
|
||||
return metaData;
|
||||
}
|
||||
@@ -265,13 +236,13 @@ TxMeta::getAsObject() const
|
||||
void
|
||||
TxMeta::addRaw(Serializer& s, TER result, std::uint32_t index)
|
||||
{
|
||||
mResult = TERtoInt(result);
|
||||
mIndex = index;
|
||||
result_ = TERtoInt(result);
|
||||
index_ = index;
|
||||
XRPL_ASSERT(
|
||||
(mResult == 0) || ((mResult > 100) && (mResult <= 255)),
|
||||
(result_ == 0) || ((result_ > 100) && (result_ <= 255)),
|
||||
"ripple::TxMeta::addRaw : valid TER input");
|
||||
|
||||
mNodes.sort([](STObject const& o1, STObject const& o2) {
|
||||
nodes_.sort([](STObject const& o1, STObject const& o2) {
|
||||
return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex);
|
||||
});
|
||||
|
||||
|
||||
@@ -148,6 +148,12 @@ Consumer::entry()
|
||||
return *m_entry;
|
||||
}
|
||||
|
||||
void
|
||||
Consumer::setPublicKey(PublicKey const& publicKey)
|
||||
{
|
||||
m_entry->publicKey = publicKey;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, Consumer const& v)
|
||||
{
|
||||
|
||||
@@ -17,15 +17,14 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/shamap/SHAMap.h>
|
||||
#include <xrpld/shamap/SHAMapAccountStateLeafNode.h>
|
||||
#include <xrpld/shamap/SHAMapNodeID.h>
|
||||
#include <xrpld/shamap/SHAMapSyncFilter.h>
|
||||
#include <xrpld/shamap/SHAMapTxLeafNode.h>
|
||||
#include <xrpld/shamap/SHAMapTxPlusMetaLeafNode.h>
|
||||
|
||||
#include <xrpl/basics/TaggedCache.ipp>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/shamap/SHAMap.h>
|
||||
#include <xrpl/shamap/SHAMapAccountStateLeafNode.h>
|
||||
#include <xrpl/shamap/SHAMapNodeID.h>
|
||||
#include <xrpl/shamap/SHAMapSyncFilter.h>
|
||||
#include <xrpl/shamap/SHAMapTxLeafNode.h>
|
||||
#include <xrpl/shamap/SHAMapTxPlusMetaLeafNode.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -17,10 +17,9 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/shamap/SHAMap.h>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.ipp>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/shamap/SHAMap.h>
|
||||
|
||||
#include <array>
|
||||
#include <stack>
|
||||
@@ -17,16 +17,15 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/shamap/SHAMapInnerNode.h>
|
||||
#include <xrpld/shamap/SHAMapTreeNode.h>
|
||||
#include <xrpld/shamap/detail/TaggedPointer.ipp>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.ipp>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/basics/spinlock.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/shamap/SHAMapInnerNode.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
#include <xrpl/shamap/detail/TaggedPointer.ipp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/shamap/SHAMapLeafNode.h>
|
||||
#include <xrpl/shamap/SHAMapLeafNode.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -17,12 +17,11 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/shamap/SHAMap.h>
|
||||
#include <xrpld/shamap/SHAMapNodeID.h>
|
||||
|
||||
#include <xrpl/beast/core/LexicalCast.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/shamap/SHAMap.h>
|
||||
#include <xrpl/shamap/SHAMapNodeID.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/shamap/SHAMap.h>
|
||||
#include <xrpld/shamap/SHAMapSyncFilter.h>
|
||||
|
||||
#include <xrpl/basics/random.h>
|
||||
#include <xrpl/shamap/SHAMap.h>
|
||||
#include <xrpl/shamap/SHAMapLeafNode.h>
|
||||
#include <xrpl/shamap/SHAMapSyncFilter.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -591,16 +591,16 @@ SHAMap::addKnownNode(
|
||||
}
|
||||
|
||||
auto const generation = f_.getFullBelowCache()->getGeneration();
|
||||
SHAMapNodeID iNodeID;
|
||||
auto iNode = root_.get();
|
||||
SHAMapNodeID currNodeID;
|
||||
auto currNode = root_.get();
|
||||
|
||||
while (iNode->isInner() &&
|
||||
!static_cast<SHAMapInnerNode*>(iNode)->isFullBelow(generation) &&
|
||||
(iNodeID.getDepth() < node.getDepth()))
|
||||
while (currNode->isInner() &&
|
||||
!static_cast<SHAMapInnerNode*>(currNode)->isFullBelow(generation) &&
|
||||
(currNodeID.getDepth() < node.getDepth()))
|
||||
{
|
||||
int branch = selectBranch(iNodeID, node.getNodeID());
|
||||
int const branch = selectBranch(currNodeID, node.getNodeID());
|
||||
XRPL_ASSERT(branch >= 0, "ripple::SHAMap::addKnownNode : valid branch");
|
||||
auto inner = static_cast<SHAMapInnerNode*>(iNode);
|
||||
auto inner = static_cast<SHAMapInnerNode*>(currNode);
|
||||
if (inner->isEmptyBranch(branch))
|
||||
{
|
||||
JLOG(journal_.warn()) << "Add known node for empty branch" << node;
|
||||
@@ -614,58 +614,84 @@ SHAMap::addKnownNode(
|
||||
}
|
||||
|
||||
auto prevNode = inner;
|
||||
std::tie(iNode, iNodeID) = descend(inner, iNodeID, branch, filter);
|
||||
std::tie(currNode, currNodeID) =
|
||||
descend(inner, currNodeID, branch, filter);
|
||||
|
||||
if (iNode == nullptr)
|
||||
if (currNode != nullptr)
|
||||
continue;
|
||||
|
||||
auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
|
||||
|
||||
if (!newNode || childHash != newNode->getHash())
|
||||
{
|
||||
auto newNode = SHAMapTreeNode::makeFromWire(rawNode);
|
||||
JLOG(journal_.warn()) << "Corrupt node received";
|
||||
return SHAMapAddNode::invalid();
|
||||
}
|
||||
|
||||
if (!newNode || childHash != newNode->getHash())
|
||||
// In rare cases, a node can still be corrupt even after hash
|
||||
// validation. For leaf nodes, we perform an additional check to
|
||||
// ensure the node's position in the tree is consistent with its
|
||||
// content to prevent inconsistencies that could
|
||||
// propagate further down the line.
|
||||
if (newNode->isLeaf())
|
||||
{
|
||||
auto const& actualKey =
|
||||
static_cast<SHAMapLeafNode const*>(newNode.get())
|
||||
->peekItem()
|
||||
->key();
|
||||
|
||||
// Validate that this leaf belongs at the target position
|
||||
auto const expectedNodeID =
|
||||
SHAMapNodeID::createID(node.getDepth(), actualKey);
|
||||
if (expectedNodeID.getNodeID() != node.getNodeID())
|
||||
{
|
||||
JLOG(journal_.warn()) << "Corrupt node received";
|
||||
JLOG(journal_.debug())
|
||||
<< "Leaf node position mismatch: "
|
||||
<< "expected=" << expectedNodeID.getNodeID()
|
||||
<< ", actual=" << node.getNodeID();
|
||||
return SHAMapAddNode::invalid();
|
||||
}
|
||||
}
|
||||
|
||||
// Inner nodes must be at a level strictly less than 64
|
||||
// but leaf nodes (while notionally at level 64) can be
|
||||
// at any depth up to and including 64:
|
||||
if ((iNodeID.getDepth() > leafDepth) ||
|
||||
(newNode->isInner() && iNodeID.getDepth() == leafDepth))
|
||||
{
|
||||
// Map is provably invalid
|
||||
state_ = SHAMapState::Invalid;
|
||||
return SHAMapAddNode::useful();
|
||||
}
|
||||
|
||||
if (iNodeID != node)
|
||||
{
|
||||
// Either this node is broken or we didn't request it (yet)
|
||||
JLOG(journal_.warn()) << "unable to hook node " << node;
|
||||
JLOG(journal_.info()) << " stuck at " << iNodeID;
|
||||
JLOG(journal_.info()) << "got depth=" << node.getDepth()
|
||||
<< ", walked to= " << iNodeID.getDepth();
|
||||
return SHAMapAddNode::useful();
|
||||
}
|
||||
|
||||
if (backed_)
|
||||
canonicalize(childHash, newNode);
|
||||
|
||||
newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
|
||||
|
||||
if (filter)
|
||||
{
|
||||
Serializer s;
|
||||
newNode->serializeWithPrefix(s);
|
||||
filter->gotNode(
|
||||
false,
|
||||
childHash,
|
||||
ledgerSeq_,
|
||||
std::move(s.modData()),
|
||||
newNode->getType());
|
||||
}
|
||||
|
||||
// Inner nodes must be at a level strictly less than 64
|
||||
// but leaf nodes (while notionally at level 64) can be
|
||||
// at any depth up to and including 64:
|
||||
if ((currNodeID.getDepth() > leafDepth) ||
|
||||
(newNode->isInner() && currNodeID.getDepth() == leafDepth))
|
||||
{
|
||||
// Map is provably invalid
|
||||
state_ = SHAMapState::Invalid;
|
||||
return SHAMapAddNode::useful();
|
||||
}
|
||||
|
||||
if (currNodeID != node)
|
||||
{
|
||||
// Either this node is broken or we didn't request it (yet)
|
||||
JLOG(journal_.warn()) << "unable to hook node " << node;
|
||||
JLOG(journal_.info()) << " stuck at " << currNodeID;
|
||||
JLOG(journal_.info()) << "got depth=" << node.getDepth()
|
||||
<< ", walked to= " << currNodeID.getDepth();
|
||||
return SHAMapAddNode::useful();
|
||||
}
|
||||
|
||||
if (backed_)
|
||||
canonicalize(childHash, newNode);
|
||||
|
||||
newNode = prevNode->canonicalizeChild(branch, std::move(newNode));
|
||||
|
||||
if (filter)
|
||||
{
|
||||
Serializer s;
|
||||
newNode->serializeWithPrefix(s);
|
||||
filter->gotNode(
|
||||
false,
|
||||
childHash,
|
||||
ledgerSeq_,
|
||||
std::move(s.modData()),
|
||||
newNode->getType());
|
||||
}
|
||||
|
||||
return SHAMapAddNode::useful();
|
||||
}
|
||||
|
||||
JLOG(journal_.trace()) << "got node, already had it (late)";
|
||||
@@ -17,18 +17,17 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/shamap/SHAMapAccountStateLeafNode.h>
|
||||
#include <xrpld/shamap/SHAMapInnerNode.h>
|
||||
#include <xrpld/shamap/SHAMapTreeNode.h>
|
||||
#include <xrpld/shamap/SHAMapTxLeafNode.h>
|
||||
#include <xrpld/shamap/SHAMapTxPlusMetaLeafNode.h>
|
||||
|
||||
#include <xrpl/basics/IntrusivePointer.ipp>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/basics/safe_cast.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
#include <xrpl/shamap/SHAMapAccountStateLeafNode.h>
|
||||
#include <xrpl/shamap/SHAMapInnerNode.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
#include <xrpl/shamap/SHAMapTxLeafNode.h>
|
||||
#include <xrpl/shamap/SHAMapTxPlusMetaLeafNode.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -198,109 +198,100 @@ private:
|
||||
// Fill or Kill - unless we fully cross, just charge a fee and don't
|
||||
// place the offer on the books. But also clean up expired offers
|
||||
// that are discovered along the way.
|
||||
//
|
||||
// fix1578 changes the return code. Verify expected behavior
|
||||
// without and with fix1578.
|
||||
for (auto const& tweakedFeatures :
|
||||
{features - fix1578, features | fix1578})
|
||||
{
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
// Order that can't be filled
|
||||
TER const killedCode{
|
||||
tweakedFeatures[fix1578] ? TER{tecKILLED}
|
||||
: TER{tesSUCCESS}};
|
||||
env(offer(carol, USD(100), XRP(100)),
|
||||
txflags(tfFillOrKill),
|
||||
ter(killedCode));
|
||||
env.close();
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'100), USD(10'000), ammAlice.tokens()));
|
||||
// fee = AMM
|
||||
BEAST_EXPECT(expectLedgerEntryRoot(
|
||||
env, carol, XRP(30'000) - (txfee(env, 1))));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 0));
|
||||
BEAST_EXPECT(expectHolding(env, carol, USD(30'000)));
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
// Order that can't be filled
|
||||
TER const killedCode{TER{tecKILLED}};
|
||||
env(offer(carol, USD(100), XRP(100)),
|
||||
txflags(tfFillOrKill),
|
||||
ter(killedCode));
|
||||
env.close();
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'100), USD(10'000), ammAlice.tokens()));
|
||||
// fee = AMM
|
||||
BEAST_EXPECT(expectLedgerEntryRoot(
|
||||
env, carol, XRP(30'000) - (txfee(env, 1))));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 0));
|
||||
BEAST_EXPECT(expectHolding(env, carol, USD(30'000)));
|
||||
|
||||
// Order that can be filled
|
||||
env(offer(carol, XRP(100), USD(100)),
|
||||
txflags(tfFillOrKill),
|
||||
ter(tesSUCCESS));
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'000), USD(10'100), ammAlice.tokens()));
|
||||
BEAST_EXPECT(expectLedgerEntryRoot(
|
||||
env, carol, XRP(30'000) + XRP(100) - txfee(env, 2)));
|
||||
BEAST_EXPECT(expectHolding(env, carol, USD(29'900)));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 0));
|
||||
},
|
||||
{{XRP(10'100), USD(10'000)}},
|
||||
0,
|
||||
std::nullopt,
|
||||
{tweakedFeatures});
|
||||
// Order that can be filled
|
||||
env(offer(carol, XRP(100), USD(100)),
|
||||
txflags(tfFillOrKill),
|
||||
ter(tesSUCCESS));
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'000), USD(10'100), ammAlice.tokens()));
|
||||
BEAST_EXPECT(expectLedgerEntryRoot(
|
||||
env, carol, XRP(30'000) + XRP(100) - txfee(env, 2)));
|
||||
BEAST_EXPECT(expectHolding(env, carol, USD(29'900)));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 0));
|
||||
},
|
||||
{{XRP(10'100), USD(10'000)}},
|
||||
0,
|
||||
std::nullopt,
|
||||
{features});
|
||||
|
||||
// Immediate or Cancel - cross as much as possible
|
||||
// and add nothing on the books.
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
env(offer(carol, XRP(200), USD(200)),
|
||||
txflags(tfImmediateOrCancel),
|
||||
ter(tesSUCCESS));
|
||||
// Immediate or Cancel - cross as much as possible
|
||||
// and add nothing on the books.
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
env(offer(carol, XRP(200), USD(200)),
|
||||
txflags(tfImmediateOrCancel),
|
||||
ter(tesSUCCESS));
|
||||
|
||||
// AMM generates a synthetic offer of 100USD/100XRP
|
||||
// to match the CLOB offer quality.
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'000), USD(10'100), ammAlice.tokens()));
|
||||
// +AMM - offer * fee
|
||||
BEAST_EXPECT(expectLedgerEntryRoot(
|
||||
env, carol, XRP(30'000) + XRP(100) - txfee(env, 1)));
|
||||
// AMM
|
||||
BEAST_EXPECT(expectHolding(env, carol, USD(29'900)));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 0));
|
||||
},
|
||||
{{XRP(10'100), USD(10'000)}},
|
||||
0,
|
||||
std::nullopt,
|
||||
{tweakedFeatures});
|
||||
// AMM generates a synthetic offer of 100USD/100XRP
|
||||
// to match the CLOB offer quality.
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'000), USD(10'100), ammAlice.tokens()));
|
||||
// +AMM - offer * fee
|
||||
BEAST_EXPECT(expectLedgerEntryRoot(
|
||||
env, carol, XRP(30'000) + XRP(100) - txfee(env, 1)));
|
||||
// AMM
|
||||
BEAST_EXPECT(expectHolding(env, carol, USD(29'900)));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 0));
|
||||
},
|
||||
{{XRP(10'100), USD(10'000)}},
|
||||
0,
|
||||
std::nullopt,
|
||||
{features});
|
||||
|
||||
// tfPassive -- place the offer without crossing it.
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
// Carol creates a passive offer that could cross AMM.
|
||||
// Carol's offer should stay in the ledger.
|
||||
env(offer(carol, XRP(100), USD(100), tfPassive));
|
||||
env.close();
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'100), STAmount{USD, 10'000}, ammAlice.tokens()));
|
||||
BEAST_EXPECT(expectOffers(
|
||||
env, carol, 1, {{{XRP(100), STAmount{USD, 100}}}}));
|
||||
},
|
||||
{{XRP(10'100), USD(10'000)}},
|
||||
0,
|
||||
std::nullopt,
|
||||
{tweakedFeatures});
|
||||
// tfPassive -- place the offer without crossing it.
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
// Carol creates a passive offer that could cross AMM.
|
||||
// Carol's offer should stay in the ledger.
|
||||
env(offer(carol, XRP(100), USD(100), tfPassive));
|
||||
env.close();
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'100), STAmount{USD, 10'000}, ammAlice.tokens()));
|
||||
BEAST_EXPECT(expectOffers(
|
||||
env, carol, 1, {{{XRP(100), STAmount{USD, 100}}}}));
|
||||
},
|
||||
{{XRP(10'100), USD(10'000)}},
|
||||
0,
|
||||
std::nullopt,
|
||||
{features});
|
||||
|
||||
// tfPassive -- cross only offers of better quality.
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
env(offer(alice, USD(110), XRP(100)));
|
||||
env.close();
|
||||
// tfPassive -- cross only offers of better quality.
|
||||
testAMM(
|
||||
[&](AMM& ammAlice, Env& env) {
|
||||
env(offer(alice, USD(110), XRP(100)));
|
||||
env.close();
|
||||
|
||||
// Carol creates a passive offer. That offer should cross
|
||||
// AMM and leave Alice's offer untouched.
|
||||
env(offer(carol, XRP(100), USD(100), tfPassive));
|
||||
env.close();
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'900),
|
||||
STAmount{USD, UINT64_C(9'082'56880733945), -11},
|
||||
ammAlice.tokens()));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 0));
|
||||
BEAST_EXPECT(expectOffers(env, alice, 1));
|
||||
},
|
||||
{{XRP(11'000), USD(9'000)}},
|
||||
0,
|
||||
std::nullopt,
|
||||
{tweakedFeatures});
|
||||
}
|
||||
// Carol creates a passive offer. That offer should cross
|
||||
// AMM and leave Alice's offer untouched.
|
||||
env(offer(carol, XRP(100), USD(100), tfPassive));
|
||||
env.close();
|
||||
BEAST_EXPECT(ammAlice.expectBalances(
|
||||
XRP(10'900),
|
||||
STAmount{USD, UINT64_C(9'082'56880733945), -11},
|
||||
ammAlice.tokens()));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 0));
|
||||
BEAST_EXPECT(expectOffers(env, alice, 1));
|
||||
},
|
||||
{{XRP(11'000), USD(9'000)}},
|
||||
0,
|
||||
std::nullopt,
|
||||
{features});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -867,8 +858,7 @@ private:
|
||||
using namespace jtx;
|
||||
|
||||
// Code returned if an offer is killed.
|
||||
TER const killedCode{
|
||||
features[fix1578] ? TER{tecKILLED} : TER{tesSUCCESS}};
|
||||
TER const killedCode{TER{tecKILLED}};
|
||||
|
||||
{
|
||||
Env env{*this, features};
|
||||
@@ -2819,15 +2809,9 @@ private:
|
||||
testcase("Circular XRP");
|
||||
|
||||
using namespace jtx;
|
||||
|
||||
for (auto const withFix : {true, false})
|
||||
{
|
||||
auto const feats = withFix
|
||||
? testable_amendments()
|
||||
: testable_amendments() - FeatureBitset{fix1781};
|
||||
|
||||
// Payment path starting with XRP
|
||||
Env env(*this, feats);
|
||||
Env env(*this, testable_amendments());
|
||||
// Note, if alice doesn't have default ripple, then pay
|
||||
// fails with tecPATH_DRY.
|
||||
fund(
|
||||
@@ -2842,8 +2826,7 @@ private:
|
||||
AMM ammAliceXRP_EUR(env, alice, XRP(100), EUR(101));
|
||||
env.close();
|
||||
|
||||
TER const expectedTer =
|
||||
withFix ? TER{temBAD_PATH_LOOP} : TER{tesSUCCESS};
|
||||
TER const expectedTer = TER{temBAD_PATH_LOOP};
|
||||
env(pay(alice, bob, EUR(1)),
|
||||
path(~USD, ~XRP, ~EUR),
|
||||
sendmax(XRP(1)),
|
||||
|
||||
@@ -545,8 +545,7 @@ public:
|
||||
|
||||
for (auto const& [hash, nVotes] : votes)
|
||||
{
|
||||
if (rules.enabled(fixAmendmentMajorityCalc) ? nVotes >= i
|
||||
: nVotes > i)
|
||||
if (nVotes >= i)
|
||||
{
|
||||
// We vote yes on this amendment
|
||||
field.push_back(hash);
|
||||
@@ -982,10 +981,6 @@ public:
|
||||
void
|
||||
testChangedUNL(FeatureBitset const& feat)
|
||||
{
|
||||
// This test doesn't work without fixAmendmentMajorityCalc enabled.
|
||||
if (!feat[fixAmendmentMajorityCalc])
|
||||
return;
|
||||
|
||||
testcase("changedUNL");
|
||||
|
||||
auto const testAmendment = amendmentId("changedUNL");
|
||||
@@ -1143,10 +1138,6 @@ public:
|
||||
void
|
||||
testValidatorFlapping(FeatureBitset const& feat)
|
||||
{
|
||||
// This test doesn't work without fixAmendmentMajorityCalc enabled.
|
||||
if (!feat[fixAmendmentMajorityCalc])
|
||||
return;
|
||||
|
||||
testcase("validatorFlapping");
|
||||
|
||||
// We run a test where a validator flaps on and off every 23 hours
|
||||
@@ -1289,14 +1280,12 @@ public:
|
||||
run() override
|
||||
{
|
||||
FeatureBitset const all{test::jtx::testable_amendments()};
|
||||
FeatureBitset const fixMajorityCalc{fixAmendmentMajorityCalc};
|
||||
|
||||
testConstruct();
|
||||
testGet();
|
||||
testBadConfig();
|
||||
testEnableVeto();
|
||||
testHasUnsupported();
|
||||
testFeature(all - fixMajorityCalc);
|
||||
testFeature(all);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3946,14 +3946,13 @@ class Batch_test : public beast::unit_test::suite
|
||||
tesSUCCESS,
|
||||
batch::outer(gw, seq, batchFee, tfIndependent),
|
||||
batch::inner(jv1, seq + 1),
|
||||
// tecNO_DELEGATE_PERMISSION: not authorized to clear freeze
|
||||
// terNO_DELEGATE_PERMISSION: not authorized to clear freeze
|
||||
batch::inner(jv2, seq + 2));
|
||||
env.close();
|
||||
|
||||
std::vector<TestLedgerData> testCases = {
|
||||
{0, "Batch", "tesSUCCESS", batchID, std::nullopt},
|
||||
{1, "TrustSet", "tesSUCCESS", txIDs[0], batchID},
|
||||
{2, "TrustSet", "tecNO_DELEGATE_PERMISSION", txIDs[1], batchID},
|
||||
};
|
||||
validateClosedLedger(env, testCases);
|
||||
}
|
||||
|
||||
@@ -1867,49 +1867,35 @@ class Check_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
void
|
||||
testFix1623Enable(FeatureBitset features)
|
||||
testDeliveredAmountForCheckCashTxn(FeatureBitset features)
|
||||
{
|
||||
testcase("Fix1623 enable");
|
||||
testcase("DeliveredAmount For CheckCash Txn");
|
||||
|
||||
using namespace test::jtx;
|
||||
Account const alice{"alice"};
|
||||
Account const bob{"bob"};
|
||||
|
||||
auto testEnable = [this](
|
||||
FeatureBitset const& features, bool hasFields) {
|
||||
// Unless fix1623 is enabled a "tx" RPC command should return
|
||||
// neither "DeliveredAmount" nor "delivered_amount" on a CheckCash
|
||||
// transaction.
|
||||
Account const alice{"alice"};
|
||||
Account const bob{"bob"};
|
||||
Env env{*this, features};
|
||||
|
||||
Env env{*this, features};
|
||||
env.fund(XRP(1000), alice, bob);
|
||||
env.close();
|
||||
|
||||
env.fund(XRP(1000), alice, bob);
|
||||
env.close();
|
||||
uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
|
||||
env(check::create(alice, bob, XRP(200)));
|
||||
env.close();
|
||||
|
||||
uint256 const chkId{getCheckIndex(alice, env.seq(alice))};
|
||||
env(check::create(alice, bob, XRP(200)));
|
||||
env.close();
|
||||
env(check::cash(bob, chkId, check::DeliverMin(XRP(100))));
|
||||
|
||||
env(check::cash(bob, chkId, check::DeliverMin(XRP(100))));
|
||||
// Get the hash for the most recent transaction.
|
||||
std::string const txHash{
|
||||
env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
|
||||
|
||||
// Get the hash for the most recent transaction.
|
||||
std::string const txHash{
|
||||
env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
|
||||
env.close();
|
||||
Json::Value const meta = env.rpc("tx", txHash)[jss::result][jss::meta];
|
||||
|
||||
// DeliveredAmount and delivered_amount are either present or
|
||||
// not present in the metadata returned by "tx" based on fix1623.
|
||||
env.close();
|
||||
Json::Value const meta =
|
||||
env.rpc("tx", txHash)[jss::result][jss::meta];
|
||||
|
||||
BEAST_EXPECT(
|
||||
meta.isMember(sfDeliveredAmount.jsonName) == hasFields);
|
||||
BEAST_EXPECT(meta.isMember(jss::delivered_amount) == hasFields);
|
||||
};
|
||||
|
||||
// Run both the disabled and enabled cases.
|
||||
testEnable(features - fix1623, false);
|
||||
testEnable(features, true);
|
||||
// DeliveredAmount and delivered_amount are present.
|
||||
BEAST_EXPECT(meta.isMember(sfDeliveredAmount.jsonName));
|
||||
BEAST_EXPECT(meta.isMember(jss::delivered_amount));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2711,7 +2697,7 @@ class Check_test : public beast::unit_test::suite
|
||||
testCashInvalid(features);
|
||||
testCancelValid(features);
|
||||
testCancelInvalid(features);
|
||||
testFix1623Enable(features);
|
||||
testDeliveredAmountForCheckCashTxn(features);
|
||||
testWithTickets(features);
|
||||
}
|
||||
|
||||
|
||||
@@ -558,6 +558,39 @@ struct Credentials_test : public beast::unit_test::suite
|
||||
jle[jss::result][jss::node]["CredentialType"] ==
|
||||
strHex(std::string_view(credType)));
|
||||
}
|
||||
|
||||
{
|
||||
testcase("Credentials fail, directory full");
|
||||
std::uint32_t const issuerSeq{env.seq(issuer) + 1};
|
||||
env(ticket::create(issuer, 63));
|
||||
env.close();
|
||||
|
||||
// Everything below can only be tested on open ledger.
|
||||
auto const res1 = directory::bumpLastPage(
|
||||
env,
|
||||
directory::maximumPageIndex(env),
|
||||
keylet::ownerDir(issuer.id()),
|
||||
directory::adjustOwnerNode);
|
||||
BEAST_EXPECT(res1);
|
||||
|
||||
auto const jv = credentials::create(issuer, subject, credType);
|
||||
env(jv, ter(tecDIR_FULL));
|
||||
// Free one directory entry by using a ticket
|
||||
env(noop(issuer), ticket::use(issuerSeq + 40));
|
||||
|
||||
// Fill subject directory
|
||||
env(ticket::create(subject, 63));
|
||||
auto const res2 = directory::bumpLastPage(
|
||||
env,
|
||||
directory::maximumPageIndex(env),
|
||||
keylet::ownerDir(subject.id()),
|
||||
directory::adjustOwnerNode);
|
||||
BEAST_EXPECT(res2);
|
||||
env(jv, ter(tecDIR_FULL));
|
||||
|
||||
// End test
|
||||
env.close();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1084,6 +1117,7 @@ struct Credentials_test : public beast::unit_test::suite
|
||||
testSuccessful(all);
|
||||
testCredentialsDelete(all);
|
||||
testCreateFailed(all);
|
||||
testCreateFailed(all - fixDirectoryLimit);
|
||||
testAcceptFailed(all);
|
||||
testDeleteFailed(all);
|
||||
testFeatureFailed(all - featureCredentials);
|
||||
|
||||
@@ -27,23 +27,27 @@ namespace test {
|
||||
class Delegate_test : public beast::unit_test::suite
|
||||
{
|
||||
void
|
||||
testFeatureDisabled()
|
||||
testFeatureDisabled(FeatureBitset features)
|
||||
{
|
||||
testcase("test featurePermissionDelegation not enabled");
|
||||
testcase("test feature not enabled");
|
||||
using namespace jtx;
|
||||
|
||||
Env env{*this, testable_amendments() - featurePermissionDelegation};
|
||||
Env env{*this, features};
|
||||
Account gw{"gateway"};
|
||||
Account alice{"alice"};
|
||||
Account bob{"bob"};
|
||||
env.fund(XRP(1000000), gw, alice, bob);
|
||||
env.close();
|
||||
|
||||
auto res = features[featurePermissionDelegationV1_1] ? ter(tesSUCCESS)
|
||||
: ter(temDISABLED);
|
||||
|
||||
// can not set Delegate when feature disabled
|
||||
env(delegate::set(gw, alice, {"Payment"}), ter(temDISABLED));
|
||||
env(delegate::set(gw, alice, {"Payment"}), res);
|
||||
env.close();
|
||||
|
||||
// can not send delegating transaction when feature disabled
|
||||
env(pay(alice, bob, XRP(100)), delegate::as(bob), ter(temDISABLED));
|
||||
env(pay(gw, bob, XRP(100)), delegate::as(alice), res);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -217,17 +221,16 @@ class Delegate_test : public beast::unit_test::suite
|
||||
}
|
||||
|
||||
// non-delegatable transaction
|
||||
auto const res = features[fixDelegateV1_1] ? ter(temMALFORMED)
|
||||
: ter(tecNO_PERMISSION);
|
||||
{
|
||||
env(delegate::set(gw, alice, {"SetRegularKey"}), res);
|
||||
env(delegate::set(gw, alice, {"AccountSet"}), res);
|
||||
env(delegate::set(gw, alice, {"SignerListSet"}), res);
|
||||
env(delegate::set(gw, alice, {"DelegateSet"}), res);
|
||||
env(delegate::set(gw, alice, {"EnableAmendment"}), res);
|
||||
env(delegate::set(gw, alice, {"UNLModify"}), res);
|
||||
env(delegate::set(gw, alice, {"SetFee"}), res);
|
||||
env(delegate::set(gw, alice, {"Batch"}), res);
|
||||
env(delegate::set(gw, alice, {"SetRegularKey"}), ter(temMALFORMED));
|
||||
env(delegate::set(gw, alice, {"AccountSet"}), ter(temMALFORMED));
|
||||
env(delegate::set(gw, alice, {"SignerListSet"}), ter(temMALFORMED));
|
||||
env(delegate::set(gw, alice, {"DelegateSet"}), ter(temMALFORMED));
|
||||
env(delegate::set(gw, alice, {"EnableAmendment"}),
|
||||
ter(temMALFORMED));
|
||||
env(delegate::set(gw, alice, {"UNLModify"}), ter(temMALFORMED));
|
||||
env(delegate::set(gw, alice, {"SetFee"}), ter(temMALFORMED));
|
||||
env(delegate::set(gw, alice, {"Batch"}), ter(temMALFORMED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,10 +308,6 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env.close();
|
||||
|
||||
{
|
||||
// Fee should be checked before permission check,
|
||||
// otherwise tecNO_DELEGATE_PERMISSION returned when permission
|
||||
// check fails could cause context reset to pay fee because it is
|
||||
// tec error
|
||||
auto aliceBalance = env.balance(alice);
|
||||
auto bobBalance = env.balance(bob);
|
||||
auto carolBalance = env.balance(carol);
|
||||
@@ -316,7 +315,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(pay(alice, carol, XRP(100)),
|
||||
fee(XRP(2000)),
|
||||
delegate::as(bob),
|
||||
ter(terINSUF_FEE_B));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
||||
@@ -523,12 +522,12 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// bob does not have permission to create check
|
||||
env(check::create(alice, bob, XRP(10)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// carol does not have permission to create check
|
||||
env(check::create(alice, bob, XRP(10)),
|
||||
delegate::as(carol),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -563,9 +562,8 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// delegate ledger object is not created yet
|
||||
env(pay(gw, alice, USD(50)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
env.require(balance(bob, bobBalance - drops(baseFee)));
|
||||
bobBalance = env.balance(bob, XRP);
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.require(balance(bob, bobBalance));
|
||||
|
||||
// gw gives bob burn permission
|
||||
env(delegate::set(gw, bob, {"PaymentBurn"}));
|
||||
@@ -576,10 +574,9 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// bob sends a payment transaction on behalf of gw
|
||||
env(pay(gw, alice, USD(50)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
env.require(balance(bob, bobBalance - drops(baseFee)));
|
||||
bobBalance = env.balance(bob, XRP);
|
||||
env.require(balance(bob, bobBalance));
|
||||
|
||||
// gw gives bob mint permission, alice gives bob burn permission
|
||||
env(delegate::set(gw, bob, {"PaymentMint"}));
|
||||
@@ -593,10 +590,9 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// can not send XRP
|
||||
env(pay(gw, alice, XRP(50)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
env.require(balance(bob, bobBalance - drops(baseFee)));
|
||||
bobBalance = env.balance(bob, XRP);
|
||||
env.require(balance(bob, bobBalance));
|
||||
|
||||
// mint 50 USD
|
||||
env(pay(gw, alice, USD(50)), delegate::as(bob));
|
||||
@@ -681,10 +677,9 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// permission
|
||||
env(pay(gw, alice, USD(50)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
env.require(balance(bob, bobBalance - drops(baseFee)));
|
||||
bobBalance = env.balance(bob, XRP);
|
||||
env.require(balance(bob, bobBalance));
|
||||
|
||||
// gw gives bob Payment permission as well
|
||||
env(delegate::set(gw, bob, {"PaymentBurn", "Payment"}));
|
||||
@@ -723,11 +718,6 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(pay(gw, carol, USD(10000)));
|
||||
env.close();
|
||||
|
||||
auto const result = features[fixDelegateV1_1]
|
||||
? static_cast<TER>(tecNO_DELEGATE_PERMISSION)
|
||||
: static_cast<TER>(tesSUCCESS);
|
||||
auto const offerCount = features[fixDelegateV1_1] ? 1 : 0;
|
||||
|
||||
// PaymentMint
|
||||
{
|
||||
env(offer(carol, XRP(100), USD(501)));
|
||||
@@ -735,16 +725,21 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(delegate::set(gw, bob, {"PaymentMint"}));
|
||||
env.close();
|
||||
|
||||
// post-amendment: fixDelegateV1_1
|
||||
// bob can not send cross currency payment on behalf of the gw,
|
||||
// even with PaymentMint permission and gw being the issuer.
|
||||
env(pay(gw, alice, USD(5000)),
|
||||
path(~USD),
|
||||
sendmax(XRP(1001)),
|
||||
txflags(tfPartialPayment),
|
||||
delegate::as(bob),
|
||||
ter(result));
|
||||
BEAST_EXPECT(expectOffers(env, carol, offerCount));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 1));
|
||||
|
||||
env(pay(gw, alice, USD(5000)),
|
||||
path(~XRP),
|
||||
txflags(tfPartialPayment),
|
||||
delegate::as(bob),
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
BEAST_EXPECT(expectOffers(env, carol, 1));
|
||||
|
||||
// succeed with direct payment
|
||||
env(pay(gw, alice, USD(100)), delegate::as(bob));
|
||||
@@ -758,16 +753,21 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(delegate::set(alice, bob, {"PaymentBurn"}));
|
||||
env.close();
|
||||
|
||||
// post-amendment: fixDelegateV1_1
|
||||
// bob can not send cross currency payment on behalf of alice,
|
||||
// even with PaymentBurn permission and gw being the issuer.
|
||||
env(pay(alice, gw, USD(5000)),
|
||||
path(~USD),
|
||||
sendmax(XRP(1001)),
|
||||
txflags(tfPartialPayment),
|
||||
delegate::as(bob),
|
||||
ter(result));
|
||||
BEAST_EXPECT(expectOffers(env, bob, offerCount));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
BEAST_EXPECT(expectOffers(env, bob, 1));
|
||||
|
||||
env(pay(alice, gw, USD(5000)),
|
||||
path(~XRP),
|
||||
txflags(tfPartialPayment),
|
||||
delegate::as(bob),
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
BEAST_EXPECT(expectOffers(env, bob, 1));
|
||||
|
||||
// succeed with direct payment
|
||||
env(pay(alice, gw, USD(100)), delegate::as(bob));
|
||||
@@ -802,20 +802,10 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(delegate::set(gw, bob, {"PaymentMint"}));
|
||||
env.close();
|
||||
|
||||
if (!features[fixDelegateV1_1])
|
||||
{
|
||||
// pre-amendment: PaymentMint is not supported for MPT
|
||||
env(pay(gw, alice, MPT(50)),
|
||||
delegate::as(bob),
|
||||
ter(tefEXCEPTION));
|
||||
}
|
||||
else
|
||||
{
|
||||
env(pay(gw, alice, MPT(50)), delegate::as(bob));
|
||||
BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT + MPT(50));
|
||||
BEAST_EXPECT(env.balance(bob, MPT) == bobMPT);
|
||||
aliceMPT = env.balance(alice, MPT);
|
||||
}
|
||||
env(pay(gw, alice, MPT(50)), delegate::as(bob));
|
||||
BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT + MPT(50));
|
||||
BEAST_EXPECT(env.balance(bob, MPT) == bobMPT);
|
||||
aliceMPT = env.balance(alice, MPT);
|
||||
}
|
||||
|
||||
// PaymentBurn
|
||||
@@ -823,24 +813,13 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(delegate::set(alice, bob, {"PaymentBurn"}));
|
||||
env.close();
|
||||
|
||||
if (!features[fixDelegateV1_1])
|
||||
{
|
||||
// pre-amendment: PaymentBurn is not supported for MPT
|
||||
env(pay(alice, gw, MPT(50)),
|
||||
delegate::as(bob),
|
||||
ter(tefEXCEPTION));
|
||||
}
|
||||
else
|
||||
{
|
||||
env(pay(alice, gw, MPT(50)), delegate::as(bob));
|
||||
BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT - MPT(50));
|
||||
BEAST_EXPECT(env.balance(bob, MPT) == bobMPT);
|
||||
aliceMPT = env.balance(alice, MPT);
|
||||
}
|
||||
env(pay(alice, gw, MPT(50)), delegate::as(bob));
|
||||
BEAST_EXPECT(env.balance(alice, MPT) == aliceMPT - MPT(50));
|
||||
BEAST_EXPECT(env.balance(bob, MPT) == bobMPT);
|
||||
aliceMPT = env.balance(alice, MPT);
|
||||
}
|
||||
|
||||
// Payment transaction for MPT is allowed for both pre and post
|
||||
// amendment
|
||||
// Grant both granular permissions and tx level permission.
|
||||
{
|
||||
env(delegate::set(
|
||||
alice, bob, {"PaymentBurn", "PaymentMint", "Payment"}));
|
||||
@@ -878,7 +857,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// has unfreeze permission
|
||||
env(trust(alice, gw["USD"](50)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
|
||||
// alice creates trustline by herself
|
||||
@@ -892,38 +871,38 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// unsupported flags
|
||||
env(trust(alice, gw["USD"](50), tfSetNoRipple),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env(trust(alice, gw["USD"](50), tfClearNoRipple),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env(trust(gw, gw["USD"](0), alice, tfSetDeepFreeze),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env(trust(gw, gw["USD"](0), alice, tfClearDeepFreeze),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
|
||||
// supported flags with wrong permission
|
||||
env(trust(gw, gw["USD"](0), alice, tfSetfAuth),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env(trust(gw, gw["USD"](0), alice, tfSetFreeze),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
|
||||
env(delegate::set(gw, bob, {"TrustlineAuthorize"}));
|
||||
env.close();
|
||||
env(trust(gw, gw["USD"](0), alice, tfClearFreeze),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
// although trustline authorize is granted, bob can not change the
|
||||
// limit number
|
||||
env(trust(gw, gw["USD"](50), alice, tfSetfAuth),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
|
||||
// supported flags with correct permission
|
||||
@@ -944,30 +923,30 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// permission
|
||||
env(trust(gw, gw["USD"](0), alice, tfSetFreeze),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// cannot update LimitAmount with granular permission, both high and
|
||||
// low account
|
||||
env(trust(alice, gw["USD"](100)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env(trust(gw, alice["USD"](100)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// can not set QualityIn or QualityOut
|
||||
auto tx = trust(alice, gw["USD"](50));
|
||||
tx["QualityIn"] = "1000";
|
||||
env(tx, delegate::as(bob), ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(tx, delegate::as(bob), ter(terNO_DELEGATE_PERMISSION));
|
||||
auto tx2 = trust(alice, gw["USD"](50));
|
||||
tx2["QualityOut"] = "1000";
|
||||
env(tx2, delegate::as(bob), ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(tx2, delegate::as(bob), ter(terNO_DELEGATE_PERMISSION));
|
||||
auto tx3 = trust(gw, alice["USD"](50));
|
||||
tx3["QualityIn"] = "1000";
|
||||
env(tx3, delegate::as(bob), ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(tx3, delegate::as(bob), ter(terNO_DELEGATE_PERMISSION));
|
||||
auto tx4 = trust(gw, alice["USD"](50));
|
||||
tx4["QualityOut"] = "1000";
|
||||
env(tx4, delegate::as(bob), ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(tx4, delegate::as(bob), ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// granting TrustSet can make it work
|
||||
env(delegate::set(gw, bob, {"TrustSet"}));
|
||||
@@ -977,7 +956,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(tx5, delegate::as(bob));
|
||||
auto tx6 = trust(alice, gw["USD"](50));
|
||||
tx6["QualityOut"] = "1000";
|
||||
env(tx6, delegate::as(bob), ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(tx6, delegate::as(bob), ter(terNO_DELEGATE_PERMISSION));
|
||||
env(delegate::set(alice, bob, {"TrustSet"}));
|
||||
env.close();
|
||||
env(tx6, delegate::as(bob));
|
||||
@@ -996,14 +975,14 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// bob does not have permission
|
||||
env(trust(alice, gw["USD"](50)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env(delegate::set(
|
||||
alice, bob, {"TrustlineUnfreeze", "NFTokenCreateOffer"}));
|
||||
env.close();
|
||||
// bob still does not have permission
|
||||
env(trust(alice, gw["USD"](50)),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// add TrustSet permission and some unrelated permission
|
||||
env(delegate::set(
|
||||
@@ -1096,7 +1075,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(delegate::set(
|
||||
alice, bob, {"TrustlineUnfreeze", "AccountEmailHashSet"}));
|
||||
env.close();
|
||||
env(jt, ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(jt, ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// alice give granular permission of AccountDomainSet to bob
|
||||
env(delegate::set(alice, bob, {"AccountDomainSet"}));
|
||||
@@ -1115,7 +1094,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
std::string const failDomain = "fail_domain_update";
|
||||
jt[sfFlags] = tfRequireAuth;
|
||||
jt[sfDomain] = strHex(failDomain);
|
||||
env(jt, ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(jt, ter(terNO_DELEGATE_PERMISSION));
|
||||
// reset flag number
|
||||
jt[sfFlags] = 0;
|
||||
|
||||
@@ -1124,7 +1103,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
jt[sfDomain] = strHex(domain);
|
||||
std::string const mh("5F31A79367DC3137FADA860C05742EE6");
|
||||
jt[sfEmailHash] = mh;
|
||||
env(jt, ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(jt, ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// alice give granular permission of AccountEmailHashSet to bob
|
||||
env(delegate::set(
|
||||
@@ -1137,7 +1116,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// bob does not have permission to set message key for alice
|
||||
auto const rkp = randomKeyPair(KeyType::ed25519);
|
||||
jt[sfMessageKey] = strHex(rkp.first.slice());
|
||||
env(jt, ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(jt, ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// alice give granular permission of AccountMessageKeySet to bob
|
||||
env(delegate::set(
|
||||
@@ -1160,7 +1139,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// bob does not have permission to set transfer rate for alice
|
||||
env(rate(alice, 2.0),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// alice give granular permission of AccountTransferRateSet to bob
|
||||
env(delegate::set(
|
||||
@@ -1178,7 +1157,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
|
||||
// bob does not have permission to set ticksize for alice
|
||||
jt[sfTickSize] = 8;
|
||||
env(jt, ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(jt, ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// alice give granular permission of AccountTickSizeSet to bob
|
||||
env(delegate::set(
|
||||
@@ -1196,7 +1175,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// can not set asfRequireAuth flag for alice
|
||||
env(fset(alice, asfRequireAuth),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// reset Delegate will delete the Delegate
|
||||
// object
|
||||
@@ -1205,7 +1184,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// alice
|
||||
env(fset(alice, asfRequireAuth),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
// alice can set for herself
|
||||
env(fset(alice, asfRequireAuth));
|
||||
env.require(flags(alice, asfRequireAuth));
|
||||
@@ -1213,7 +1192,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
|
||||
// can not update tick size because bob no longer has permission
|
||||
jt[sfTickSize] = 7;
|
||||
env(jt, ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(jt, ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
env(delegate::set(
|
||||
alice,
|
||||
@@ -1231,7 +1210,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
jv2[sfDomain] = strHex(domain);
|
||||
jv2[sfDelegate] = bob.human();
|
||||
jv2[sfWalletLocator] = locator;
|
||||
env(jv2, ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(jv2, ter(terNO_DELEGATE_PERMISSION));
|
||||
}
|
||||
|
||||
// can not set AccountSet flags on behalf of other account
|
||||
@@ -1246,7 +1225,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// bob can not set flag on behalf of alice
|
||||
env(fset(alice, flag),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
// alice set by herself
|
||||
env(fset(alice, flag));
|
||||
env.close();
|
||||
@@ -1254,7 +1233,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// bob can not clear on behalf of alice
|
||||
env(fclear(alice, flag),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
};
|
||||
|
||||
// testSetClearFlag(asfNoFreeze);
|
||||
@@ -1283,19 +1262,19 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// bob can not set asfAccountTxnID on behalf of alice
|
||||
env(fset(alice, asfAccountTxnID),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env(fset(alice, asfAccountTxnID));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.le(alice)->isFieldPresent(sfAccountTxnID));
|
||||
env(fclear(alice, asfAccountTxnID),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// bob can not set asfAuthorizedNFTokenMinter on behalf of alice
|
||||
Json::Value jt = fset(alice, asfAuthorizedNFTokenMinter);
|
||||
jt[sfDelegate] = bob.human();
|
||||
jt[sfNFTokenMinter] = bob.human();
|
||||
env(jt, ter(tecNO_DELEGATE_PERMISSION));
|
||||
env(jt, ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// bob gives alice some permissions
|
||||
env(delegate::set(
|
||||
@@ -1311,14 +1290,14 @@ class Delegate_test : public beast::unit_test::suite
|
||||
// behalf of bob.
|
||||
env(fset(alice, asfNoFreeze),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env(fset(bob, asfNoFreeze));
|
||||
env.close();
|
||||
env.require(flags(bob, asfNoFreeze));
|
||||
// alice can not clear on behalf of bob
|
||||
env(fclear(alice, asfNoFreeze),
|
||||
delegate::as(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
|
||||
// bob can not set asfDisableMaster on behalf of alice
|
||||
Account const bobKey{"bobKey", KeyType::secp256k1};
|
||||
@@ -1327,7 +1306,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env(fset(alice, asfDisableMaster),
|
||||
delegate::as(bob),
|
||||
sig(bob),
|
||||
ter(tecNO_DELEGATE_PERMISSION));
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
}
|
||||
|
||||
// tfFullyCanonicalSig won't block delegated transaction
|
||||
@@ -1377,7 +1356,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
{.account = alice,
|
||||
.flags = tfMPTLock,
|
||||
.delegate = bob,
|
||||
.err = tecNO_DELEGATE_PERMISSION});
|
||||
.err = terNO_DELEGATE_PERMISSION});
|
||||
|
||||
// alice gives granular permission to bob of MPTokenIssuanceUnlock
|
||||
env(delegate::set(alice, bob, {"MPTokenIssuanceUnlock"}));
|
||||
@@ -1387,7 +1366,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
{.account = alice,
|
||||
.flags = tfMPTLock,
|
||||
.delegate = bob,
|
||||
.err = tecNO_DELEGATE_PERMISSION});
|
||||
.err = terNO_DELEGATE_PERMISSION});
|
||||
// bob now has lock permission, but does not have unlock permission
|
||||
env(delegate::set(alice, bob, {"MPTokenIssuanceLock"}));
|
||||
env.close();
|
||||
@@ -1396,7 +1375,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
{.account = alice,
|
||||
.flags = tfMPTUnlock,
|
||||
.delegate = bob,
|
||||
.err = tecNO_DELEGATE_PERMISSION});
|
||||
.err = terNO_DELEGATE_PERMISSION});
|
||||
|
||||
// now bob can lock and unlock
|
||||
env(delegate::set(
|
||||
@@ -1429,7 +1408,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
{.account = alice,
|
||||
.flags = tfMPTUnlock,
|
||||
.delegate = bob,
|
||||
.err = tecNO_DELEGATE_PERMISSION});
|
||||
.err = terNO_DELEGATE_PERMISSION});
|
||||
|
||||
// alice gives bob some unrelated permission with
|
||||
// MPTokenIssuanceLock
|
||||
@@ -1443,7 +1422,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
{.account = alice,
|
||||
.flags = tfMPTUnlock,
|
||||
.delegate = bob,
|
||||
.err = tecNO_DELEGATE_PERMISSION});
|
||||
.err = terNO_DELEGATE_PERMISSION});
|
||||
|
||||
// alice add MPTokenIssuanceSet to permissions
|
||||
env(delegate::set(
|
||||
@@ -1519,29 +1498,96 @@ class Delegate_test : public beast::unit_test::suite
|
||||
testcase("test single sign with bad secret");
|
||||
using namespace jtx;
|
||||
|
||||
Env env(*this);
|
||||
Account alice{"alice"};
|
||||
Account bob{"bob"};
|
||||
Account carol{"carol"};
|
||||
env.fund(XRP(100000), alice, bob, carol);
|
||||
env.close();
|
||||
{
|
||||
Env env(*this);
|
||||
Account alice{"alice"};
|
||||
Account bob{"bob"};
|
||||
Account carol{"carol"};
|
||||
env.fund(XRP(100000), alice, bob, carol);
|
||||
env.close();
|
||||
|
||||
env(delegate::set(alice, bob, {"Payment"}));
|
||||
env.close();
|
||||
env(delegate::set(alice, bob, {"Payment"}));
|
||||
env.close();
|
||||
|
||||
auto aliceBalance = env.balance(alice);
|
||||
auto bobBalance = env.balance(bob);
|
||||
auto carolBalance = env.balance(carol);
|
||||
auto aliceBalance = env.balance(alice);
|
||||
auto bobBalance = env.balance(bob);
|
||||
auto carolBalance = env.balance(carol);
|
||||
|
||||
env(pay(alice, carol, XRP(100)),
|
||||
fee(XRP(10)),
|
||||
delegate::as(bob),
|
||||
sig(alice),
|
||||
ter(tefBAD_AUTH));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
||||
BEAST_EXPECT(env.balance(carol) == carolBalance);
|
||||
env(pay(alice, carol, XRP(100)),
|
||||
fee(XRP(10)),
|
||||
delegate::as(bob),
|
||||
sig(alice),
|
||||
ter(tefBAD_AUTH));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
||||
BEAST_EXPECT(env.balance(carol) == carolBalance);
|
||||
}
|
||||
|
||||
{
|
||||
Env env(*this);
|
||||
Account alice{"alice"}, bob{"bob"}, carol{"carol"};
|
||||
env.fund(XRP(100000), alice, bob, carol);
|
||||
env.close();
|
||||
|
||||
env(delegate::set(alice, bob, {"TrustSet"}));
|
||||
env.close();
|
||||
|
||||
auto aliceBalance = env.balance(alice);
|
||||
auto bobBalance = env.balance(bob);
|
||||
auto carolBalance = env.balance(carol);
|
||||
|
||||
env(pay(alice, carol, XRP(100)),
|
||||
fee(XRP(10)),
|
||||
delegate::as(bob),
|
||||
sig(carol),
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
||||
BEAST_EXPECT(env.balance(carol) == carolBalance);
|
||||
|
||||
env(pay(alice, carol, XRP(100)),
|
||||
fee(XRP(10)),
|
||||
delegate::as(bob),
|
||||
sig(alice),
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
||||
BEAST_EXPECT(env.balance(carol) == carolBalance);
|
||||
}
|
||||
|
||||
{
|
||||
Env env(*this);
|
||||
Account alice{"alice"}, bob{"bob"}, carol{"carol"};
|
||||
env.fund(XRP(100000), alice, bob, carol);
|
||||
env.close();
|
||||
|
||||
auto aliceBalance = env.balance(alice);
|
||||
auto bobBalance = env.balance(bob);
|
||||
auto carolBalance = env.balance(carol);
|
||||
|
||||
env(pay(alice, carol, XRP(100)),
|
||||
fee(XRP(10)),
|
||||
delegate::as(bob),
|
||||
sig(alice),
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
||||
BEAST_EXPECT(env.balance(carol) == carolBalance);
|
||||
|
||||
env(pay(alice, carol, XRP(100)),
|
||||
fee(XRP(10)),
|
||||
delegate::as(bob),
|
||||
sig(carol),
|
||||
ter(terNO_DELEGATE_PERMISSION));
|
||||
env.close();
|
||||
BEAST_EXPECT(env.balance(alice) == aliceBalance);
|
||||
BEAST_EXPECT(env.balance(bob) == bobBalance);
|
||||
BEAST_EXPECT(env.balance(carol) == carolBalance);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1659,10 +1705,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
for (auto value : {0, 100000, 54321})
|
||||
{
|
||||
auto jv = buildRequest(value);
|
||||
if (!features[fixDelegateV1_1])
|
||||
env(jv);
|
||||
else
|
||||
env(jv, ter(temMALFORMED));
|
||||
env(jv, ter(temMALFORMED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1720,8 +1763,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
{"VaultWithdraw", featureSingleAssetVault},
|
||||
{"VaultClawback", featureSingleAssetVault}};
|
||||
|
||||
// fixDelegateV1_1 post-amendment: can not delegate tx if any
|
||||
// required feature disabled.
|
||||
// Can not delegate tx if any required feature disabled.
|
||||
{
|
||||
auto txAmendmentDisabled = [&](FeatureBitset features,
|
||||
std::string const& tx) {
|
||||
@@ -1734,10 +1776,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
env.fund(XRP(100000), alice, bob);
|
||||
env.close();
|
||||
|
||||
if (!features[fixDelegateV1_1])
|
||||
env(delegate::set(alice, bob, {tx}));
|
||||
else
|
||||
env(delegate::set(alice, bob, {tx}), ter(temMALFORMED));
|
||||
env(delegate::set(alice, bob, {tx}), ter(temMALFORMED));
|
||||
};
|
||||
|
||||
for (auto const& tx : txRequiredFeatures)
|
||||
@@ -1786,10 +1825,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
"NFTokenCancelOffer",
|
||||
"NFTokenAcceptOffer"})
|
||||
{
|
||||
if (!features[fixDelegateV1_1])
|
||||
env(delegate::set(alice, bob, {tx}));
|
||||
else
|
||||
env(delegate::set(alice, bob, {tx}), ter(temMALFORMED));
|
||||
env(delegate::set(alice, bob, {tx}), ter(temMALFORMED));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1823,17 +1859,16 @@ class Delegate_test : public beast::unit_test::suite
|
||||
{
|
||||
FeatureBitset const all = jtx::testable_amendments();
|
||||
|
||||
testFeatureDisabled();
|
||||
testFeatureDisabled(all - featurePermissionDelegationV1_1);
|
||||
testFeatureDisabled(all);
|
||||
testDelegateSet();
|
||||
testInvalidRequest(all);
|
||||
testInvalidRequest(all - fixDelegateV1_1);
|
||||
testReserve();
|
||||
testFee();
|
||||
testSequence();
|
||||
testAccountDelete();
|
||||
testDelegateTransaction();
|
||||
testPaymentGranular(all);
|
||||
testPaymentGranular(all - fixDelegateV1_1);
|
||||
testTrustSetGranular();
|
||||
testAccountSetGranular();
|
||||
testMPTokenIssuanceSetGranular();
|
||||
@@ -1842,9 +1877,7 @@ class Delegate_test : public beast::unit_test::suite
|
||||
testMultiSign();
|
||||
testMultiSignQuorumNotMet();
|
||||
testPermissionValue(all);
|
||||
testPermissionValue(all - fixDelegateV1_1);
|
||||
testTxReqireFeatures(all);
|
||||
testTxReqireFeatures(all - fixDelegateV1_1);
|
||||
}
|
||||
};
|
||||
BEAST_DEFINE_TESTSUITE(Delegate, app, ripple);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user