mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-12 06:38:01 +00:00
Compare commits
46 Commits
mvadari/re
...
bthomee/rp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44a5da0632 | ||
|
|
db3764b231 | ||
|
|
5795eb3be2 | ||
|
|
8eae0c338e | ||
|
|
f0d66e2da7 | ||
|
|
212621c9a0 | ||
|
|
8e24943093 | ||
|
|
6d6ab2d067 | ||
|
|
00e6407514 | ||
|
|
00c06edffb | ||
|
|
de5053ae0d | ||
|
|
1940ec5c2a | ||
|
|
19c94c73f4 | ||
|
|
cd005ff60d | ||
|
|
578224f2e6 | ||
|
|
3857ce21cd | ||
|
|
aa490df46b | ||
|
|
88c1f1e7ac | ||
|
|
ede8af8191 | ||
|
|
3c24b605a1 | ||
|
|
d343b542f1 | ||
|
|
7acd719bf7 | ||
|
|
b4564d5301 | ||
|
|
60195e6d37 | ||
|
|
3d526d456e | ||
|
|
f05c9f7913 | ||
|
|
c2a4bc3aa1 | ||
|
|
718185e3b2 | ||
|
|
1d7783bb86 | ||
|
|
9fd2c552f5 | ||
|
|
70b8fd301b | ||
|
|
e6564f553d | ||
|
|
ed96e60ce3 | ||
|
|
2ebd745a1b | ||
|
|
cfcbe45b60 | ||
|
|
9cbf78ba99 | ||
|
|
b8d8738f81 | ||
|
|
63c97e719f | ||
|
|
3ac26f23c7 | ||
|
|
ff9410bc56 | ||
|
|
1798262d7a | ||
|
|
cd633b9ac9 | ||
|
|
5c5f7d315a | ||
|
|
0f7493ce50 | ||
|
|
40f61f828a | ||
|
|
108277f4b7 |
16
.clang-tidy
16
.clang-tidy
@@ -5,7 +5,10 @@ Checks: "-*,
|
||||
-bugprone-exception-escape,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-signed-bitwise,
|
||||
-bugprone-std-exception-baseclass,
|
||||
-bugprone-throwing-static-initialization,
|
||||
-bugprone-unhandled-code-paths,
|
||||
|
||||
cppcoreguidelines-*,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
@@ -14,6 +17,7 @@ Checks: "-*,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||
-cppcoreguidelines-c-copy-assignment-signature,
|
||||
-cppcoreguidelines-explicit-constructor,
|
||||
-cppcoreguidelines-interfaces-global-init,
|
||||
-cppcoreguidelines-macro-usage,
|
||||
-cppcoreguidelines-missing-std-forward,
|
||||
@@ -32,6 +36,7 @@ Checks: "-*,
|
||||
llvm-namespace-comment,
|
||||
|
||||
misc-*,
|
||||
-misc-explicit-constructor,
|
||||
-misc-multiple-inheritance,
|
||||
-misc-no-recursion,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
@@ -45,6 +50,8 @@ Checks: "-*,
|
||||
-modernize-avoid-c-style-cast,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-use-integer-sign-comparison,
|
||||
-modernize-use-string-view,
|
||||
-modernize-use-structured-binding,
|
||||
-modernize-use-trailing-return-type,
|
||||
|
||||
performance-*,
|
||||
@@ -53,6 +60,7 @@ Checks: "-*,
|
||||
-performance-noexcept-move-constructor,
|
||||
-performance-unnecessary-copy-initialization,
|
||||
-performance-unnecessary-value-param,
|
||||
-performance-use-std-move,
|
||||
|
||||
readability-*,
|
||||
-readability-avoid-const-params-in-decls,
|
||||
@@ -65,7 +73,11 @@ Checks: "-*,
|
||||
-readability-named-parameter,
|
||||
-readability-qualified-auto,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-redundant-nested-if,
|
||||
-readability-redundant-qualified-alias,
|
||||
-readability-static-accessed-through-instance,
|
||||
-readability-trailing-comma,
|
||||
-readability-trivial-switch,
|
||||
-readability-uppercase-literal-suffix
|
||||
"
|
||||
# ---
|
||||
@@ -81,6 +93,10 @@ CheckOptions:
|
||||
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
|
||||
bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
|
||||
|
||||
# New in clang-tidy 23; disabled until the code is updated
|
||||
misc-const-correctness.AnalyzeAutoVariables: false
|
||||
misc-const-correctness.AnalyzeLambdas: false
|
||||
misc-const-correctness.AnalyzeParameters: false
|
||||
misc-include-cleaner.IgnoreHeaders: ".*/(detail|impl)/.*;.*fwd\\.h(pp)?;time.h;stdlib.h;sqlite3.h;netinet/in\\.h;sys/resource\\.h;sys/sysinfo\\.h;linux/sysinfo\\.h;__chrono/.*;bits/.*;_abort\\.h;boost/.*;openssl/obj_mac\\.h"
|
||||
|
||||
readability-braces-around-statements.ShortStatementLines: 2
|
||||
|
||||
@@ -108,3 +108,75 @@ endfunction()
|
||||
|
||||
function(patch_nix_binary target)
|
||||
endfunction()
|
||||
|
||||
function(rpcspec_generate_instantiations)
|
||||
set(options)
|
||||
set(oneValueArgs OUT_VAR VALUE_TYPE VIEW_HEADER INCLUDE_DIR)
|
||||
set(multiValueArgs HANDLERS)
|
||||
cmake_parse_arguments(
|
||||
THIS_FUNCTION_PREFIX
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(corrosion_import_crate)
|
||||
set(options
|
||||
ALL_FEATURES
|
||||
NO_DEFAULT_FEATURES
|
||||
NO_STD
|
||||
NO_LINKER_OVERRIDE
|
||||
NO_USES_TERMINAL
|
||||
LOCKED
|
||||
FROZEN
|
||||
)
|
||||
set(oneValueArgs MANIFEST_PATH PROFILE IMPORTED_CRATES)
|
||||
set(multiValueArgs
|
||||
CRATE_TYPES
|
||||
CRATES
|
||||
FEATURES
|
||||
FLAGS
|
||||
OVERRIDE_CRATE_TYPE
|
||||
)
|
||||
cmake_parse_arguments(
|
||||
THIS_FUNCTION_PREFIX
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(corrosion_set_env_vars target_name env_var)
|
||||
endfunction()
|
||||
|
||||
function(corrosion_add_cxxbridge cxx_target)
|
||||
set(options)
|
||||
set(oneValueArgs CRATE)
|
||||
set(multiValueArgs FILES)
|
||||
cmake_parse_arguments(
|
||||
THIS_FUNCTION_PREFIX
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(_unlink_libgcc_s crate)
|
||||
endfunction()
|
||||
|
||||
function(add_xrpl_crate name)
|
||||
set(options)
|
||||
set(oneValueArgs CRATE)
|
||||
set(multiValueArgs FILES)
|
||||
cmake_parse_arguments(
|
||||
THIS_FUNCTION_PREFIX
|
||||
"${options}"
|
||||
"${oneValueArgs}"
|
||||
"${multiValueArgs}"
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
27
.github/actions/build-deps/action.yml
vendored
27
.github/actions/build-deps/action.yml
vendored
@@ -15,9 +15,9 @@ inputs:
|
||||
required: false
|
||||
default: "false"
|
||||
log_verbosity:
|
||||
description: "The logging verbosity."
|
||||
description: 'The logging verbosity ("quiet", "verbose"), or empty to use the Conan defaults.'
|
||||
required: false
|
||||
default: "verbose"
|
||||
default: ""
|
||||
sanitizers:
|
||||
description: "The sanitizers to enable."
|
||||
required: false
|
||||
@@ -35,6 +35,16 @@ runs:
|
||||
LOG_VERBOSITY: ${{ inputs.log_verbosity }}
|
||||
SANITIZERS: ${{ inputs.sanitizers }}
|
||||
run: |
|
||||
# By default, leave the verbosity unset, so CMake configure output is
|
||||
# shown, but compile commands and Boost's b2 debug output (~85k lines
|
||||
# when "verbose") are not.
|
||||
VERBOSITY_ARGS=()
|
||||
if [[ -n "${LOG_VERBOSITY}" ]]; then
|
||||
VERBOSITY_ARGS=(
|
||||
--conf:all tools.build:verbosity="${LOG_VERBOSITY}"
|
||||
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}"
|
||||
)
|
||||
fi
|
||||
conan install \
|
||||
--profile:all ci \
|
||||
--build="${BUILD_OPTION}" \
|
||||
@@ -42,6 +52,13 @@ runs:
|
||||
--options:host='&:xrpld=True' \
|
||||
--settings:all build_type="${BUILD_TYPE}" \
|
||||
--conf:all tools.build:jobs=${BUILD_NPROC} \
|
||||
--conf:all tools.build:verbosity="${LOG_VERBOSITY}" \
|
||||
--conf:all tools.compilation:verbosity="${LOG_VERBOSITY}" \
|
||||
.
|
||||
"${VERBOSITY_ARGS[@]}" \
|
||||
--format=json \
|
||||
. >"${RUNNER_TEMP}/conan-graph.json"
|
||||
|
||||
# Tools that run during the build may only load glibc from the Nix store,
|
||||
# as their package ID survives a GCC runtime update.
|
||||
- name: Check build-context packages for Nix store dependencies (Linux)
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
shell: bash
|
||||
run: ./bin/nix/check-build-context-runtime.sh "${RUNNER_TEMP}/conan-graph.json"
|
||||
|
||||
@@ -174,6 +174,7 @@ test.server > xrpl.basics
|
||||
test.server > xrpl.config
|
||||
test.server > xrpld.app
|
||||
test.server > xrpld.core
|
||||
test.server > xrpld.rpc
|
||||
test.server > xrpl.json
|
||||
test.server > xrpl.protocol
|
||||
test.server > xrpl.server
|
||||
|
||||
8
.github/scripts/strategy-matrix/linux.json
vendored
8
.github/scripts/strategy-matrix/linux.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"image_tag": "sha-060957e",
|
||||
"image_tag": "sha-3d526d4",
|
||||
"configs": {
|
||||
"ubuntu": [
|
||||
{
|
||||
@@ -74,7 +74,7 @@
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON",
|
||||
"package": {
|
||||
"type": "deb",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f"
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -86,7 +86,7 @@
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
|
||||
"package": {
|
||||
"type": "deb",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-3a2d19f",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-e6055dd",
|
||||
"variant": "assert"
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@
|
||||
"extra_cmake_args": "-Dvalidator_keys=ON",
|
||||
"package": {
|
||||
"type": "rpm",
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-3a2d19f"
|
||||
"image": "ghcr.io/xrplf/xrpld/packaging-rhel:sha-e6055dd"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
7
.github/workflows/build-nix-images.yml
vendored
7
.github/workflows/build-nix-images.yml
vendored
@@ -12,8 +12,7 @@ on:
|
||||
- "!nix/docker/README.md"
|
||||
- "!nix/devshell.nix"
|
||||
- "!nix/check-tools/**"
|
||||
- "bin/default-loader-path.sh"
|
||||
- "bin/install-sanitizer-libs.sh"
|
||||
- "bin/nix/default-loader-path.sh"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/build-nix-images.yml"
|
||||
@@ -25,8 +24,8 @@ on:
|
||||
- "!nix/devshell.nix"
|
||||
- "!nix/check-tools/**"
|
||||
- "bin/check-tools.sh"
|
||||
- "bin/default-loader-path.sh"
|
||||
- "bin/install-sanitizer-libs.sh"
|
||||
- "bin/nix/default-loader-path.sh"
|
||||
- "bin/install/sanitizer-libs.sh"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
|
||||
5
.github/workflows/build-packaging-images.yml
vendored
5
.github/workflows/build-packaging-images.yml
vendored
@@ -5,13 +5,12 @@ on:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-packaging-images.yml"
|
||||
- "bin/install-packaging-tools.sh"
|
||||
- "bin/install/packaging-tools.sh"
|
||||
- "package/images/packaging/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/build-packaging-images.yml"
|
||||
- "bin/install-packaging-tools.sh"
|
||||
- "bin/install/packaging-tools.sh"
|
||||
- "package/images/packaging/**"
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
1
.github/workflows/build-pre-commit-image.yml
vendored
1
.github/workflows/build-pre-commit-image.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-pre-commit-image.yml"
|
||||
- "bin/pre-commit/Dockerfile"
|
||||
- "rust-toolchain.toml"
|
||||
pull_request:
|
||||
|
||||
2
.github/workflows/cargo-audit.yml
vendored
2
.github/workflows/cargo-audit.yml
vendored
@@ -34,7 +34,7 @@ permissions:
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
permissions:
|
||||
contents: read
|
||||
# Needed to open an issue on scheduled failures.
|
||||
|
||||
3
.github/workflows/on-pr.yml
vendored
3
.github/workflows/on-pr.yml
vendored
@@ -93,9 +93,8 @@ jobs:
|
||||
.github/workflows/reusable-upload-recipe.yml
|
||||
.clang-tidy
|
||||
.codecov.yml
|
||||
bin/check-nix-store-refs.sh
|
||||
bin/check-tools.sh
|
||||
bin/default-loader-path.sh
|
||||
bin/nix/**
|
||||
cfg/**
|
||||
cmake/**
|
||||
conan/**
|
||||
|
||||
3
.github/workflows/on-trigger.yml
vendored
3
.github/workflows/on-trigger.yml
vendored
@@ -31,9 +31,8 @@ on:
|
||||
- ".github/workflows/reusable-upload-recipe.yml"
|
||||
- ".clang-tidy"
|
||||
- ".codecov.yml"
|
||||
- "bin/check-nix-store-refs.sh"
|
||||
- "bin/check-tools.sh"
|
||||
- "bin/default-loader-path.sh"
|
||||
- "bin/nix/**"
|
||||
- "cfg/**"
|
||||
- "cmake/**"
|
||||
- "conan/**"
|
||||
|
||||
2
.github/workflows/pre-commit.yml
vendored
2
.github/workflows/pre-commit.yml
vendored
@@ -17,4 +17,4 @@ jobs:
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@279ec358f4a1be4088be3e024b07916fa97c75b6
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-473fe44" }'
|
||||
container: '{ "image": "ghcr.io/xrplf/xrpld/pre-commit:sha-70b8fd3" }'
|
||||
|
||||
2
.github/workflows/publish-docs.yml
vendored
2
.github/workflows/publish-docs.yml
vendored
@@ -41,7 +41,7 @@ env:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
13
.github/workflows/reusable-build-test-config.yml
vendored
13
.github/workflows/reusable-build-test-config.yml
vendored
@@ -186,9 +186,6 @@ jobs:
|
||||
with:
|
||||
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' }}
|
||||
sanitizers: ${{ inputs.sanitizers }}
|
||||
|
||||
- name: Configure CMake
|
||||
@@ -257,20 +254,20 @@ jobs:
|
||||
# cache included, since what it holds is what gets uploaded and reused.
|
||||
- name: Check the build output for Nix store references (Nix toolchain)
|
||||
if: ${{ inputs.toolchain == 'nix' }}
|
||||
run: ./bin/check-nix-store-refs.sh "${BUILD_DIR}"
|
||||
run: ./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}"
|
||||
|
||||
- name: Check the Conan cache for Nix store references (Nix toolchain)
|
||||
if: ${{ inputs.toolchain == 'nix' }}
|
||||
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}"
|
||||
run: ./bin/nix/check-nix-store-refs.sh "${CONAN_HOME}"
|
||||
|
||||
# Only what PatchNixBinary.cmake retargets: the toolchain in the Linux
|
||||
# images always references the store. Same condition it uses.
|
||||
- name: Check for Nix store references (Linux)
|
||||
if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }}
|
||||
run: |
|
||||
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld"
|
||||
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests"
|
||||
./bin/check-nix-store-refs.sh "${BUILD_DIR}/xrpld_tests"
|
||||
./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpld"
|
||||
./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpl_tests"
|
||||
./bin/nix/check-nix-store-refs.sh "${BUILD_DIR}/xrpld_tests"
|
||||
|
||||
- name: Show ccache statistics
|
||||
if: ${{ inputs.ccache_enabled }}
|
||||
|
||||
3
.github/workflows/reusable-clang-tidy.yml
vendored
3
.github/workflows/reusable-clang-tidy.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
needs: [determine-files]
|
||||
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-060957e"
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-3d526d4"
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
@@ -73,7 +73,6 @@ jobs:
|
||||
with:
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ env.BUILD_TYPE }}
|
||||
log_verbosity: verbose
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
|
||||
6
.github/workflows/reusable-rust.yml
vendored
6
.github/workflows/reusable-rust.yml
vendored
@@ -28,7 +28,7 @@ permissions:
|
||||
jobs:
|
||||
clippy:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
|
||||
coverage:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
doc:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
2
.github/workflows/reusable-upload-recipe.yml
vendored
2
.github/workflows/reusable-upload-recipe.yml
vendored
@@ -40,7 +40,7 @@ defaults:
|
||||
jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-060957e
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-3d526d4
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
|
||||
|
||||
5
.github/workflows/upload-conan-deps.yml
vendored
5
.github/workflows/upload-conan-deps.yml
vendored
@@ -108,14 +108,11 @@ jobs:
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ matrix.build_type }}
|
||||
force_build: ${{ github.event_name == 'schedule' || github.event.inputs.force_source_build == 'true' }}
|
||||
# Set the verbosity to "quiet" for Windows to avoid an excessive
|
||||
# amount of logs. For other OSes, the "verbose" logs are more useful.
|
||||
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
|
||||
sanitizers: ${{ matrix.sanitizers }}
|
||||
|
||||
- name: Check the Conan cache for Nix store references (Nix toolchain)
|
||||
if: ${{ matrix.toolchain == 'nix' }}
|
||||
run: ./bin/check-nix-store-refs.sh "${CONAN_HOME}"
|
||||
run: ./bin/nix/check-nix-store-refs.sh "${CONAN_HOME}"
|
||||
|
||||
- name: Log into Conan remote
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
|
||||
|
||||
@@ -60,7 +60,7 @@ repos:
|
||||
types_or: [c++, c]
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: e2b496dc2bd8340c2524cb9a2d2a943cde1bb6df # frozen: v23.1.1
|
||||
rev: a9a8a861f30ed207ead7d5a3b7e8032283ba5da7 # frozen: v23.1.2
|
||||
hooks:
|
||||
- id: clang-format
|
||||
args: [--style=file]
|
||||
@@ -82,9 +82,10 @@ repos:
|
||||
files: ^crates/.*\.rs$
|
||||
|
||||
- repo: https://github.com/BlankSpruce/gersemi-pre-commit
|
||||
rev: f1c4833f8cf23c6d952673abc73525411a5719e8 # frozen: 0.29.1
|
||||
rev: 28010ddd6016e1a0f7bd232acb6536ef996ae897 # frozen: 0.29.2
|
||||
hooks:
|
||||
- id: gersemi
|
||||
args: [-i, --warnings-as-errors]
|
||||
|
||||
- repo: https://github.com/rbubley/mirrors-prettier
|
||||
rev: ef4a397f916211b4a39ccf9d3d9cbb6562157251 # frozen: v3.9.9
|
||||
@@ -95,19 +96,19 @@ repos:
|
||||
# Scoped to package/: the rest of the repo's Python has pre-existing findings,
|
||||
# so widening these is its own change.
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: a56c0b927e6465d37cae3e97d35d4d18ab2b96cd # frozen: v0.16.9
|
||||
rev: f12be1ebaa5351c1fc76472de98db2c3446c8253 # frozen: v0.16.10
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
args: [--fix]
|
||||
files: ^package/.*\.py$
|
||||
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 4160603246a6b365d4a2af661c6d71b0a0f50478 # frozen: 26.5.1
|
||||
rev: 96ae3e5802f3fe2d551e703e18f0a367d1a81ac2 # frozen: 26.10.0
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: 7ff8d35ae36a7d2b968f2f90b4c723e292e594ee # frozen: v2.3.1
|
||||
rev: 2834ec6639549dd6796205c8f011dedcd587288b # frozen: v2.4.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
args: [--strict]
|
||||
|
||||
@@ -22,13 +22,33 @@ API version 2 is available in `xrpld` version 2.0.0 and later. See [API-VERSION-
|
||||
|
||||
This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified.
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- A request echoed back in an error reply now has every credential-bearing field masked: `admin_password`, `admin_user`, `passphrase`, `password`, `secret`, `seed`, `seed_hex`, `url_password`, `url_username` and `username`. Nesting no longer matters, so a credential inside `params` is masked too. The same masking is applied to every request and reply written to the log, and it covers six further names that only a reply carries: `master_key`, `master_seed`, `master_seed_hex`, `validation_key`, `validation_private_key` and `validation_seed`, which is how `wallet_propose` and `validation_create` used to write a live private key to the log. A request or reply written to the log is truncated at 10,000 characters.
|
||||
- The command line client no longer prints a credential the operator did not type. A failing command echoes the request it built under `request_sent`, which carries the `admin_password` the client copies out of `[port_rpc]` in the config, so `./xrpld account_info rBogus` printed that password to stdout and into any captured output. `request_sent` is now masked. The `rpc` member beside it, which echoes the arguments as they were typed, is unchanged. The command line client also no longer writes an unparsed `json` or `ripple_path_find` argument to its trace log before parsing it, where a `secret` inside that argument could not be masked; it logs the parsed request instead, masked. The reply it receives is logged the same way, parsed and masked, where the raw body was written before, a `validation_create` answer included.
|
||||
- A WebSocket frame that does not parse, or exceeds the request size limit, is answered `{"type": "error", "error": "jsonInvalid", "size": <bytes>}`. The frame's body is reported by size rather than echoed back in a `value` member, since a body that does not parse has no fields to mask. A client that read `value` gets `size` instead.
|
||||
- Four error codes that named no HTTP status of their own, and so answered 200 on a reply reporting an error, now name one: `actMalformed`, `alreadyMultisig` and `alreadySingleSig` answer 400, and `actNotFound` answers 404. **No shipped envelope reports these four.** A request sending `ripplerpc: "3.0"` still receives 200 for all four, as it always has, so `account_info` on a malformed account or one the ledger does not hold answers 200 exactly as before.
|
||||
- `submit`, `simulate`, `transaction_entry`, `ledger_entry` and `ledger_accept`: Errors from these methods now include `error_code` and `error_message` alongside the `error` token, as every other method already did. Each error now answers the status its code names: 400 for a malformed request, 404 for `transactionNotFound`, 500 for an internal failure, and 501 for `notYetImplemented` and `notStandAlone`. That status change reaches only a request sending `ripplerpc: "3.0"`, which is the envelope that derives the status from the error. With `ripplerpc` `"1.0"` the status stays 200 and the two new members appear beside `error`; with `"2.0"` the status stays 200, `error_code` appears, and the `code` and `message` members carry the code and the message rather than null, since that envelope copies them from `error_code` and `error_message` and drops `error_message`.
|
||||
|
||||
## XRP Ledger server version 3.5.0
|
||||
|
||||
Version 3.5.0 is not yet released.
|
||||
|
||||
### Additions in 3.5.0
|
||||
|
||||
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive a message with `type` `mptTransaction` for each validated transaction whose metadata affects a subscribed issuance; the message has the same fields as the `transactions` stream. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
|
||||
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive the same `transaction` message as the `transactions` stream for each validated transaction whose metadata affects a subscribed issuance. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
|
||||
- `ledger_entry`: Add full support for checks, NFT offers, payment channels, and signer lists. ([#6319](https://github.com/XRPLF/rippled/pull/6319))
|
||||
|
||||
### Bugfixes in 3.5.0
|
||||
|
||||
- `channel_authorize`: The `channel_id` field now returns an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
|
||||
- `channel_verify`: The `channel_id` and `signature` fields now return an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
|
||||
|
||||
### Bugfixes in 3.5.0
|
||||
|
||||
- `feature`: The admin-only `vetoed` field now returns `invalidParams` unless its value is a boolean. [#7583](https://github.com/XRPLF/rippled/pull/7583)
|
||||
|
||||
## XRP Ledger server version 3.4.0
|
||||
|
||||
@@ -50,6 +70,7 @@ Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta
|
||||
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)
|
||||
- `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706)
|
||||
- `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)).
|
||||
- `transaction_entry`: An object or an array in `tx_hash` now returns `malformedRequest`, like any other value that is not a hex hash, instead of an `internal` error.
|
||||
|
||||
## XRP Ledger server version 3.3.0
|
||||
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
# development setups, but not in the macOS CI environment. They are checked
|
||||
# everywhere except when running in CI on macOS.
|
||||
#
|
||||
# Tools that Nix also exposes under a version-suffixed name (`clang-tidy-22`,
|
||||
# `g++-15`, ...) are probed under both names: a suffixed name can break while
|
||||
# the plain one still works (see mkVersionedToolLinks in nix/packages.nix).
|
||||
# Tools that Nix also exposes under a version-suffixed name
|
||||
# (`clang-tidy-<v>`, `g++-<v>`, ...) are probed under both names:
|
||||
# a suffixed name can break while the plain one still works
|
||||
# (see mkVersionedToolLinks in nix/packages.nix).
|
||||
# The suffix is the major version of the plain `clang` / `gcc` on PATH.
|
||||
#
|
||||
# Tools scoped to a single dev shell rather than to commonPackages are checked
|
||||
# only in that shell, keyed off XRPL_DEVSHELL.
|
||||
@@ -34,9 +36,16 @@
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# Version suffixes of the Nix tool links, tracking nix/packages.nix.
|
||||
gcc_version=15
|
||||
llvm_version=22
|
||||
# major_version <compiler>
|
||||
# Major version of a compiler on PATH, or "unknown" when it isn't there.
|
||||
major_version() {
|
||||
local version
|
||||
version="$("$1" -dumpversion 2>/dev/null)" || version=""
|
||||
version="${version%%.*}"
|
||||
printf '%s' "${version:-unknown}"
|
||||
}
|
||||
|
||||
llvm_version="$(major_version clang)"
|
||||
|
||||
missing=()
|
||||
checked=0
|
||||
@@ -112,6 +121,7 @@ if [ "${os}" = "linux" ] || [ "${os}" = "macos" ]; then
|
||||
check ClangBuildAnalyzer
|
||||
check curl
|
||||
check file
|
||||
check jq
|
||||
check less
|
||||
check make
|
||||
# net-tools netstat reports "net-tools X.Y"; macOS ships BSD netstat with no
|
||||
@@ -180,6 +190,7 @@ fi
|
||||
if [ "${os}" = "linux" ]; then
|
||||
echo
|
||||
echo "GCC toolchain:"
|
||||
gcc_version="$(major_version gcc)"
|
||||
check gcc
|
||||
check "gcc-${gcc_version}"
|
||||
check g++
|
||||
|
||||
65
bin/nix/check-build-context-runtime.sh
Executable file
65
bin/nix/check-build-context-runtime.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fail if a binary of a build-context Conan package loads anything from the Nix
|
||||
# store other than glibc, or cannot resolve a library at all.
|
||||
#
|
||||
# Only binaries linked by the Nix toolchain are checked, i.e. those recording a
|
||||
# store path as their interpreter or RUNPATH. Prebuilt upstream binaries (such
|
||||
# as the ones the cmake package ships) use the system loader instead.
|
||||
#
|
||||
# Build-context packages provide the tools that run during the build (protoc,
|
||||
# grpc_cpp_plugin, ...). Their package ID does not change when a Nix toolchain
|
||||
# update moves the GCC runtime to a new store path, so a cached binary has to
|
||||
# get by with the pinned glibc alone. See docs/build/nix.md.
|
||||
#
|
||||
# Usage: bin/nix/check-build-context-runtime.sh <graph.json>
|
||||
# <graph.json> is the output of `conan install --format=json`.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "usage: $0 <graph.json>" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$(uname -s)" != "Linux" ]; then
|
||||
echo "$0: Linux only" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
folders="$(jq -r '.graph.nodes[] | select(.context == "build" and .package_folder) | .package_folder' "$1" | sort -u)"
|
||||
|
||||
checked=0
|
||||
failed=0
|
||||
|
||||
while IFS= read -r file; do
|
||||
case "$(file -b "${file}")" in
|
||||
ELF*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
[[ "$(readelf -ldW "${file}")" == */nix/store/* ]] || continue
|
||||
checked=$((checked + 1))
|
||||
|
||||
# `ldd` lists the interpreter and every library as the loader resolves them.
|
||||
if deps="$(ldd "${file}" 2>&1)"; then
|
||||
bad="$(printf '%s\n' "${deps}" |
|
||||
grep -E 'not found|/nix/store/' |
|
||||
grep -vE '/nix/store/[^/]+-glibc-[^/]+/' || true)"
|
||||
else
|
||||
case "${deps}" in
|
||||
*"not a dynamic executable"*) continue ;;
|
||||
esac
|
||||
bad="${deps}"
|
||||
fi
|
||||
if [ -n "${bad}" ]; then
|
||||
failed=$((failed + 1))
|
||||
echo "::error file=${file}::loads a library from the Nix store other than glibc"
|
||||
echo "${file}"
|
||||
echo "${bad}" | sed 's/^/ /'
|
||||
fi
|
||||
done < <(
|
||||
# shellcheck disable=SC2086 # one folder per line, no spaces in Conan paths
|
||||
[ -z "${folders}" ] || find ${folders} -type f \( -perm -u+x -o -name '*.so*' \)
|
||||
)
|
||||
|
||||
echo "Build-context packages: checked ${checked} binaries, ${failed} failed."
|
||||
[ "${failed}" -eq 0 ]
|
||||
@@ -10,7 +10,7 @@
|
||||
# alone; the scripts in a Conan cache are all git hook samples and autotools
|
||||
# scratch, 36 false positives to 0 real.
|
||||
#
|
||||
# Usage: bin/check-nix-store-refs.sh <path>
|
||||
# Usage: bin/nix/check-nix-store-refs.sh <path>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
@@ -23,7 +23,7 @@ apt-get clean
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
EOF
|
||||
|
||||
ARG PRE_COMMIT_VERSION=4.6.0
|
||||
ARG PRE_COMMIT_VERSION=4.6.2
|
||||
RUN pip install --no-cache --break-system-packages \
|
||||
pre-commit==${PRE_COMMIT_VERSION}
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@ import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
CLANG_TIDY_VERSION = 22
|
||||
|
||||
# Extensions run-clang-tidy can analyse: `.cpp` translation units and, thanks to
|
||||
# the `verify_headers` build option, `.h`/`.hpp` headers (each has its own
|
||||
# compile_commands.json entry). `.ipp` fragments have no entry and are skipped.
|
||||
@@ -39,8 +37,21 @@ TIDY_EXTENSIONS = {".cpp", ".h", ".hpp"}
|
||||
FILEPATH_RE = re.compile(r"^(\s*(?:-\s+)?FilePath:\s*)'((?:[^']|'')*)'\s*$")
|
||||
|
||||
|
||||
def find_tool(name: str) -> str | None:
|
||||
for candidate in (f"{name}-{CLANG_TIDY_VERSION}", name):
|
||||
def clang_tidy_major() -> str | None:
|
||||
"""Major version of the `clang-tidy` on PATH, which run-clang-tidy invokes."""
|
||||
if not (clang_tidy := shutil.which("clang-tidy")):
|
||||
return None
|
||||
output = subprocess.run(
|
||||
[clang_tidy, "--version"], capture_output=True, text=True
|
||||
).stdout
|
||||
m = re.search(r"LLVM version (\d+)", output)
|
||||
return m.group(1) if m else None
|
||||
|
||||
|
||||
def find_tool(name: str, version: str | None) -> str | None:
|
||||
"""Prefer `<name>-<version>`, so a host tool of another version can't win."""
|
||||
candidates = ([f"{name}-{version}"] if version else []) + [name]
|
||||
for candidate in candidates:
|
||||
if path := shutil.which(candidate):
|
||||
return path
|
||||
return None
|
||||
@@ -103,8 +114,9 @@ def main():
|
||||
if not files:
|
||||
return 0
|
||||
|
||||
run_clang_tidy = find_tool("run-clang-tidy")
|
||||
clang_apply_replacements = find_tool("clang-apply-replacements")
|
||||
version = clang_tidy_major()
|
||||
run_clang_tidy = find_tool("run-clang-tidy", version)
|
||||
clang_apply_replacements = find_tool("clang-apply-replacements", version)
|
||||
missing = [
|
||||
name
|
||||
for name, path in (
|
||||
@@ -114,9 +126,10 @@ def main():
|
||||
if not path
|
||||
]
|
||||
if missing:
|
||||
tried = f" (tried the '-{version}' suffix too)" if version else ""
|
||||
print(
|
||||
f"clang-tidy check failed: TIDY is enabled but {' and '.join(missing)} "
|
||||
f"was not found in PATH (tried the '-{CLANG_TIDY_VERSION}' suffix too).",
|
||||
f"was not found in PATH{tried}.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
(runtime libraries resolved through the rpath) are skipped too.
|
||||
Everywhere else `patch_nix_binary` is a no-op.
|
||||
|
||||
The default loader is resolved by bin/default-loader-path.sh.
|
||||
The default loader is resolved by bin/nix/default-loader-path.sh.
|
||||
#]===================================================================]
|
||||
|
||||
include_guard(GLOBAL)
|
||||
@@ -25,7 +25,7 @@ include_guard(GLOBAL)
|
||||
include(CompilationEnv)
|
||||
|
||||
# Resolves the system default ELF loader path for the current architecture.
|
||||
set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/default-loader-path.sh")
|
||||
set(_loader_path_script "${CMAKE_SOURCE_DIR}/bin/nix/default-loader-path.sh")
|
||||
|
||||
if(
|
||||
is_linux
|
||||
|
||||
@@ -292,6 +292,14 @@ if(xrpld)
|
||||
)
|
||||
target_sources(xrpld PRIVATE ${sources})
|
||||
|
||||
rpcspec_generate_instantiations(
|
||||
OUT_VAR rpcspec_instantiations
|
||||
VALUE_TYPE "::json::Value"
|
||||
VIEW_HEADER "xrpld/rpc/detail/JsonObjectView.hpp"
|
||||
HANDLERS book_changes ledger transaction_entry
|
||||
)
|
||||
target_sources(xrpld PRIVATE ${rpcspec_instantiations})
|
||||
|
||||
if(tests)
|
||||
file(
|
||||
GLOB_RECURSE sources
|
||||
@@ -322,6 +330,7 @@ if(xrpld)
|
||||
# antithesis_instrumentation.h, which is not exported as INTERFACE
|
||||
target_include_directories(
|
||||
xrpld
|
||||
SYSTEM
|
||||
PRIVATE ${CMAKE_SOURCE_DIR}/external/antithesis-sdk
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -77,19 +77,24 @@ if(is_clang)
|
||||
message(STATUS " Ignorelist: ${ignorelist_path}")
|
||||
endif()
|
||||
|
||||
# Define SANITIZERS macro for BuildInfo.cpp
|
||||
# Define the SANITIZERS macro for BuildInfo.cpp, plus one of XRPL_ASAN,
|
||||
# XRPL_TSAN and XRPL_UBSAN per active sanitizer, so that code can test for a
|
||||
# specific one with #ifdef instead of parsing the dot-joined SANITIZERS string.
|
||||
set(sanitizers_list)
|
||||
if(SANITIZERS MATCHES "address")
|
||||
set(enable_asan ON)
|
||||
list(APPEND sanitizers_list "ASAN")
|
||||
target_compile_definitions(common INTERFACE XRPL_ASAN)
|
||||
endif()
|
||||
if(SANITIZERS MATCHES "thread")
|
||||
set(enable_tsan ON)
|
||||
list(APPEND sanitizers_list "TSAN")
|
||||
target_compile_definitions(common INTERFACE XRPL_TSAN)
|
||||
endif()
|
||||
if(SANITIZERS MATCHES "undefinedbehavior")
|
||||
set(enable_ubsan ON)
|
||||
list(APPEND sanitizers_list "UBSAN")
|
||||
target_compile_definitions(common INTERFACE XRPL_UBSAN)
|
||||
endif()
|
||||
|
||||
if(sanitizers_list)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
|
||||
"xrpl-rpc-spec/0.1.19#870b2d3abcfbbf13b61c2d3c69495060%1790348286.187549",
|
||||
"xrpl-rpc-spec/0.1.21#d536f87a2ae7d313452746cfa3ac4404%1790869005.122975",
|
||||
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
|
||||
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
|
||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
|
||||
@@ -20,7 +20,7 @@
|
||||
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892",
|
||||
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
|
||||
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
|
||||
"grpc/1.81.1#b87796a4269034856cbc1a2522db16eb%1788275071.530512",
|
||||
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
|
||||
"fast_float/8.2.10#f6f28d6bb22112078e7dbda611caf681%1785888854.601666",
|
||||
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
|
||||
@@ -34,11 +34,15 @@
|
||||
"build_requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639",
|
||||
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
|
||||
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
|
||||
"openssl/3.6.3#f806de8933e3bf6f01016c6a888cee2e%1783945160.863288",
|
||||
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162",
|
||||
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
|
||||
"m4/1.4.19#1727f439cf74e83826ec96d0b4904eee%1784541921.659",
|
||||
"grpc/1.81.1#aaa93ab6cda2f2baa6a84490582c8adf%1791284951.826256",
|
||||
"cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091",
|
||||
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
|
||||
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
|
||||
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
|
||||
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
|
||||
|
||||
@@ -3,5 +3,13 @@
|
||||
core:non_interactive=True
|
||||
core.download:parallel={{ os.cpu_count() }}
|
||||
core.upload:parallel={{ os.cpu_count() }}
|
||||
tools.files.download:retry=5
|
||||
# Fall back to Conan Center's source backups when a recipe's upstream URL is down
|
||||
# (e.g. the GNU FTP mirrors), see
|
||||
# https://github.com/conan-io/conan-center-index/issues/28147#issuecomment-3183544772
|
||||
# The backups are only tried once every upstream URL has used up its retries,
|
||||
# so keep the retries low.
|
||||
core.sources:download_urls=["origin", "https://c3i.jfrog.io/artifactory/conan-center-backup-sources"]
|
||||
tools.files.download:retry=1
|
||||
tools.files.download:retry_wait=10
|
||||
# Fail fast on unreachable hosts (default connect timeout is 30s), keep the 60s read timeout.
|
||||
core.net.http:timeout=(5, 60)
|
||||
|
||||
@@ -29,9 +29,9 @@ os.version={{ min_macos_version }}
|
||||
[conf]
|
||||
{# The Boost recipe builds with b2, which doesn't use Conan's toolchain files. #}
|
||||
{# Instead it hand-rolls the compiler for user-config.jam, #}
|
||||
{# and its fallback probes a version-suffixed binary (e.g. `g++-15`) before plain `g++`. #}
|
||||
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-15` suffix), #}
|
||||
{# so on a host that also has a system `g++-15` the probe escapes Nix #}
|
||||
{# and its fallback probes a version-suffixed binary (e.g. `g++-<major>`) before plain `g++`. #}
|
||||
{# Inside the Nix shell the wrapper only provides `g++`/`gcc` (no `-<major>` suffix), #}
|
||||
{# so on a host that also has a system `g++-<major>` the probe escapes Nix #}
|
||||
{# and picks the system compiler, which is mismatched with the Nix libraries #}
|
||||
{# and breaks the build (e.g. Boost.Stacktrace link checks fail). #}
|
||||
{# Pinning the executables here short-circuits that probe so Boost (and the rest of the toolchain) #}
|
||||
@@ -49,8 +49,31 @@ tools.build:compiler_executables={'c':'{{ cc_exe }}','cpp':'{{ cxx_exe }}'}
|
||||
user.package:cppstd_version=23
|
||||
tools.info.package_id:confs+=["user.package:cppstd_version"]
|
||||
|
||||
{% if os == "Macos" %}
|
||||
{% if os == "Linux" and context == "build" %}
|
||||
{# Build-context executables (protoc, grpc_cpp_plugin, build tools) run during the build #}
|
||||
{# and would otherwise load libstdc++/libgcc from a Nix store path #}
|
||||
{# that might change with a Nix toolchain update. #}
|
||||
{# --as-needed drops the ones they link but don't use, #}
|
||||
{# such as libatomic for grpc_cpp_plugin on arm64. #}
|
||||
{% set static_runtime_flags = ["-static-libstdc++", "-static-libgcc", "-Wl,--as-needed"] %}
|
||||
tools.build:exelinkflags+={{ static_runtime_flags }}
|
||||
tools.info.package_id:confs+=["tools.build:exelinkflags"]
|
||||
{% endif %}
|
||||
|
||||
{% if os == "Linux" and context == "build" %}
|
||||
{# b2 links itself with its own script, which ignores exelinkflags #}
|
||||
{# and only takes CXXFLAGS when use_cxx_env is set (see [buildenv] below). #}
|
||||
[options]
|
||||
b2/*:use_cxx_env=True
|
||||
{% endif %}
|
||||
|
||||
[buildenv]
|
||||
{# gRPC emits thousands of compiler warnings that we cannot act on. #}
|
||||
{# CMake picks up CXXFLAGS, and unlike tools.build:cxxflags, #}
|
||||
{# this is not part of the package ID, so binaries stay shareable. #}
|
||||
grpc/*:CXXFLAGS=-w
|
||||
|
||||
{% if os == "Macos" %}
|
||||
{# os.version adds -mmacosx-version-min to compiler command lines, #}
|
||||
{# but Boost.Context's b2 assembly (.S) rule ignores it, #}
|
||||
{# so those objects keep the host SDK version and still warn at link time. #}
|
||||
@@ -58,3 +81,7 @@ tools.info.package_id:confs+=["user.package:cppstd_version"]
|
||||
{# Scoped to boost/* since it is the only gap. #}
|
||||
boost/*:MACOSX_DEPLOYMENT_TARGET={{ min_macos_version }}
|
||||
{% endif %}
|
||||
|
||||
{% if os == "Linux" and context == "build" %}
|
||||
b2/*:CXXFLAGS={{ static_runtime_flags | join(" ") }}
|
||||
{% endif %}
|
||||
|
||||
@@ -5,6 +5,9 @@ include(default)
|
||||
|
||||
{% if not sanitizers %}
|
||||
{# Sanitizers not configured; no additional settings needed #}
|
||||
{% elif context == "build" %}
|
||||
{# Build-context packages are tools we run, not code we test, #}
|
||||
{# so don't instrument them #}
|
||||
{% else %}
|
||||
|
||||
{% if compiler == "msvc" %}
|
||||
|
||||
11
conanfile.py
11
conanfile.py
@@ -40,7 +40,7 @@ class Xrpl(ConanFile):
|
||||
"nudb/2.0.9",
|
||||
"openssl/3.6.3",
|
||||
"soci/4.0.3",
|
||||
"xrpl-rpc-spec/0.1.19",
|
||||
"xrpl-rpc-spec/0.1.21",
|
||||
"zlib/1.3.2",
|
||||
]
|
||||
|
||||
@@ -49,7 +49,8 @@ class Xrpl(ConanFile):
|
||||
]
|
||||
|
||||
tool_requires = [
|
||||
"protobuf/6.33.5",
|
||||
"grpc/<host_version>",
|
||||
"protobuf/<host_version>",
|
||||
]
|
||||
|
||||
default_options = {
|
||||
@@ -123,6 +124,10 @@ class Xrpl(ConanFile):
|
||||
"xxhash/*:shared": False,
|
||||
}
|
||||
|
||||
# default_options only reach the host context;
|
||||
# give tool_requires (and their dependencies) the same dependency options.
|
||||
default_build_options = {k: v for k, v in default_options.items() if "/" in k}
|
||||
|
||||
def set_version(self):
|
||||
self.version = self.version or DEV_VERSION
|
||||
|
||||
@@ -149,7 +154,7 @@ class Xrpl(ConanFile):
|
||||
self.requires("xxhash/0.8.3", transitive_headers=True)
|
||||
|
||||
exports_sources = (
|
||||
"bin/default-loader-path.sh",
|
||||
"bin/nix/default-loader-path.sh",
|
||||
"CMakeLists.txt",
|
||||
"cfg/*",
|
||||
"cmake/*",
|
||||
|
||||
@@ -80,13 +80,12 @@ function(add_xrpl_crate name)
|
||||
# `cc` picks its runtime flag from `crt-static` alone, so it compiles a
|
||||
# crate's C++ with `-MT`; Debug needs `-MTd` (to match cmake/XrplCompiler.cmake).
|
||||
if(is_msvc)
|
||||
corrosion_set_env_vars(
|
||||
${ARG_CRATE}
|
||||
"$<$<CONFIG:Debug>:CXXFLAGS=-MTd>"
|
||||
)
|
||||
corrosion_set_env_vars(${ARG_CRATE} "$<$<CONFIG:Debug>:CXXFLAGS=-MTd>")
|
||||
endif()
|
||||
corrosion_add_cxxbridge(${name}_cxxbridge CRATE ${ARG_CRATE} FILES
|
||||
${ARG_FILES}
|
||||
corrosion_add_cxxbridge(
|
||||
${name}_cxxbridge
|
||||
CRATE ${ARG_CRATE}
|
||||
FILES ${ARG_FILES}
|
||||
)
|
||||
# Generated cxxbridge headers don't exist at configure time; CMake 3.28+
|
||||
# validates INTERFACE_SOURCES on consuming targets. Clear it to skip the
|
||||
|
||||
16
docs/build/environment.md
vendored
16
docs/build/environment.md
vendored
@@ -10,14 +10,15 @@ This document explains how to set one up.
|
||||
support it — see [compiler support for C++23][cpp23-support].
|
||||
The versions currently tested in CI are:
|
||||
|
||||
| Compiler | Version |
|
||||
| ----------- | ------------------ |
|
||||
| GCC | 15.2 |
|
||||
| Clang | 22 |
|
||||
| Apple Clang | 21 |
|
||||
| MSVC | Visual Studio 2026 |
|
||||
| Compiler | Version |
|
||||
| ----------- | ------------------------------- |
|
||||
| GCC | `gccVersion` in [packages.nix] |
|
||||
| Clang | `llvmVersion` in [packages.nix] |
|
||||
| Apple Clang | 21 |
|
||||
| MSVC | Visual Studio 2026 |
|
||||
|
||||
LLVM tools (`clang-tidy` and `clang-format`) are also pinned to version 22.
|
||||
LLVM tools (`clang-tidy` and `clang-format`)
|
||||
come from the same LLVM release as Clang.
|
||||
|
||||
### Older compilers
|
||||
|
||||
@@ -156,3 +157,4 @@ version out of the box — run it via `run-clang-tidy`. No separate installation
|
||||
is needed.
|
||||
|
||||
[cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23
|
||||
[packages.nix]: ../../nix/packages.nix
|
||||
|
||||
30
docs/build/nix.md
vendored
30
docs/build/nix.md
vendored
@@ -183,24 +183,36 @@ at link or run time.
|
||||
> configuration CI covers, and no dependency binaries are published for it.
|
||||
|
||||
This is checked rather than assumed.
|
||||
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) takes one file
|
||||
or directory and fails if a binary under it resolves a store path at run time.
|
||||
[`bin/nix/check-nix-store-refs.sh`](../../bin/nix/check-nix-store-refs.sh) takes one
|
||||
file or directory and fails if a binary under it resolves a store path at run time.
|
||||
CI runs it over the build output and the Conan cache, and again in the upload job
|
||||
before anything is published. You can run it yourself:
|
||||
|
||||
```bash
|
||||
bin/check-nix-store-refs.sh build
|
||||
bin/check-nix-store-refs.sh ~/.conan2-nix
|
||||
bin/nix/check-nix-store-refs.sh build
|
||||
bin/nix/check-nix-store-refs.sh ~/.conan2-nix
|
||||
```
|
||||
|
||||
It works on Linux too, but asserts something narrower there: the toolchain always
|
||||
writes the store into `PT_INTERP` and `RUNPATH`, and CI builds inside an image
|
||||
whose store is fixed for its lifetime, so that is fine. Only the binaries
|
||||
[`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake) retargets to the
|
||||
system loader have to be clean, and those are what CI checks:
|
||||
writes the store into `PT_INTERP` and `RUNPATH`. That is fine for the pinned
|
||||
glibc, whose path does not move, but not for the GCC runtime, which moves with
|
||||
every GCC update. So [`conan/profiles/default`](../../conan/profiles/default)
|
||||
links build-context packages, whose executables run during the build, with
|
||||
`-static-libstdc++ -static-libgcc -Wl,--as-needed`, and
|
||||
[`conan/profiles/sanitizers`](../../conan/profiles/sanitizers) does not
|
||||
instrument them. CI checks that they load nothing from the store but glibc, from
|
||||
the graph `conan install --format=json` writes:
|
||||
|
||||
```bash
|
||||
bin/check-nix-store-refs.sh build/xrpld
|
||||
bin/nix/check-build-context-runtime.sh graph.json
|
||||
```
|
||||
|
||||
Only the binaries [`PatchNixBinary.cmake`](../../cmake/PatchNixBinary.cmake)
|
||||
retargets to the system loader have to be fully clean, and those are what CI
|
||||
checks:
|
||||
|
||||
```bash
|
||||
bin/nix/check-nix-store-refs.sh build/xrpld
|
||||
```
|
||||
|
||||
### The libresolv stub
|
||||
|
||||
6
docs/build/nix_troubleshooting.md
vendored
6
docs/build/nix_troubleshooting.md
vendored
@@ -178,11 +178,11 @@ A binary stops starting after a `nix flake update`, or after
|
||||
dyld[57271]: Library not loaded: /nix/store/…-libresolv-93/lib/libresolv.9.dylib
|
||||
```
|
||||
|
||||
[`bin/check-nix-store-refs.sh`](../../bin/check-nix-store-refs.sh) finds the same
|
||||
thing without having to run anything, and names the file:
|
||||
[`bin/nix/check-nix-store-refs.sh`](../../bin/nix/check-nix-store-refs.sh) finds the
|
||||
same thing without having to run anything, and names the file:
|
||||
|
||||
```
|
||||
$ bin/check-nix-store-refs.sh ~/.conan2-nix
|
||||
$ bin/nix/check-nix-store-refs.sh ~/.conan2-nix
|
||||
::error file=/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig::references the Nix store at run time
|
||||
/Users/you/.conan2-nix/p/b/c-area24ded30c388c/p/bin/adig
|
||||
/nix/store/p4lp3xq4imd1qzqh08x8vcq2zfhi7rca-libresolv-93/lib/libresolv.9.dylib
|
||||
|
||||
2
external/antithesis-sdk/CMakeLists.txt
vendored
2
external/antithesis-sdk/CMakeLists.txt
vendored
@@ -6,7 +6,7 @@ project(antithesis-sdk-cpp VERSION 0.4.4 LANGUAGES CXX)
|
||||
add_library(antithesis-sdk-cpp INTERFACE antithesis_sdk.h)
|
||||
|
||||
# Note, both sections below created by xrpld project
|
||||
target_include_directories(antithesis-sdk-cpp INTERFACE
|
||||
target_include_directories(antithesis-sdk-cpp SYSTEM INTERFACE
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
)
|
||||
|
||||
12
flake.lock
generated
12
flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1781173989,
|
||||
"narHash": "sha256-fnzKKPvS+oieI/pTzotA5tkoM47EB1NpaBcgk4R97hE=",
|
||||
"lastModified": 1791130267,
|
||||
"narHash": "sha256-1sjwcQMcgAbmiip/VivBSiK8p2bTkQGOvCuO7vnwfx4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "8c91a71d13451abc40eb9dae8910f972f979852f",
|
||||
"rev": "9013764fcc0ea99fa16cf7aa7decf8a5c3889dd2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -47,11 +47,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1784611586,
|
||||
"narHash": "sha256-OfqgY+0hp/zseZB7uyH0U8kIDPS4scZZCyAurEplvG0=",
|
||||
"lastModified": 1791189933,
|
||||
"narHash": "sha256-Y8eN7ki0Urx4Ojf4w1xSpWg8uk/3lJqK+E0Oth77rH0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "14f58845249f3552a89b07772626b8d3c632fa86",
|
||||
"rev": "e60029353d0c48d216bc4b065168ccd4079c166f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -3,9 +3,84 @@
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Add two signed 64-bit integers, returning std::nullopt when the exact
|
||||
* mathematical sum is not representable in std::int64_t.
|
||||
*/
|
||||
[[nodiscard]] constexpr std::optional<std::int64_t>
|
||||
checkedAdd(std::int64_t a, std::int64_t b) noexcept
|
||||
{
|
||||
using L = std::numeric_limits<std::int64_t>;
|
||||
|
||||
if ((b > 0 && a > L::max() - b) || (b < 0 && a < L::min() - b))
|
||||
return std::nullopt;
|
||||
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract two signed 64-bit integers, returning std::nullopt when the exact
|
||||
* mathematical difference is not representable in std::int64_t.
|
||||
*/
|
||||
[[nodiscard]] constexpr std::optional<std::int64_t>
|
||||
checkedSub(std::int64_t a, std::int64_t b) noexcept
|
||||
{
|
||||
using L = std::numeric_limits<std::int64_t>;
|
||||
|
||||
if ((b > 0 && a < L::min() + b) || (b < 0 && a > L::max() + b))
|
||||
return std::nullopt;
|
||||
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static_assert(checkedAdd(0, 0) == 0);
|
||||
static_assert(checkedAdd(1, -1) == 0);
|
||||
static_assert(checkedAdd(-5, 2) == -3);
|
||||
static_assert(!checkedAdd(std::numeric_limits<std::int64_t>::max(), 1).has_value());
|
||||
static_assert(!checkedAdd(std::numeric_limits<std::int64_t>::min(), -1).has_value());
|
||||
static_assert(
|
||||
checkedAdd(std::numeric_limits<std::int64_t>::max() - 1, 1) ==
|
||||
std::numeric_limits<std::int64_t>::max());
|
||||
static_assert(
|
||||
checkedAdd(
|
||||
std::numeric_limits<std::int64_t>::min(),
|
||||
std::numeric_limits<std::int64_t>::max()) == -1);
|
||||
static_assert(
|
||||
checkedAdd(
|
||||
std::numeric_limits<std::int64_t>::max(),
|
||||
std::numeric_limits<std::int64_t>::min()) == -1);
|
||||
static_assert(
|
||||
!checkedAdd(std::numeric_limits<std::int64_t>::max(), std::numeric_limits<std::int64_t>::max())
|
||||
.has_value());
|
||||
static_assert(
|
||||
!checkedAdd(std::numeric_limits<std::int64_t>::min(), std::numeric_limits<std::int64_t>::min())
|
||||
.has_value());
|
||||
|
||||
static_assert(checkedSub(0, 0) == 0);
|
||||
static_assert(checkedSub(1, 1) == 0);
|
||||
static_assert(checkedSub(-5, 2) == -7);
|
||||
static_assert(checkedSub(-5, -2) == -3);
|
||||
static_assert(!checkedSub(std::numeric_limits<std::int64_t>::min(), 1).has_value());
|
||||
static_assert(!checkedSub(std::numeric_limits<std::int64_t>::max(), -1).has_value());
|
||||
static_assert(
|
||||
checkedSub(std::numeric_limits<std::int64_t>::min() + 1, 1) ==
|
||||
std::numeric_limits<std::int64_t>::min());
|
||||
static_assert(
|
||||
checkedSub(-1, std::numeric_limits<std::int64_t>::max()) ==
|
||||
std::numeric_limits<std::int64_t>::min());
|
||||
static_assert(
|
||||
!checkedSub(std::numeric_limits<std::int64_t>::max(), std::numeric_limits<std::int64_t>::min())
|
||||
.has_value());
|
||||
static_assert(
|
||||
!checkedSub(std::numeric_limits<std::int64_t>::min(), std::numeric_limits<std::int64_t>::max())
|
||||
.has_value());
|
||||
|
||||
/**
|
||||
* Calculate one number divided by another number in percentage.
|
||||
* The result is rounded up to the next integer, and capped in the range [0,100]
|
||||
|
||||
@@ -36,7 +36,7 @@ template <typename T>
|
||||
concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> ||
|
||||
std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>;
|
||||
|
||||
inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = []() {
|
||||
inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = [] {
|
||||
std::array<std::optional<int>, 256> t{};
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
|
||||
@@ -783,7 +783,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::scoped_lock<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
return std::thread([&, this] {
|
||||
int cacheRemovals = 0;
|
||||
int mapRemovals = 0;
|
||||
|
||||
@@ -863,7 +863,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::scoped_lock<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
return std::thread([&, this] {
|
||||
// NOLINTBEGIN https://github.com/XRPLF/rippled/issues/7056
|
||||
int cacheRemovals = 0;
|
||||
int mapRemovals = 0;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
namespace xrpl {
|
||||
|
||||
template <typename Key>
|
||||
static std::size_t
|
||||
std::size_t
|
||||
extract(Key const& key)
|
||||
{
|
||||
return key;
|
||||
|
||||
@@ -1604,7 +1604,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
|
||||
beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
|
||||
requires(!IsBoostReverseIterator<Iterator>::value)
|
||||
{
|
||||
unlinkAndDeleteElement(&*((pos++).iterator()));
|
||||
unlinkAndDeleteElement(&*(pos++).iterator());
|
||||
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
|
||||
}
|
||||
|
||||
@@ -1617,7 +1617,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
|
||||
requires(!IsBoostReverseIterator<Iterator>::value)
|
||||
{
|
||||
for (; first != last;)
|
||||
unlinkAndDeleteElement(&*((first++).iterator()));
|
||||
unlinkAndDeleteElement(&*(first++).iterator());
|
||||
|
||||
return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator());
|
||||
}
|
||||
|
||||
@@ -2404,7 +2404,7 @@ beast::detail::AgedContainerIterator<false, Iterator>
|
||||
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::erase(
|
||||
beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
|
||||
{
|
||||
unlinkAndDeleteElement(&*((pos++).iterator()));
|
||||
unlinkAndDeleteElement(&*(pos++).iterator());
|
||||
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
|
||||
}
|
||||
|
||||
@@ -2424,7 +2424,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
|
||||
beast::detail::AgedContainerIterator<IsConst, Iterator> last)
|
||||
{
|
||||
for (; first != last;)
|
||||
unlinkAndDeleteElement(&*((first++).iterator()));
|
||||
unlinkAndDeleteElement(&*(first++).iterator());
|
||||
|
||||
return beast::detail::AgedContainerIterator<false, Iterator>(first.iterator());
|
||||
}
|
||||
|
||||
@@ -390,7 +390,7 @@ void
|
||||
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||
requires(IsContiguouslyHashable<Key, Hasher>::value)
|
||||
{
|
||||
h(&(v.begin()), v.size() * sizeof(Key));
|
||||
h(&v.begin(), v.size() * sizeof(Key));
|
||||
}
|
||||
// tuple
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace beast::insight {
|
||||
class HookImpl : public std::enable_shared_from_this<HookImpl>
|
||||
{
|
||||
public:
|
||||
using HandlerType = std::function<void(void)>;
|
||||
using HandlerType = std::function<void()>;
|
||||
|
||||
virtual ~HookImpl() = 0;
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@ isMulticast(Address const& addr)
|
||||
inline bool
|
||||
isPrivate(Address const& addr)
|
||||
{
|
||||
return (addr.is_v4()) ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6());
|
||||
return addr.is_v4() ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +70,7 @@ isPrivate(Address const& addr)
|
||||
inline bool
|
||||
isPublic(Address const& addr)
|
||||
{
|
||||
return (addr.is_v4()) ? isPublic(addr.to_v4()) : isPublic(addr.to_v6());
|
||||
return addr.is_v4() ? isPublic(addr.to_v4()) : isPublic(addr.to_v6());
|
||||
}
|
||||
|
||||
} // namespace ip
|
||||
|
||||
@@ -34,7 +34,7 @@ typeName()
|
||||
name += " volatile";
|
||||
if (std::is_lvalue_reference_v<T>)
|
||||
{
|
||||
name += "&";
|
||||
name += '&';
|
||||
}
|
||||
else if (std::is_rvalue_reference_v<T>)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace beast::unit_test {
|
||||
namespace detail {
|
||||
|
||||
template <class String>
|
||||
static std::string
|
||||
std::string
|
||||
makeReason(String const& reason, char const* file, int line)
|
||||
{
|
||||
std::string s(reason);
|
||||
|
||||
@@ -47,8 +47,8 @@ public:
|
||||
template <class F, class... Args>
|
||||
explicit Thread(Suite& s, F&& f, Args&&... args) : s_(&s)
|
||||
{
|
||||
std::function<void(void)> b = [f = std::forward<F>(f),
|
||||
... args = std::forward<Args>(args)]() mutable {
|
||||
std::function<void()> b = [f = std::forward<F>(f),
|
||||
... args = std::forward<Args>(args)] mutable {
|
||||
std::invoke(f, args...);
|
||||
};
|
||||
t_ = std::thread(&Thread::run, this, std::move(b));
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
|
||||
private:
|
||||
void
|
||||
run(std::function<void(void)> f)
|
||||
run(std::function<void()> f)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -54,7 +54,7 @@ JobQueue::Coro::post()
|
||||
}
|
||||
|
||||
// sp keeps 'this' alive
|
||||
if (jq_.addJob(type_, name_, [this, sp = shared_from_this()]() { resume(); }))
|
||||
if (jq_.addJob(type_, name_, [this, sp = shared_from_this()] { resume(); }))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -130,7 +130,7 @@ inline void
|
||||
JobQueue::Coro::join()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutexRun_);
|
||||
cv_.wait(lk, [this]() { return !running_; });
|
||||
cv_.wait(lk, [this] { return !running_; });
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/json/json_forwards.h>
|
||||
|
||||
#include <concepts>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
@@ -198,6 +200,15 @@ public:
|
||||
*/
|
||||
Value(StaticString const& value);
|
||||
Value(std::string const& value);
|
||||
/**
|
||||
* @brief Constructs a value from a string view.
|
||||
*
|
||||
* The characters are copied, so the view need not outlive the call and need
|
||||
* not be NUL-terminated.
|
||||
*
|
||||
* @param value The characters to copy.
|
||||
*/
|
||||
Value(std::string_view value);
|
||||
Value(bool value);
|
||||
Value(Value const& other);
|
||||
~Value();
|
||||
@@ -472,6 +483,32 @@ toJson(xrpl::Number const& number)
|
||||
bool
|
||||
operator==(Value const&, Value const&);
|
||||
|
||||
/**
|
||||
* Compares a value with a string view, reading the value's characters in place
|
||||
* rather than building a Value from the view.
|
||||
*
|
||||
* Constrained to the exact type: a string literal converts equally well to a
|
||||
* view and to a Value, so a plain overload makes `value == "literal"`
|
||||
* ambiguous.
|
||||
*
|
||||
* @param x The value to compare.
|
||||
* @param y The characters to compare it against.
|
||||
* @return Whether `x` is a string whose characters up to its first NUL are
|
||||
* exactly the characters of `y`.
|
||||
*/
|
||||
template <class T>
|
||||
requires std::same_as<T, std::string_view>
|
||||
bool
|
||||
operator==(Value const& x, T y)
|
||||
{
|
||||
if (!x.isString())
|
||||
return false;
|
||||
|
||||
// A string `Value` can hold a null pointer, which names no characters, so it equals no view.
|
||||
char const* const s = x.asCString();
|
||||
return s != nullptr && std::string_view{s} == y;
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(Value const&, Value const&);
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
@@ -212,7 +211,7 @@ canWithdraw(
|
||||
ReadView const& view,
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
AccountRootEntryR const& toSle,
|
||||
SLE::ConstRef toSle,
|
||||
STAmount const& amount,
|
||||
bool hasDestinationTag,
|
||||
std::optional<std::vector<UInt256>> const& credentialIDs = std::nullopt);
|
||||
|
||||
@@ -7,20 +7,9 @@
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
struct Adjustment
|
||||
{
|
||||
std::int32_t ownerCountDelta = 0;
|
||||
std::int32_t accountCountDelta = 0;
|
||||
};
|
||||
|
||||
template <typename ViewT>
|
||||
class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT>
|
||||
{
|
||||
@@ -38,123 +27,6 @@ public:
|
||||
: Base(keylet::account(id), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the account reserve, in drops.
|
||||
*
|
||||
* Actual owner count can be adjusted by delta in ownerCountAdj
|
||||
* Actual reserve count can be adjusted by delta in accountCountAdj
|
||||
* The reserve is calculated as:
|
||||
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
|
||||
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
|
||||
*
|
||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
|
||||
* to subtract.
|
||||
* @return The account reserve amount in drops
|
||||
*/
|
||||
[[nodiscard]] XRPAmount
|
||||
reserve(Adjustment adj = {}) const;
|
||||
|
||||
/**
|
||||
* Return number of the objects which reserve is covered by the account (so called "owner
|
||||
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
|
||||
*
|
||||
* @param ownerCountAdj Adjustment to the owner count (default: 0)
|
||||
* @return The adjusted owner count
|
||||
*/
|
||||
[[nodiscard]] std::uint32_t
|
||||
ownerCount(std::int32_t ownerCountAdj = 0) const;
|
||||
|
||||
/**
|
||||
* Check if this account has sufficient reserve.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param accBalance The account's balance
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative
|
||||
* to subtract.
|
||||
* @param insufReserveCode The transaction result code to return if the reserve is
|
||||
* insufficient (default: tecINSUFFICIENT_RESERVE).
|
||||
* @return Transaction result code
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkReserve(
|
||||
ApplyViewContext ctx,
|
||||
XRPAmount accBalance,
|
||||
std::optional<AccountRootEntry<ReadView>> const& sponsorSle,
|
||||
Adjustment adj,
|
||||
TER insufReserveCode = tecINSUFFICIENT_RESERVE) const;
|
||||
|
||||
/**
|
||||
* Check if this account has sufficient reserve, deriving the sponsor internally.
|
||||
*
|
||||
* Equivalent to the overload above, but resolves the sponsor via
|
||||
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use this
|
||||
* in the common case where the sponsor is simply the transaction's reserve
|
||||
* sponsor for this account. Callers that must force the account's-own-reserve branch
|
||||
* (passing a null sponsor) or supply a different sponsor should use the
|
||||
* explicit overload above.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param accBalance The account's balance
|
||||
* @param adj Reserve adjustments (owner/account count deltas)
|
||||
* @return Transaction result code
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkReserve(ApplyViewContext ctx, XRPAmount accBalance, Adjustment adj) const;
|
||||
|
||||
/**
|
||||
* Increase owner-count fields when the caller supplies the sponsor.
|
||||
*
|
||||
* This helper does not create a ledger object. It updates reserve accounting
|
||||
* after the caller has created/updated an object.
|
||||
* If sponsorSle is provided, this also adjusts the account's sponsored count
|
||||
* and the sponsor's sponsoring count.
|
||||
*
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param count Amount to add to the owner count
|
||||
*/
|
||||
void
|
||||
increaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
|
||||
requires Base::kIsWritable;
|
||||
|
||||
/**
|
||||
* Increase owner-count fields, deriving the tx reserve sponsor internally.
|
||||
*
|
||||
* Equivalent to the overload above, but resolves the sponsor via
|
||||
* getEffectiveTxReserveSponsor(ctx, *this) instead of taking it explicitly. Use
|
||||
* this when the sponsor is the transaction's reserve sponsor for this account
|
||||
* (the common create path). Deletion paths, which derive the sponsor from an
|
||||
* object's sfSponsor field, should keep using the explicit overload.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param count Amount to add to the owner count
|
||||
*/
|
||||
void
|
||||
increaseOwnerCount(ApplyViewContext ctx, std::uint32_t count)
|
||||
requires Base::kIsWritable;
|
||||
|
||||
/**
|
||||
* Decrease owner-count fields when the caller supplies the sponsor.
|
||||
*
|
||||
* This helper does not delete a ledger object. It updates reserve accounting
|
||||
* after the caller has removed an owner-counted reserve, or for special
|
||||
* owner-count changes whose sponsor cannot be derived from an object's
|
||||
* sfSponsor field.
|
||||
*
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param count Amount to remove from the owner count
|
||||
*/
|
||||
void
|
||||
decreaseOwnerCount(std::optional<AccountRootEntry<ApplyView>>& sponsorSle, std::uint32_t count)
|
||||
requires Base::kIsWritable;
|
||||
|
||||
private:
|
||||
void
|
||||
adjustOwnerCountSigned(
|
||||
std::optional<AccountRootEntry<ApplyView>>& sponsorSle,
|
||||
std::int32_t adjustment)
|
||||
requires Base::kIsWritable;
|
||||
};
|
||||
|
||||
using AccountRootEntryR = AccountRootEntry<ReadView>;
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -25,6 +31,52 @@ public:
|
||||
: Base(keylet::amendments(), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of amendments this entry reports as enabled.
|
||||
*
|
||||
* @return the set of enabled amendments.
|
||||
*/
|
||||
[[nodiscard]] std::set<UInt256>
|
||||
enabledAmendments() const
|
||||
{
|
||||
std::set<UInt256> amendments;
|
||||
|
||||
if (this->exists() && (*this)->isFieldPresent(sfAmendments))
|
||||
{
|
||||
auto const& v = (*this)->getFieldV256(sfAmendments);
|
||||
amendments.insert_range(v);
|
||||
}
|
||||
|
||||
return amendments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of amendments that have achieved majority, to the time
|
||||
* majority was reached.
|
||||
*
|
||||
* @return a map of amendment to the time majority was reached.
|
||||
*/
|
||||
[[nodiscard]] std::map<UInt256, NetClock::time_point>
|
||||
majorityAmendments() const
|
||||
{
|
||||
std::map<UInt256, NetClock::time_point> ret;
|
||||
|
||||
if (this->exists() && (*this)->isFieldPresent(sfMajorities))
|
||||
{
|
||||
using TimePoint = NetClock::time_point;
|
||||
using Duration = TimePoint::duration;
|
||||
|
||||
auto const majorities = (*this)->getFieldArray(sfMajorities);
|
||||
|
||||
for (auto const& m : majorities)
|
||||
{
|
||||
ret[m.getFieldH256(sfAmendment)] = TimePoint(Duration(m.getFieldU32(sfCloseTime)));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
using AmendmentsEntryR = AmendmentsEntry<ReadView>;
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -25,6 +31,31 @@ public:
|
||||
: Base(keylet::skip(), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a hash `diff` slots back from the most recent entry in the
|
||||
* sfHashes vector (diff == 0 is the most recent entry).
|
||||
*
|
||||
* Callers decide which skip list entry to read and how to translate a
|
||||
* target ledger sequence into `diff`; this only does the bounds check
|
||||
* and vector indexing shared by both the recent (stride 1) and distant
|
||||
* (stride 256) skip lists.
|
||||
*
|
||||
* @param diff how many slots back from the most recent hash to look up;
|
||||
* 0 is the most recent hash.
|
||||
* @return the hash at that slot, or std::nullopt if the entry does not
|
||||
* exist or `diff` is out of range.
|
||||
*/
|
||||
[[nodiscard]] std::optional<UInt256>
|
||||
hashAt(std::size_t diff) const
|
||||
{
|
||||
if (!this->exists())
|
||||
return std::nullopt;
|
||||
STVector256 const vec = (*this)->getFieldV256(sfHashes);
|
||||
if (vec.size() > diff)
|
||||
return vec[vec.size() - diff - 1];
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
using LedgerHashesEntryR = LedgerHashesEntry<ReadView>;
|
||||
|
||||
@@ -353,7 +353,7 @@ changeSpotPriceQuality(
|
||||
}
|
||||
if (auto const nTakerPaysPropose = (-b + root2(res)) / (2 * a); nTakerPaysPropose > 0)
|
||||
{
|
||||
auto const nTakerPays = [&]() {
|
||||
auto const nTakerPays = [&] {
|
||||
// The fee might make the AMM offer quality less than CLOB
|
||||
// quality. Therefore, AMM offer has to satisfy this constraint:
|
||||
// o / i >= q. Substituting o with swapAssetIn() gives: i <= O /
|
||||
@@ -372,8 +372,8 @@ changeSpotPriceQuality(
|
||||
auto const takerPays =
|
||||
toAmount<TIn>(getAsset(pool.in), nTakerPays, Number::RoundingMode::Upward);
|
||||
// should not fail
|
||||
if (auto amounts = TAmounts<TIn, TOut>{takerPays, swapAssetIn(pool, takerPays, tfee)};
|
||||
Quality{amounts} < quality &&
|
||||
auto amounts = TAmounts<TIn, TOut>{takerPays, swapAssetIn(pool, takerPays, tfee)};
|
||||
if (Quality{amounts} < quality &&
|
||||
!withinRelativeDistance(Quality{amounts}, quality, Number(1, -7)))
|
||||
{
|
||||
JLOG(j.error()) << "changeSpotPriceQuality failed: " << to_string(pool.in) << " "
|
||||
@@ -382,21 +382,19 @@ changeSpotPriceQuality(
|
||||
<< " " << to_string(amounts.out);
|
||||
Throw<std::runtime_error>("changeSpotPriceQuality failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " << to_string(pool.in) << " "
|
||||
<< to_string(pool.out) << " "
|
||||
<< " " << quality << " " << tfee << " " << to_string(amounts.in)
|
||||
<< " " << to_string(amounts.out);
|
||||
return amounts;
|
||||
}
|
||||
|
||||
JLOG(j.trace()) << "changeSpotPriceQuality succeeded: " << to_string(pool.in) << " "
|
||||
<< to_string(pool.out) << " "
|
||||
<< " " << quality << " " << tfee << " " << to_string(amounts.in) << " "
|
||||
<< to_string(amounts.out);
|
||||
return amounts;
|
||||
}
|
||||
JLOG(j.trace()) << "changeSpotPriceQuality calc failed: " << to_string(pool.in) << " "
|
||||
<< to_string(pool.out) << " " << quality << " " << tfee;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto amounts = [&]() {
|
||||
auto amounts = [&] {
|
||||
bool const inIntegral = getAsset(pool.in).integral();
|
||||
bool const outIntegral = getAsset(pool.out).integral();
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Rate.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
@@ -46,55 +46,30 @@ isGlobalFrozen(ReadView const& view, AccountID const& issuer);
|
||||
[[nodiscard]] XRPAmount
|
||||
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
|
||||
|
||||
namespace detail {
|
||||
struct Adjustment
|
||||
{
|
||||
std::int32_t ownerCountDelta = 0;
|
||||
std::int32_t accountCountDelta = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* An owner count cannot be negative. If adjustment would cause a negative
|
||||
* owner count, clamp the owner count at 0. Similarly for overflow. This
|
||||
* adjustment allows the ownerCount to be adjusted up or down in multiple steps.
|
||||
* If id != std::nullopt, then do error reporting.
|
||||
* Returns the account reserve, in drops.
|
||||
*
|
||||
* Shared by AccountRootEntry::ownerCount() and the owner-count helpers.
|
||||
* Actual owner count can be adjusted by delta in ownerCountAdj
|
||||
* Actual reserve count can be adjusted by delta in accountCountAdj
|
||||
* The reserve is calculated as:
|
||||
* (ownerCount + "sponsoring object count" - "sponsored object count" + additionalOwnerCount) *
|
||||
* increment + (1 if not sponsored account + sponsoringAccountCount) * "reserve base"
|
||||
*
|
||||
* @param currentOwnerCount The owner count before adjustment
|
||||
* @param ownerCountAdj Positive to add to count, negative to reduce count
|
||||
* @param id The account ID to use for error reporting, or std::nullopt to
|
||||
* skip error reporting
|
||||
* @param view The ledger view to read from
|
||||
* @param sle The ledger entry for the account
|
||||
* @param j Journal for logging
|
||||
* @return The adjusted owner count
|
||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
|
||||
* subtract.
|
||||
* @return The account reserve amount in drops
|
||||
*/
|
||||
std::uint32_t
|
||||
confineOwnerCount(
|
||||
std::uint32_t currentOwnerCount,
|
||||
std::int32_t ownerCountAdj,
|
||||
std::optional<AccountID> const& id = std::nullopt,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
/**
|
||||
* Clamps and writes an owner-count field of sle, then updates sle in view.
|
||||
*
|
||||
* Shared by AccountRootEntry and adjustLoanBrokerOwnerCount().
|
||||
*
|
||||
* @return The adjusted owner count
|
||||
*/
|
||||
std::uint32_t
|
||||
adjustOwnerCountImpl(
|
||||
ApplyView& view,
|
||||
SLE::Ref sle,
|
||||
SF_UINT32 const& sfield,
|
||||
AccountID const& accID,
|
||||
std::int32_t ownerCountAdj,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
* Returns the number of account reserves funded by this account: 1 for itself
|
||||
* (0 if sponsored by another account) plus the count of accounts it sponsors.
|
||||
* Shared by AccountRootEntry::reserve() and xrpLiquid().
|
||||
*/
|
||||
std::uint32_t
|
||||
accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, beast::Journal j);
|
||||
|
||||
} // namespace detail
|
||||
[[nodiscard]] XRPAmount
|
||||
accountReserve(ReadView const& view, SLE::ConstRef sle, beast::Journal j, Adjustment adj = {});
|
||||
|
||||
/**
|
||||
* Convenience overload that accepts AccountID instead of SLE.
|
||||
@@ -109,9 +84,114 @@ accountCountImpl(AccountRootEntryR const& sle, std::int32_t accountCountAdj, bea
|
||||
[[nodiscard]] inline XRPAmount
|
||||
accountReserve(ReadView const& view, AccountID const& id, beast::Journal j, Adjustment adj = {})
|
||||
{
|
||||
return AccountRootEntryR(id, view, j).reserve(adj);
|
||||
return accountReserve(view, view.read(keylet::account(id)), j, adj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an account has sufficient reserve.
|
||||
*
|
||||
* @param view The ledger view to read from
|
||||
* @param tx The transaction being processed
|
||||
* @param accSle The account's ledger entry
|
||||
* @param accBalance The account's balance
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param adj Adjustment to the owner/account count (default: 0/0). Positive to add, negative to
|
||||
* subtract.
|
||||
* @param j Journal for logging (default: null sink)
|
||||
* @param insufReserveCode The transaction result code to return if the reserve is insufficient
|
||||
* (default: tecINSUFFICIENT_RESERVE).
|
||||
* @return Transaction result code
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkReserve(
|
||||
ApplyViewContext ctx,
|
||||
SLE::ConstRef accSle,
|
||||
XRPAmount accBalance,
|
||||
SLE::ConstRef sponsorSle,
|
||||
Adjustment adj,
|
||||
beast::Journal j,
|
||||
TER insufReserveCode = tecINSUFFICIENT_RESERVE);
|
||||
|
||||
/**
|
||||
* Check if an account has sufficient reserve, deriving the sponsor internally.
|
||||
*
|
||||
* Equivalent to the overload above, but resolves the sponsor via
|
||||
* getEffectiveTxReserveSponsor(ctx, accSle) instead of taking it explicitly. Use this
|
||||
* in the common case where the sponsor is simply the transaction's reserve
|
||||
* sponsor for accSle. Callers that must force the account's-own-reserve branch
|
||||
* (passing a null sponsor) or supply a different sponsor should use the
|
||||
* explicit overload above.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param accSle The account's ledger entry
|
||||
* @param accBalance The account's balance
|
||||
* @param adj Reserve adjustments (owner/account count deltas)
|
||||
* @param j Journal for logging (default: null sink)
|
||||
* @return Transaction result code
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkReserve(
|
||||
ApplyViewContext ctx,
|
||||
SLE::ConstRef accSle,
|
||||
XRPAmount accBalance,
|
||||
Adjustment adj,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
/**
|
||||
* Return number of the objects which reserve is covered by the account(sle) (so called "owner
|
||||
* count"). Actual owner count can be adjusted by delta in ownerCountAdj.
|
||||
*
|
||||
* @param sle The account's ledger entry
|
||||
* @param j Journal for logging
|
||||
* @param ownerCountAdj Adjustment to the owner count (default: 0)
|
||||
* @return The adjusted owner count
|
||||
*/
|
||||
std::uint32_t
|
||||
ownerCount(SLE::ConstRef sle, beast::Journal j, std::int32_t ownerCountAdj = 0);
|
||||
|
||||
/**
|
||||
* Increase owner-count fields when the caller supplies the sponsor.
|
||||
*
|
||||
* This helper does not create a ledger object. It updates reserve accounting
|
||||
* after the caller has created/updated an object.
|
||||
* If sponsorSle is provided, this also adjusts the account's sponsored count
|
||||
* and the sponsor's sponsoring count.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param count Amount to add to the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
void
|
||||
increaseOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::Ref accountSle,
|
||||
SLE::Ref sponsorSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
* Increase owner-count fields, deriving the tx reserve sponsor internally.
|
||||
*
|
||||
* Equivalent to the overload above, but resolves the sponsor via
|
||||
* getEffectiveTxReserveSponsor(ctx, accountSle) instead of taking it explicitly. Use
|
||||
* this when the sponsor is the transaction's reserve sponsor for accountSle
|
||||
* (the common create path). Deletion paths, which derive the sponsor from an
|
||||
* object's sfSponsor field, should keep using the explicit overload.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param count Amount to add to the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
void
|
||||
increaseOwnerCount(
|
||||
ApplyViewContext ctx,
|
||||
SLE::Ref accountSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
* Convenience overload that accepts AccountID instead of SLE references.
|
||||
*
|
||||
@@ -129,13 +209,36 @@ increaseOwnerCount(
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
AccountRootEntryW accountSle(account, view, j);
|
||||
std::optional<AccountRootEntryW> sponsorSle;
|
||||
if (sponsor)
|
||||
sponsorSle.emplace(*sponsor, view);
|
||||
accountSle.increaseOwnerCount(sponsorSle, count);
|
||||
increaseOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(account)),
|
||||
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
|
||||
count,
|
||||
j);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease owner-count fields when the caller supplies the sponsor.
|
||||
*
|
||||
* This helper does not delete a ledger object. It updates reserve accounting
|
||||
* after the caller has removed an owner-counted reserve, or for special
|
||||
* owner-count changes whose sponsor cannot be derived from an object's
|
||||
* sfSponsor field.
|
||||
*
|
||||
* @param view The apply view for making changes
|
||||
* @param accountSle The account's ledger entry
|
||||
* @param sponsorSle The sponsor's ledger entry (if applicable)
|
||||
* @param count Amount to remove from the owner count
|
||||
* @param j Journal for logging
|
||||
*/
|
||||
void
|
||||
decreaseOwnerCount(
|
||||
ApplyView& view,
|
||||
SLE::Ref accountSle,
|
||||
SLE::Ref sponsorSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
* Convenience overload that accepts AccountID instead of SLE references.
|
||||
*
|
||||
@@ -153,11 +256,12 @@ decreaseOwnerCount(
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
AccountRootEntryW accountSle(account, view, j);
|
||||
std::optional<AccountRootEntryW> sponsorSle;
|
||||
if (sponsor)
|
||||
sponsorSle.emplace(*sponsor, view);
|
||||
accountSle.decreaseOwnerCount(sponsorSle, count);
|
||||
decreaseOwnerCount(
|
||||
view,
|
||||
view.peek(keylet::account(account)),
|
||||
sponsor ? view.peek(keylet::account(*sponsor)) : SLE::pointer(),
|
||||
count,
|
||||
j);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +281,7 @@ decreaseOwnerCount(
|
||||
void
|
||||
decreaseOwnerCountForObject(
|
||||
ApplyView& view,
|
||||
AccountRootEntryW& accountSle,
|
||||
SLE::Ref accountSle,
|
||||
SLE::Ref objectSle,
|
||||
std::uint32_t count,
|
||||
beast::Journal j);
|
||||
@@ -199,7 +303,7 @@ decreaseOwnerCountForObject(
|
||||
std::uint32_t count,
|
||||
beast::Journal j)
|
||||
{
|
||||
AccountRootEntryW accountSle(account, view);
|
||||
SLE::Ref accountSle = view.peek(keylet::account(account));
|
||||
decreaseOwnerCountForObject(view, accountSle, objectSle, count, j);
|
||||
}
|
||||
|
||||
@@ -263,7 +367,7 @@ getPseudoAccountFields();
|
||||
* - null pointer
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isPseudoAccount(AccountRootEntryR const& sleAcct);
|
||||
isPseudoAccount(SLE::const_pointer sleAcct);
|
||||
|
||||
/**
|
||||
* Convenience overload that reads the account from the view.
|
||||
@@ -271,7 +375,7 @@ isPseudoAccount(AccountRootEntryR const& sleAcct);
|
||||
[[nodiscard]] inline bool
|
||||
isPseudoAccount(ReadView const& view, AccountID const& accountId)
|
||||
{
|
||||
return isPseudoAccount(AccountRootEntryR(accountId, view));
|
||||
return isPseudoAccount(view.read(keylet::account(accountId)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,6 +396,6 @@ createPseudoAccount(ApplyView& view, UInt256 const& pseudoOwnerKey, SField const
|
||||
* - If the SLE requires a destination tag, checks that there is a tag.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkDestinationAndTag(AccountRootEntryR const& toSle, bool hasDestinationTag);
|
||||
checkDestinationAndTag(SLE::ConstRef toSle, bool hasDestinationTag);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
@@ -27,31 +29,290 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Before fixCleanup3_2_0, EscrowCancel passes the escrow SLE as sleDest.
|
||||
* Return what the old reserve check returned for it, without adopting a
|
||||
* non-AccountRoot SLE into an AccountRootEntry: the tx reserve sponsor's
|
||||
* error if the escrow owner submitted the tx, else tefINTERNAL.
|
||||
* Validate that @p account may lock @p amount of a token for later delivery
|
||||
* to @p dest.
|
||||
*
|
||||
* @param ctx the apply view context for the escrow transaction.
|
||||
* @param sleDest the non-AccountRoot SLE that was passed as the destination.
|
||||
* @return the tx reserve sponsor's error code if the escrow owner submitted
|
||||
* the tx, else tefINTERNAL.
|
||||
* The lock-side counterpart of escrowUnlockPreclaimHelper: every issuer
|
||||
* control (locking opt-in, authorization, freeze/lock, transferability,
|
||||
* spendable balance) that gates locking token value lives here, so any
|
||||
* transactor that locks funds applies the same rules. The signature is
|
||||
* view-based rather than PreclaimContext-based so it can also run from
|
||||
* doApply.
|
||||
*/
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
escrowLockPreclaimHelper(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
AccountID const& dest,
|
||||
STAmount const& amount,
|
||||
beast::Journal j);
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowDestNotAccountResult(ApplyViewContext ctx, SLE::ConstRef sleDest)
|
||||
escrowLockPreclaimHelper<Issue>(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
AccountID const& dest,
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (sleDest->getAccountID(sfAccount) == ctx.tx[sfAccount])
|
||||
{
|
||||
if (auto const sponsor = getTxReserveSponsor(ctx); !sponsor)
|
||||
return sponsor.error(); // LCOV_EXCL_LINE
|
||||
}
|
||||
return tefINTERNAL;
|
||||
auto const& issue = amount.get<Issue>();
|
||||
auto const& issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the account, return tecNO_PERMISSION
|
||||
if (issuer == account)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
|
||||
auto const sleIssuer = view.read(keylet::account(issuer));
|
||||
if (!sleIssuer)
|
||||
return tecNO_ISSUER;
|
||||
if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the account does not have a trustline to the issuer, return tecNO_LINE
|
||||
auto const sleRippleState = view.read(keylet::trustLine(account, issuer, issue.currency));
|
||||
if (!sleRippleState)
|
||||
return tecNO_LINE;
|
||||
|
||||
STAmount const balance = (*sleRippleState)[sfBalance];
|
||||
|
||||
// If balance is positive, issuer must have higher address than account
|
||||
if (balance > beast::kZero && issuer < account)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If balance is negative, issuer must have lower address than account
|
||||
if (balance < beast::kZero && issuer > account)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If the issuer has requireAuth set, check if the account is authorized
|
||||
if (auto const ter = requireAuth(view, issue, account); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has requireAuth set, check if the destination is authorized
|
||||
if (auto const ter = requireAuth(view, issue, dest); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has frozen the account, return tecFROZEN
|
||||
if (isFrozen(view, account, issue))
|
||||
return tecFROZEN;
|
||||
|
||||
// If the issuer has frozen the destination, return tecFROZEN
|
||||
if (isFrozen(view, dest, issue))
|
||||
return tecFROZEN;
|
||||
|
||||
STAmount const spendableAmount =
|
||||
accountHolds(view, account, issue.currency, issuer, FreezeHandling::IgnoreFreeze, j);
|
||||
|
||||
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount <= beast::kZero)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the spendable amount is less than the amount, return
|
||||
// tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount < amount)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the amount is not addable to the balance, return tecPRECISION_LOSS
|
||||
if (!canAdd(spendableAmount, amount))
|
||||
return tecPRECISION_LOSS;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
template <>
|
||||
inline TER
|
||||
escrowLockPreclaimHelper<MPTIssue>(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
AccountID const& dest,
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
{
|
||||
AccountID const issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the account, return tecNO_PERMISSION
|
||||
if (issuer == account)
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
|
||||
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
|
||||
auto const sleIssuance = view.read(issuanceKey);
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
// If the lsfMPTCanEscrow is not enabled, return tecNO_PERMISSION
|
||||
if (!sleIssuance->isFlag(lsfMPTCanEscrow))
|
||||
return tecNO_PERMISSION;
|
||||
|
||||
// If the issuer is not the same as the issuer of the mpt, return
|
||||
// tecNO_PERMISSION
|
||||
if (sleIssuance->getAccountID(sfIssuer) != issuer)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If the account does not have the mpt, return tecOBJECT_NOT_FOUND
|
||||
if (!view.exists(keylet::mptoken(issuanceKey.key, account)))
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
// If the issuer has requireAuth set, check if the account is
|
||||
// authorized
|
||||
auto const& mptIssue = amount.get<MPTIssue>();
|
||||
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has requireAuth set, check if the destination is
|
||||
// authorized
|
||||
if (auto const ter = requireAuth(view, mptIssue, dest, AuthType::WeakAuth); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has frozen the account, return tecLOCKED
|
||||
if (isFrozen(view, account, *sleIssuance))
|
||||
return tecLOCKED;
|
||||
|
||||
// If the issuer has frozen the destination, return tecLOCKED
|
||||
if (isFrozen(view, dest, *sleIssuance))
|
||||
return tecLOCKED;
|
||||
|
||||
// If the mpt cannot be transferred, return tecNO_AUTH
|
||||
if (auto const ter = canTransfer(view, mptIssue, account, dest); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
STAmount const spendableAmount = accountHolds(
|
||||
view,
|
||||
account,
|
||||
amount.get<MPTIssue>(),
|
||||
FreezeHandling::IgnoreFreeze,
|
||||
AuthHandling::IgnoreAuth,
|
||||
j);
|
||||
|
||||
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount <= beast::kZero)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the spendable amount is less than the amount, return
|
||||
// tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount < amount)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
escrowLockApplyHelper(
|
||||
ApplyView& view,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
STAmount const& amount,
|
||||
beast::Journal journal);
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowLockApplyHelper<Issue>(
|
||||
ApplyView& view,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
STAmount const& amount,
|
||||
beast::Journal journal)
|
||||
{
|
||||
// Defensive: Issuer cannot create an escrow
|
||||
if (issuer == sender)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const ter =
|
||||
directSendNoFee(view, sender, issuer, amount, !amount.holds<MPTIssue>(), journal);
|
||||
if (!isTesSuccess(ter))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowLockApplyHelper<MPTIssue>(
|
||||
ApplyView& view,
|
||||
AccountID const& issuer,
|
||||
AccountID const& sender,
|
||||
STAmount const& amount,
|
||||
beast::Journal journal)
|
||||
{
|
||||
// Defensive: Issuer cannot create an escrow
|
||||
if (issuer == sender)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
auto const ter = lockEscrowMPT(view, sender, amount, journal);
|
||||
if (!isTesSuccess(ter))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
escrowUnlockPreclaimHelper(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
bool checkFreeze = true);
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowUnlockPreclaimHelper<Issue>(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
bool checkFreeze)
|
||||
{
|
||||
AccountID const& issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the account, return tesSUCCESS
|
||||
if (issuer == account)
|
||||
return tesSUCCESS;
|
||||
|
||||
// If the issuer has requireAuth set, check if the destination is authorized
|
||||
if (auto const ter = requireAuth(view, amount.get<Issue>(), account); !isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has deep frozen the destination, return tecFROZEN
|
||||
if (checkFreeze &&
|
||||
isDeepFrozen(view, account, amount.get<Issue>().currency, amount.getIssuer()))
|
||||
return tecFROZEN;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline TER
|
||||
escrowUnlockPreclaimHelper<MPTIssue>(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
STAmount const& amount,
|
||||
bool checkFreeze)
|
||||
{
|
||||
AccountID const& issuer = amount.getIssuer();
|
||||
// If the issuer is the same as the account, return tesSUCCESS
|
||||
if (issuer == account)
|
||||
return tesSUCCESS;
|
||||
|
||||
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
|
||||
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
|
||||
auto const sleIssuance = view.read(issuanceKey);
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
// If the issuer has requireAuth set, check if the account is
|
||||
// authorized
|
||||
auto const& mptIssue = amount.get<MPTIssue>();
|
||||
if (auto const ter = requireAuth(view, mptIssue, account, AuthType::WeakAuth);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// If the issuer has frozen the account, return tecLOCKED
|
||||
if (checkFreeze && isFrozen(view, account, *sleIssuance))
|
||||
return tecLOCKED;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <ValidIssueType T>
|
||||
TER
|
||||
@@ -81,9 +342,6 @@ escrowUnlockApplyHelper<Issue>(
|
||||
bool createAsset,
|
||||
beast::Journal journal)
|
||||
{
|
||||
auto const& issue = amount.get<Issue>();
|
||||
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
|
||||
bool const recvLow = issuer > receiver;
|
||||
bool const senderIssuer = issuer == sender;
|
||||
bool const receiverIssuer = issuer == receiver;
|
||||
|
||||
@@ -93,20 +351,25 @@ escrowUnlockApplyHelper<Issue>(
|
||||
if (receiverIssuer)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const& issue = amount.get<Issue>();
|
||||
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
|
||||
bool const recvLow = issuer > receiver;
|
||||
|
||||
if (!ctx.view.exists(trustLineKey) && createAsset)
|
||||
{
|
||||
// Can the account cover the trust line's reserve?
|
||||
if (sleDest->getType() != ltACCOUNT_ROOT)
|
||||
return detail::escrowDestNotAccountResult(ctx, sleDest);
|
||||
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
|
||||
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
|
||||
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
|
||||
if (!sponsorSle)
|
||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||
|
||||
auto& sponsor = *sponsorSle;
|
||||
|
||||
if (auto const ret = destSle.checkReserve(
|
||||
ctx, xrpBalance, sponsor, {.ownerCountDelta = 1}, tecNO_LINE_INSUF_RESERVE);
|
||||
if (auto const ret = checkReserve(
|
||||
ctx,
|
||||
sleDest,
|
||||
xrpBalance,
|
||||
*sponsorSle,
|
||||
{.ownerCountDelta = 1},
|
||||
journal,
|
||||
tecNO_LINE_INSUF_RESERVE);
|
||||
!isTesSuccess(ret))
|
||||
{
|
||||
JLOG(journal.trace()) << "Trust line does not exist. "
|
||||
@@ -119,22 +382,22 @@ escrowUnlockApplyHelper<Issue>(
|
||||
initialBalance.get<Issue>().account = noAccount();
|
||||
|
||||
if (TER const ter = trustCreate(
|
||||
ctx.view, // payment sandbox
|
||||
recvLow, // is dest low?
|
||||
issuer, // source
|
||||
receiver, // destination
|
||||
trustLineKey.key, // ledger index
|
||||
sleDest, // Account to add to
|
||||
false, // authorize account
|
||||
!sleDest->isFlag(lsfDefaultRipple), //
|
||||
false, // freeze trust line
|
||||
false, // deep freeze trust line
|
||||
initialBalance, // zero initial balance
|
||||
Issue(currency, receiver), // limit of zero
|
||||
0, // quality in
|
||||
0, // quality out
|
||||
sponsor ? sponsor->mutableRawSle() : SLE::pointer(), // sponsor
|
||||
journal); // journal
|
||||
ctx.view, // payment sandbox
|
||||
recvLow, // is dest low?
|
||||
issuer, // source
|
||||
receiver, // destination
|
||||
trustLineKey.key, // ledger index
|
||||
sleDest, // Account to add to
|
||||
false, // authorize account
|
||||
!sleDest->isFlag(lsfDefaultRipple), //
|
||||
false, // freeze trust line
|
||||
false, // deep freeze trust line
|
||||
initialBalance, // zero initial balance
|
||||
Issue(currency, receiver), // limit of zero
|
||||
0, // quality in
|
||||
0, // quality out
|
||||
*sponsorSle, // sponsor
|
||||
journal); // journal
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
@@ -229,29 +492,23 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
auto const mptKeylet = keylet::mptoken(issuanceKey.key, receiver);
|
||||
if (!ctx.view.exists(mptKeylet) && createAsset && !receiverIssuer)
|
||||
{
|
||||
if (sleDest->getType() != ltACCOUNT_ROOT)
|
||||
return detail::escrowDestNotAccountResult(ctx, sleDest);
|
||||
auto const destSle = AccountRootEntryR(sleDest, ctx.view, journal);
|
||||
auto sponsorSle = getEffectiveTxReserveSponsor(ctx, destSle);
|
||||
auto const sponsorSle = getEffectiveTxReserveSponsor(ctx, sleDest);
|
||||
if (!sponsorSle)
|
||||
return sponsorSle.error(); // LCOV_EXCL_LINE
|
||||
|
||||
auto& sponsor = *sponsorSle;
|
||||
|
||||
if (auto const ret = destSle.checkReserve(ctx, xrpBalance, sponsor, {.ownerCountDelta = 1});
|
||||
if (auto const ret = checkReserve(
|
||||
ctx, sleDest, xrpBalance, *sponsorSle, {.ownerCountDelta = 1}, journal);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (auto const ter = createMPToken(
|
||||
ctx.view, mptID, receiver, sponsor ? sponsor->mutableRawSle() : SLE::pointer(), 0);
|
||||
if (auto const ter = createMPToken(ctx.view, mptID, receiver, *sponsorSle, 0);
|
||||
!isTesSuccess(ter))
|
||||
{
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// update owner count.
|
||||
AccountRootEntryW receiverSle(receiver, ctx.view, journal);
|
||||
receiverSle.increaseOwnerCount(sponsor, 1);
|
||||
increaseOwnerCount(ctx.view, sleDest, *sponsorSle, 1, journal);
|
||||
}
|
||||
|
||||
if (!ctx.view.exists(mptKeylet) && !receiverIssuer)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
@@ -55,11 +54,11 @@ getTxReserveSponsorID(STTx const& tx);
|
||||
* Return a mutable SLE for the transaction's reserve sponsor account.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @return The sponsor account entry, nullopt if the tx is not
|
||||
* @return The sponsor account SLE, a null pointer if the tx is not
|
||||
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
|
||||
* be loaded (an already-checked invariant).
|
||||
*/
|
||||
std::expected<std::optional<AccountRootEntryW>, TER>
|
||||
std::expected<SLE::pointer, TER>
|
||||
getTxReserveSponsor(ApplyViewContext ctx);
|
||||
|
||||
/**
|
||||
@@ -67,29 +66,29 @@ getTxReserveSponsor(ApplyViewContext ctx);
|
||||
*
|
||||
* @param view The ledger read view
|
||||
* @param tx The transaction to inspect
|
||||
* @return The sponsor account entry, nullopt if the tx is not
|
||||
* @return The sponsor account SLE, a null pointer if the tx is not
|
||||
* reserve-sponsored, or tecINTERNAL if the sponsor account cannot
|
||||
* be loaded (an already-checked invariant).
|
||||
*/
|
||||
std::expected<std::optional<AccountRootEntryR>, TER>
|
||||
std::expected<SLE::const_pointer, TER>
|
||||
getTxReserveSponsor(ReadView const& view, STTx const& tx);
|
||||
|
||||
/**
|
||||
* The transaction's reserve sponsor for the given account, if applicable.
|
||||
*
|
||||
* A reserve sponsor only covers the transaction submitter's own objects, so
|
||||
* this returns the tx reserve sponsor entry only when accountSle is the tx's
|
||||
* own (non-pseudo) account; otherwise it returns nullopt. This is
|
||||
* this returns the tx reserve sponsor SLE only when accountSle is the tx's own
|
||||
* (non-pseudo) account; otherwise it returns a null sponsor pointer. This is
|
||||
* the single source of truth for the "sponsor applies to tx.Account only" rule
|
||||
* that the sponsor-deriving helper overloads in AccountRootHelpers rely on.
|
||||
*
|
||||
* @param ctx The apply-view context (view + tx)
|
||||
* @param accountSle The account whose sponsor is being resolved
|
||||
* @return The sponsor entry (nullopt if unsponsored), or tecINTERNAL if the
|
||||
* @return The sponsor SLE (nullptr if unsponsored), or tecINTERNAL if the
|
||||
* sponsor account cannot be loaded (an already-checked invariant)
|
||||
*/
|
||||
[[nodiscard]] std::expected<std::optional<AccountRootEntryW>, TER>
|
||||
getEffectiveTxReserveSponsor(ApplyViewContext ctx, AccountRootEntryR const& accountSle);
|
||||
[[nodiscard]] std::expected<SLE::pointer, TER>
|
||||
getEffectiveTxReserveSponsor(ApplyViewContext ctx, SLE::ConstRef accountSle);
|
||||
|
||||
/**
|
||||
* Return the AccountID stored in the given sponsor field of a ledger entry, or nullopt if absent.
|
||||
@@ -106,9 +105,9 @@ getLedgerEntryReserveSponsorID(SLE::ConstRef sle, SF_ACCOUNT const& field = sfSp
|
||||
* @param view The mutable apply view
|
||||
* @param sle The ledger entry whose sponsor field is inspected
|
||||
* @param field The field that holds the sponsor AccountID (defaults to sfSponsor)
|
||||
* @return The sponsor account entry, or nullopt if the entry is unsponsored.
|
||||
* @return The sponsor account SLE, or a null pointer if the entry is unsponsored.
|
||||
*/
|
||||
std::optional<AccountRootEntryW>
|
||||
SLE::pointer
|
||||
getLedgerEntryReserveSponsor(
|
||||
ApplyView& view,
|
||||
SLE::ConstRef sle,
|
||||
|
||||
@@ -103,7 +103,7 @@ public:
|
||||
void
|
||||
asyncHandshake(HandshakeType type, Callback cbFunc)
|
||||
{
|
||||
if ((type == SslSocket::client) || (secure_))
|
||||
if ((type == SslSocket::client) || secure_)
|
||||
{
|
||||
// must be ssl
|
||||
secure_ = true;
|
||||
|
||||
@@ -67,7 +67,7 @@ class EncodedBlob
|
||||
|
||||
public:
|
||||
explicit EncodedBlob(std::shared_ptr<NodeObject> const& obj)
|
||||
: size_([&obj]() {
|
||||
: size_([&obj] {
|
||||
XRPL_ASSERT(obj, "xrpl::node_store::EncodedBlob::EncodedBlob : non-null input");
|
||||
|
||||
if (!obj)
|
||||
|
||||
@@ -6,31 +6,21 @@
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* API version numbers used in later API versions
|
||||
* The `api_version` numbers this server serves.
|
||||
*
|
||||
* Requests with a version number in the range
|
||||
* [apiMinimumSupportedVersion, apiMaximumSupportedVersion]
|
||||
* are supported.
|
||||
* A request naming a version in [kApiMinimumSupportedVersion,
|
||||
* kApiMaximumSupportedVersion] is served. With `[beta_rpc_api]` set to `1` in
|
||||
* the config the range extends to kApiBetaVersion.
|
||||
*
|
||||
* If [beta_rpc_api] is enabled in config, the version numbers
|
||||
* in the range [apiMinimumSupportedVersion, apiBetaVersion]
|
||||
* are supported.
|
||||
*
|
||||
* Network Requests without explicit version numbers use
|
||||
* apiVersionIfUnspecified. apiVersionIfUnspecified is 1,
|
||||
* because all the RPC requests with a version >= 2 must
|
||||
* explicitly specify the version in the requests.
|
||||
* Note that apiVersionIfUnspecified will be lower than
|
||||
* apiMinimumSupportedVersion when we stop supporting API
|
||||
* version 1.
|
||||
*
|
||||
* Command line Requests use apiCommandLineVersion.
|
||||
* A request naming no version is served at kApiVersionIfUnspecified, which is 1
|
||||
* because a request wanting any later version states it.
|
||||
*/
|
||||
|
||||
namespace rpc {
|
||||
@@ -57,6 +47,16 @@ static_assert(kApiMaximumSupportedVersion >= kApiMinimumSupportedVersion);
|
||||
static_assert(kApiBetaVersion >= kApiMaximumSupportedVersion);
|
||||
static_assert(kApiMaximumValidVersion >= kApiMaximumSupportedVersion);
|
||||
|
||||
/**
|
||||
* Values accepted in the `ripplerpc` request field, which selects the shape of
|
||||
* the JSON-RPC reply envelope. Distinct from `kJsonRpcVersion` in JsonRpc.h,
|
||||
* which names the JSON-RPC protocol itself, and from the `api_version`
|
||||
* constants above, which select the content of the response.
|
||||
*/
|
||||
inline constexpr std::string_view kRippleRpcVersion1{"1.0"};
|
||||
inline constexpr std::string_view kRippleRpcVersion2{"2.0"};
|
||||
inline constexpr std::string_view kRippleRpcVersion3{"3.0"};
|
||||
|
||||
inline void
|
||||
setVersion(json::Value& parent, unsigned int apiVersion, bool betaEnabled)
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ hash_append(Hasher& h, Book const& b)
|
||||
using beast::hash_append;
|
||||
hash_append(h, b.in, b.out);
|
||||
if (b.domain)
|
||||
hash_append(h, *(b.domain));
|
||||
hash_append(h, *b.domain);
|
||||
}
|
||||
|
||||
Book
|
||||
|
||||
@@ -144,7 +144,27 @@ enum ErrorCodeI {
|
||||
RpcEntryNotFound = 98,
|
||||
RpcUnexpectedLedgerType = 99,
|
||||
|
||||
RpcLast = RpcUnexpectedLedgerType // rpcLAST should always equal the last code.
|
||||
// submit + simulate
|
||||
RpcInvalidTransaction = 100,
|
||||
RpcInternalSubmit = 101,
|
||||
RpcInternalJson = 102,
|
||||
RpcInternalSimulate = 103,
|
||||
|
||||
// transaction_entry
|
||||
RpcFieldNotFoundTransaction = 104,
|
||||
RpcNotYetImplemented = 105,
|
||||
RpcTransactionNotFound = 106,
|
||||
|
||||
// transaction_entry + ledger_entry
|
||||
RpcMalformedRequest = 107,
|
||||
|
||||
// ledger_accept
|
||||
RpcNotStandAlone = 108,
|
||||
|
||||
// ledger_entry, API version 1 only
|
||||
RpcUnknownOption = 109,
|
||||
|
||||
RpcLast = RpcUnknownOption // rpcLAST should always equal the last code.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -180,11 +200,6 @@ struct ErrorInfo
|
||||
{
|
||||
}
|
||||
|
||||
constexpr ErrorInfo(ErrorCodeI code, char const* token, char const* message)
|
||||
: code(code), token(token), message(message), httpStatus(200)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr ErrorInfo(ErrorCodeI code, char const* token, char const* message, int httpStatus)
|
||||
: code(code), token(token), message(message), httpStatus(httpStatus)
|
||||
{
|
||||
|
||||
20
include/xrpl/protocol/JsonRpc.h
Normal file
20
include/xrpl/protocol/JsonRpc.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl::rpc {
|
||||
|
||||
/**
|
||||
* Constants of the JSON-RPC 2.0 protocol itself.
|
||||
*
|
||||
* Kept apart from the `api_version` and `ripplerpc` constants in ApiVersion.h,
|
||||
* which go when support for API versions 1 and 2 goes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Value of the `jsonrpc` member of a request and of its reply, fixed at "2.0"
|
||||
* by the JSON-RPC specification.
|
||||
*/
|
||||
inline constexpr std::string_view kJsonRpcVersion{"2.0"};
|
||||
|
||||
} // namespace xrpl::rpc
|
||||
@@ -208,7 +208,10 @@ enum LedgerEntryType : std::uint16_t {
|
||||
\
|
||||
LEDGER_OBJECT(Sponsorship, \
|
||||
LSF_FLAG(lsfSponsorshipRequireSignForFee, 0x00010000) \
|
||||
LSF_FLAG(lsfSponsorshipRequireSignForReserve, 0x00020000))
|
||||
LSF_FLAG(lsfSponsorshipRequireSignForReserve, 0x00020000)) \
|
||||
\
|
||||
LEDGER_OBJECT(LoanBroker, \
|
||||
LSF_FLAG(lsfLoanBrokerPrivate, 0x00010000))
|
||||
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Enumeration of ledger shortcuts for specifying which ledger to use.
|
||||
*
|
||||
* These shortcuts provide a convenient way to reference commonly used ledgers
|
||||
* without needing to specify their exact hash or sequence number.
|
||||
*/
|
||||
enum class LedgerShortcut {
|
||||
/**
|
||||
* The current working ledger (open, not yet closed)
|
||||
*/
|
||||
Current,
|
||||
|
||||
/**
|
||||
* The most recently closed ledger (may not be validated)
|
||||
*/
|
||||
Closed,
|
||||
|
||||
/**
|
||||
* The most recently validated ledger
|
||||
*/
|
||||
Validated
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -457,9 +457,7 @@ private:
|
||||
// The remove_cv and remove_reference are necessitated by the STBitString
|
||||
// types. Their value() returns by const ref. We return those types
|
||||
// by value.
|
||||
template <
|
||||
typename T,
|
||||
typename V = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<T>().value())>>>
|
||||
template <typename T, typename V = std::remove_cvref_t<decltype(std::declval<T>().value())>>
|
||||
V
|
||||
getFieldByValue(SField const& field) const;
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ private:
|
||||
template <class LookupNodeID>
|
||||
STValidation::STValidation(SerialIter& sit, LookupNodeID&& lookupNodeID, DeserializeOptions options)
|
||||
: STObject(validationFormat(), sit, sfValidation, options.requireCanonicalOrder)
|
||||
, signingPubKey_([this]() {
|
||||
, signingPubKey_([this] {
|
||||
auto const spk = getFieldVL(sfSigningPubKey);
|
||||
|
||||
if (publicKeyType(makeSlice(spk)) != KeyType::Secp256k1)
|
||||
|
||||
@@ -252,7 +252,7 @@ public:
|
||||
{
|
||||
auto success = (offset + (Bits / 8)) <= data_.size();
|
||||
if (success)
|
||||
memcpy(data.begin(), &(data_.front()) + offset, (Bits / 8));
|
||||
memcpy(data.begin(), &data_.front() + offset, (Bits / 8));
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -449,7 +449,7 @@ public:
|
||||
// Trait tells the requires-clause which types are allowed for construction.
|
||||
template <typename T>
|
||||
constexpr TERSubset(T rhs)
|
||||
requires(Trait<std::remove_cv_t<std::remove_reference_t<T>>>::value)
|
||||
requires(Trait<std::remove_cvref_t<T>>::value)
|
||||
: code_(TERtoInt(rhs))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -226,6 +226,10 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
TF_FLAG(tfLoanUnimpair, 0x00040000), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(LoanBrokerSet, \
|
||||
TF_FLAG(tfLoanBrokerPrivate, 0x00010000), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(SponsorshipSet, \
|
||||
TF_FLAG(tfSponsorshipSetRequireSignForFee, 0x00010000) \
|
||||
TF_FLAG(tfSponsorshipClearRequireSignForFee, 0x00020000) \
|
||||
|
||||
@@ -20,6 +20,7 @@ XRPL_FEATURE(SmartEscrow, Supported::No, VoteBehavior::DefaultN
|
||||
XRPL_FEATURE(LendingProtocolV1_2, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (Cleanup3_5_0, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(ConfidentialMPTKeyRotation, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (BatchV1_2, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (Cleanup3_4_0, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Sponsor, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(BatchV1_1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -549,6 +549,7 @@ LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
|
||||
{sfCoverAvailable, SoeDefault},
|
||||
{sfCoverRateMinimum, SoeDefault},
|
||||
{sfCoverRateLiquidation, SoeDefault},
|
||||
{sfDomainID, SoeOptional},
|
||||
}))
|
||||
|
||||
/** A ledger object representing a loan between a Borrower and a Loan Broker
|
||||
|
||||
@@ -900,6 +900,7 @@ TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
|
||||
{sfDebtMaximum, SoeOptional},
|
||||
{sfCoverRateMinimum, SoeOptional},
|
||||
{sfCoverRateLiquidation, SoeOptional},
|
||||
{sfDomainID, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction deletes a Loan Broker */
|
||||
|
||||
@@ -245,7 +245,7 @@ JSS(ephemeral_key); // out: ValidatorInfo
|
||||
JSS(error); // out: error
|
||||
JSS(errored); //
|
||||
JSS(error_code); // out: error
|
||||
JSS(error_exception); // out: Submit
|
||||
JSS(error_exception); // out: Submit, Simulate
|
||||
JSS(error_message); // out: error
|
||||
JSS(expand); // in: handler/Ledger
|
||||
JSS(expected_date); // out: any (warnings)
|
||||
@@ -559,7 +559,7 @@ JSS(signing_key); // out: NetworkOPs
|
||||
JSS(signing_keys); // out: ValidatorList
|
||||
JSS(signing_time); // out: NetworkOPs
|
||||
JSS(signer_lists); // in/out: AccountInfo
|
||||
JSS(size); // out: get_aggregate_price
|
||||
JSS(size); // out: get_aggregate_price, ServerHandler
|
||||
JSS(snapshot); // in: Subscribe
|
||||
JSS(source_account); // in: PathRequest, RipplePathFind
|
||||
JSS(source_amount); // in: PathRequest, RipplePathFind
|
||||
|
||||
@@ -335,6 +335,30 @@ public:
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfCoverRateLiquidation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDomainID (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT256::type::value_type>
|
||||
getDomainID() const
|
||||
{
|
||||
if (hasDomainID())
|
||||
return this->sle_->at(sfDomainID);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfDomainID is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasDomainID() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfDomainID);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -578,6 +602,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDomainID (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
LoanBrokerBuilder&
|
||||
setDomainID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDomainID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed LoanBroker wrapper.
|
||||
* @param index The ledger entry index.
|
||||
|
||||
@@ -213,6 +213,32 @@ public:
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfCoverRateLiquidation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDomainID (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT256::type::value_type>
|
||||
getDomainID() const
|
||||
{
|
||||
if (hasDomainID())
|
||||
{
|
||||
return this->tx_->at(sfDomainID);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfDomainID is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasDomainID() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDomainID);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -336,6 +362,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDomainID (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
LoanBrokerSetBuilder&
|
||||
setDomainID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDomainID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the LoanBrokerSet wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
|
||||
@@ -178,7 +178,7 @@ public:
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
LockedSociSession session = perf::measureDurationAndLog(
|
||||
[&]() { return LockedSociSession(session_, lock_); }, "checkoutDb", 10ms, j_);
|
||||
[&] { return LockedSociSession(session_, lock_); }, "checkoutDb", 10ms, j_);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/LedgerHeader.h>
|
||||
#include <xrpl/protocol/LedgerShortcut.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/TxMeta.h>
|
||||
#include <xrpl/protocol/TxSearched.h>
|
||||
@@ -105,21 +104,6 @@ public:
|
||||
using TxnMetaLedgerType = std::tuple<Blob, Blob, std::uint32_t>;
|
||||
using MetaTxsList = std::vector<TxnMetaLedgerType>;
|
||||
|
||||
using LedgerSequence = uint32_t;
|
||||
using LedgerHash = UInt256;
|
||||
using LedgerSpecifier = std::variant<LedgerRange, LedgerShortcut, LedgerSequence, LedgerHash>;
|
||||
|
||||
struct AccountTxArgs
|
||||
{
|
||||
AccountID account;
|
||||
std::optional<LedgerSpecifier> ledger;
|
||||
bool binary = false;
|
||||
bool forward = false;
|
||||
uint32_t limit = 0;
|
||||
std::optional<AccountTxMarker> marker;
|
||||
std::optional<DelegateFilter> delegate;
|
||||
};
|
||||
|
||||
struct AccountTxResult
|
||||
{
|
||||
std::variant<AccountTxs, MetaTxsList> transactions;
|
||||
|
||||
@@ -279,7 +279,7 @@ public:
|
||||
virtual bool
|
||||
unsubPeerStatus(std::uint64_t uListener) = 0;
|
||||
virtual void
|
||||
pubPeerStatus(std::function<json::Value(void)> const&) = 0;
|
||||
pubPeerStatus(std::function<json::Value()> const&) = 0;
|
||||
|
||||
virtual bool
|
||||
subConsensus(Ref ispListener) = 0;
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
prepare(std::size_t bytes, std::function<void(void)>) override
|
||||
prepare(std::size_t bytes, std::function<void()>) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
* empty vector.
|
||||
*/
|
||||
virtual std::pair<boost::tribool, std::vector<boost::asio::const_buffer>>
|
||||
prepare(std::size_t bytes, std::function<void(void)> resume) = 0;
|
||||
prepare(std::size_t bytes, std::function<void()> resume) = 0;
|
||||
};
|
||||
|
||||
template <class Streambuf>
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
}
|
||||
|
||||
std::pair<boost::tribool, std::vector<boost::asio::const_buffer>>
|
||||
prepare(std::size_t bytes, std::function<void(void)>) override
|
||||
prepare(std::size_t bytes, std::function<void()>) override
|
||||
{
|
||||
if (sb_.size() == 0)
|
||||
return {true, {}};
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
* @return `true` if the writer is ready to provide more data.
|
||||
*/
|
||||
virtual bool
|
||||
prepare(std::size_t bytes, std::function<void(void)> resume) = 0;
|
||||
prepare(std::size_t bytes, std::function<void()> resume) = 0;
|
||||
|
||||
/**
|
||||
* Returns a ConstBufferSequence representing the input sequence.
|
||||
|
||||
@@ -342,10 +342,10 @@ BaseHTTPPeer<Handler, Impl>::doWriter(
|
||||
bool keepAlive,
|
||||
YieldContext doYield)
|
||||
{
|
||||
std::function<void(void)> resume;
|
||||
std::function<void()> resume;
|
||||
{
|
||||
auto const p = impl().shared_from_this();
|
||||
resume = std::function<void(void)>([this, p, writer, keepAlive]() {
|
||||
resume = std::function<void()>([this, p, writer, keepAlive] {
|
||||
util::spawn(strand_, [p, writer, keepAlive](YieldContext doYield) {
|
||||
p->doWriter(writer, keepAlive, doYield);
|
||||
});
|
||||
|
||||
@@ -99,7 +99,7 @@ private:
|
||||
port_.protocol.contains("wss2") || port_.protocol.contains("peer")};
|
||||
bool plain_{
|
||||
port_.protocol.contains("http") || port_.protocol.contains("ws") ||
|
||||
(port_.protocol.contains("ws2"))};
|
||||
port_.protocol.contains("ws2")};
|
||||
static constexpr std::chrono::milliseconds kInitialAcceptDelay{50};
|
||||
static constexpr std::chrono::milliseconds kMaxAcceptDelay{2000};
|
||||
std::chrono::milliseconds acceptDelay_{kInitialAcceptDelay};
|
||||
|
||||
@@ -7,6 +7,18 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Writes an HTTP reply carrying @p strMsg with status @p nStatus to @p output,
|
||||
* and logs the status at trace. The body is not logged here: it may carry a
|
||||
* credential this library cannot mask, so the caller logs it masked.
|
||||
*
|
||||
* A 401 with an empty body is answered with the fixed authentication page.
|
||||
*
|
||||
* @param nStatus The HTTP status code.
|
||||
* @param strMsg The body.
|
||||
* @param output Where the reply bytes are written.
|
||||
* @param j The journal the status is logged to.
|
||||
*/
|
||||
void
|
||||
httpReply(int nStatus, std::string const& strMsg, json::Output const&, beast::Journal j);
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
bool closed_ = false;
|
||||
std::condition_variable cv_;
|
||||
boost::container::flat_map<Work*, std::weak_ptr<Work>> map_;
|
||||
std::function<void(void)> f_;
|
||||
std::function<void()> f_;
|
||||
|
||||
public:
|
||||
IOList() = default;
|
||||
@@ -171,7 +171,7 @@ IOList::Work::destroy()
|
||||
{
|
||||
if (!ios_)
|
||||
return;
|
||||
std::function<void(void)> f;
|
||||
std::function<void()> f;
|
||||
{
|
||||
std::scoped_lock const lock(ios_->m_);
|
||||
ios_->map_.erase(this);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <xrpl/tx/invariants/SponsorshipInvariant.h>
|
||||
#include <xrpl/tx/invariants/VaultInvariant.h>
|
||||
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@@ -27,18 +29,6 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Returns true if sleAcct is an AccountRoot carrying a pseudo-account field.
|
||||
*
|
||||
* isPseudoAccount() takes a view-bound AccountRootEntry, which is not
|
||||
* available while visiting entries, so invariant checks use this instead.
|
||||
*
|
||||
* @param sleAcct the SLE to check.
|
||||
* @return true if sleAcct is an AccountRoot carrying a pseudo-account field.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isPseudoAccountSle(SLE::ConstRef sleAcct);
|
||||
|
||||
#if GENERATING_DOCS
|
||||
/**
|
||||
* @brief Prototype for invariant check implementations.
|
||||
@@ -151,7 +141,7 @@ public:
|
||||
*/
|
||||
class XRPNotCreated
|
||||
{
|
||||
std::int64_t drops_ = 0;
|
||||
boost::multiprecision::int128_t drops_ = 0;
|
||||
|
||||
public:
|
||||
void
|
||||
|
||||
@@ -42,6 +42,14 @@ class ValidMPTIssuance
|
||||
*/
|
||||
bool referenceHoldingMutated_ = false;
|
||||
|
||||
/**
|
||||
* Flags cleared on an existing MPTokenIssuance, except lsfMPTLocked,
|
||||
* which tfMPTUnlock clears legitimately. Every other issuance flag is
|
||||
* fixed at creation or set-once via MPTokenIssuanceSet, so any bit
|
||||
* accumulated here is a bug. Enforced post-fixCleanup3_5_0.
|
||||
*/
|
||||
std::uint32_t issuanceFlagsCleared_ = 0;
|
||||
|
||||
/**
|
||||
* MPTokens and RippleStates deleted during apply. finalize() checks each
|
||||
* holder's AccountRoot to detect vault pseudo-account holdings deleted
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
@@ -26,7 +25,7 @@ checkFreeze(
|
||||
XRPL_ASSERT(src != dst, "xrpl::checkFreeze : unequal input accounts");
|
||||
|
||||
// check freeze
|
||||
if (auto sle = AccountRootEntryR(dst, view))
|
||||
if (auto sle = view.read(keylet::account(dst)))
|
||||
{
|
||||
if (sle->isFlag(lsfGlobalFreeze))
|
||||
{
|
||||
@@ -50,7 +49,7 @@ checkFreeze(
|
||||
|
||||
if (view.rules().enabled(fixFrozenLPTokenTransfer))
|
||||
{
|
||||
if (auto const sleDst = AccountRootEntryR(dst, view);
|
||||
if (auto const sleDst = view.read(keylet::account(dst));
|
||||
sleDst && sleDst->isFieldPresent(sfAMMID))
|
||||
{
|
||||
auto const sleAmm = view.read(keylet::amm((*sleDst)[sfAMMID]));
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/MathUtilities.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -23,6 +25,7 @@
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -502,6 +505,46 @@ public:
|
||||
};
|
||||
/** @endcond */
|
||||
|
||||
/** @cond INTERNAL */
|
||||
template <class T>
|
||||
[[nodiscard]] std::optional<T>
|
||||
checkedStepAddOpt(T const& lhs, T const& rhs)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, XRPAmount>)
|
||||
{
|
||||
if (auto const r = checkedAdd(lhs.drops(), rhs.drops()))
|
||||
return XRPAmount{*r};
|
||||
return std::nullopt;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, MPTAmount>)
|
||||
{
|
||||
if (auto const r = checkedAdd(lhs.value(), rhs.value()))
|
||||
return MPTAmount{*r};
|
||||
return std::nullopt;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, IOUAmount>)
|
||||
{
|
||||
// IOUAmount is Number-backed and throws on overflow.
|
||||
return lhs + rhs;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A new amount type must decide explicitly how to add; do not fall back
|
||||
// to an unchecked add.
|
||||
static_assert(sizeof(T) == 0, "checkedStepAddOpt: unsupported amount type");
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
[[nodiscard]] T
|
||||
checkedStepAdd(T const& lhs, T const& rhs)
|
||||
{
|
||||
if (auto const r = checkedStepAddOpt(lhs, rhs))
|
||||
return *r;
|
||||
Throw<FlowException>(tecPATH_DRY);
|
||||
}
|
||||
/** @endcond */
|
||||
|
||||
/** @cond INTERNAL */
|
||||
// Check equal with tolerance
|
||||
bool
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
@@ -408,7 +407,7 @@ limitOut(
|
||||
if (!qf || qf->isConst())
|
||||
return remainingOut;
|
||||
|
||||
auto const out = [&]() {
|
||||
auto const out = [&] {
|
||||
auto const out = qf->outFromAvgQ(limitQuality);
|
||||
if (!out)
|
||||
return remainingOut;
|
||||
@@ -646,11 +645,21 @@ flow(
|
||||
boost::container::flat_multiset<TOutAmt> savedOuts;
|
||||
savedOuts.reserve(maxTries);
|
||||
|
||||
auto sum = [](auto const& col) {
|
||||
// Returns std::nullopt if the aggregate overflows; callers treat that as a
|
||||
// dry path.
|
||||
auto sum = [](auto const& col) -> std::optional<std::decay_t<decltype(*col.begin())>> {
|
||||
using TResult = std::decay_t<decltype(*col.begin())>;
|
||||
if (col.empty())
|
||||
return TResult{beast::kZero};
|
||||
return std::accumulate(col.begin() + 1, col.end(), *col.begin());
|
||||
TResult total = *col.begin();
|
||||
for (auto it = col.begin() + 1; it != col.end(); ++it)
|
||||
{
|
||||
auto const next = checkedStepAddOpt(total, *it);
|
||||
if (!next)
|
||||
return std::nullopt;
|
||||
total = *next;
|
||||
}
|
||||
return total;
|
||||
};
|
||||
|
||||
// These offers only need to be removed if the payment is not
|
||||
@@ -670,7 +679,7 @@ flow(
|
||||
ammContext.setMultiPath(activeStrands.size() > 1);
|
||||
|
||||
// Limit only if one strand and limitQuality
|
||||
auto const limitRemainingOut = [&]() {
|
||||
auto const limitRemainingOut = [&] {
|
||||
if (activeStrands.size() == 1 && limitQuality)
|
||||
{
|
||||
if (auto const strand = activeStrands.get(0))
|
||||
@@ -749,9 +758,17 @@ flow(
|
||||
{
|
||||
savedIns.insert(best->in);
|
||||
savedOuts.insert(best->out);
|
||||
remainingOut = outReq - sum(savedOuts);
|
||||
auto const sumOut = sum(savedOuts);
|
||||
if (!sumOut)
|
||||
return {tecPATH_DRY, std::move(ofrsToRmOnFail)};
|
||||
remainingOut = outReq - *sumOut;
|
||||
if (sendMax)
|
||||
remainingIn = *sendMax - sum(savedIns);
|
||||
{
|
||||
auto const sumIn = sum(savedIns);
|
||||
if (!sumIn)
|
||||
return {tecPATH_DRY, std::move(ofrsToRmOnFail)};
|
||||
remainingIn = *sendMax - *sumIn;
|
||||
}
|
||||
|
||||
if (flowDebugInfo)
|
||||
{
|
||||
@@ -786,8 +803,12 @@ flow(
|
||||
break;
|
||||
}
|
||||
|
||||
auto const actualOut = sum(savedOuts);
|
||||
auto const actualIn = sum(savedIns);
|
||||
auto const actualOutOpt = sum(savedOuts);
|
||||
auto const actualInOpt = sum(savedIns);
|
||||
if (!actualOutOpt || !actualInOpt)
|
||||
return {tecPATH_DRY, std::move(ofrsToRmOnFail)};
|
||||
auto const actualOut = *actualOutOpt;
|
||||
auto const actualIn = *actualInOpt;
|
||||
|
||||
JLOG(j.trace()) << "Total flow: in: " << to_string(actualIn)
|
||||
<< " out: " << to_string(actualOut);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -32,6 +33,9 @@ public:
|
||||
static std::vector<OptionaledField<STNumber>> const&
|
||||
getValueFields();
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/AccountRootEntry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
@@ -13,7 +12,6 @@
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -58,8 +56,8 @@ private:
|
||||
Keylet const& sponsorshipKeylet,
|
||||
AccountID const& sponsorID,
|
||||
AccountID const& sponseeID,
|
||||
AccountRootEntryW& sponsorAccSle,
|
||||
std::optional<AccountRootEntryW>& reserveSponsorAccSle);
|
||||
SLE::Ref sponsorAccSle,
|
||||
SLE::Ref reserveSponsorAccSle);
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user