mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-03 10:32:30 +00:00
Compare commits
32 Commits
develop
...
mvadari/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7e48d9bb1 | ||
|
|
1a822da112 | ||
|
|
458dce37b6 | ||
|
|
95d57983b4 | ||
|
|
e89e83c802 | ||
|
|
370a420aa3 | ||
|
|
1eef4554e2 | ||
|
|
22fba7d90e | ||
|
|
9659b9baff | ||
|
|
44c6c52319 | ||
|
|
cee7dfb11b | ||
|
|
48e9c5623d | ||
|
|
640b231f5f | ||
|
|
89e9caed17 | ||
|
|
8a1adc4ec9 | ||
|
|
c9db124015 | ||
|
|
7056b43c5e | ||
|
|
ee370fefee | ||
|
|
e68d74cda4 | ||
|
|
89a3a6c379 | ||
|
|
f3a6d17b5b | ||
|
|
45531b1eaf | ||
|
|
fa8de2b47f | ||
|
|
6fcda8802e | ||
|
|
0cf42b150c | ||
|
|
74b010a905 | ||
|
|
265deccabe | ||
|
|
ea1146d413 | ||
|
|
5fa9bb53a8 | ||
|
|
d9bf263543 | ||
|
|
1f73da466c | ||
|
|
e9eb5e53c9 |
100
.clang-tidy
100
.clang-tidy
@@ -1,6 +1,4 @@
|
||||
---
|
||||
# This entire group of checks was applied to all cpp files but not all header files.
|
||||
# ---
|
||||
Checks: "-*,
|
||||
bugprone-argument-comment,
|
||||
bugprone-assert-side-effect,
|
||||
@@ -10,26 +8,26 @@ Checks: "-*,
|
||||
bugprone-chained-comparison,
|
||||
bugprone-compare-pointer-to-member-virtual-function,
|
||||
bugprone-copy-constructor-init,
|
||||
# bugprone-crtp-constructor-accessibility, # has issues
|
||||
bugprone-crtp-constructor-accessibility,
|
||||
bugprone-dangling-handle,
|
||||
bugprone-dynamic-static-initializers,
|
||||
# bugprone-empty-catch, # has issues
|
||||
bugprone-empty-catch,
|
||||
bugprone-fold-init-type,
|
||||
# bugprone-forward-declaration-namespace, # has issues
|
||||
# bugprone-inaccurate-erase,
|
||||
# bugprone-inc-dec-in-conditions,
|
||||
# bugprone-incorrect-enable-if,
|
||||
# bugprone-incorrect-roundings,
|
||||
# bugprone-infinite-loop,
|
||||
# bugprone-integer-division,
|
||||
bugprone-forward-declaration-namespace,
|
||||
bugprone-inaccurate-erase,
|
||||
bugprone-inc-dec-in-conditions,
|
||||
bugprone-incorrect-enable-if,
|
||||
bugprone-incorrect-roundings,
|
||||
bugprone-infinite-loop,
|
||||
bugprone-integer-division,
|
||||
bugprone-lambda-function-name,
|
||||
# bugprone-macro-parentheses, # has issues
|
||||
bugprone-macro-parentheses,
|
||||
bugprone-macro-repeated-side-effects,
|
||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||
bugprone-misplaced-widening-cast,
|
||||
bugprone-move-forwarding-reference,
|
||||
# bugprone-multi-level-implicit-pointer-conversion, # has issues
|
||||
bugprone-multi-level-implicit-pointer-conversion,
|
||||
bugprone-multiple-new-in-one-expression,
|
||||
bugprone-multiple-statement-macro,
|
||||
bugprone-no-escape,
|
||||
@@ -39,13 +37,13 @@ Checks: "-*,
|
||||
bugprone-pointer-arithmetic-on-polymorphic-object,
|
||||
bugprone-posix-return,
|
||||
bugprone-redundant-branch-condition,
|
||||
# bugprone-reserved-identifier, # has issues
|
||||
# bugprone-return-const-ref-from-parameter, # has issues
|
||||
bugprone-reserved-identifier,
|
||||
bugprone-return-const-ref-from-parameter,
|
||||
bugprone-shared-ptr-array-mismatch,
|
||||
bugprone-signal-handler,
|
||||
bugprone-signed-char-misuse,
|
||||
bugprone-sizeof-container,
|
||||
# bugprone-sizeof-expression, # has issues
|
||||
bugprone-sizeof-expression,
|
||||
bugprone-spuriously-wake-up-functions,
|
||||
bugprone-standalone-empty,
|
||||
bugprone-string-constructor,
|
||||
@@ -62,7 +60,7 @@ Checks: "-*,
|
||||
bugprone-suspicious-string-compare,
|
||||
bugprone-suspicious-stringview-data-usage,
|
||||
bugprone-swapped-arguments,
|
||||
# bugprone-switch-missing-default-case, # has issues
|
||||
bugprone-switch-missing-default-case,
|
||||
bugprone-terminating-continue,
|
||||
bugprone-throw-keyword-missing,
|
||||
bugprone-too-small-loop-variable,
|
||||
@@ -73,7 +71,7 @@ Checks: "-*,
|
||||
bugprone-unhandled-self-assignment,
|
||||
bugprone-unique-ptr-array-mismatch,
|
||||
bugprone-unsafe-functions,
|
||||
# bugprone-use-after-move, # has issues
|
||||
bugprone-use-after-move,
|
||||
bugprone-unused-raii,
|
||||
bugprone-unused-return-value,
|
||||
bugprone-unused-local-non-trivial-variable,
|
||||
@@ -87,11 +85,9 @@ Checks: "-*,
|
||||
cppcoreguidelines-use-default-member-init,
|
||||
cppcoreguidelines-virtual-class-destructor,
|
||||
hicpp-ignored-remove-result,
|
||||
misc-const-correctness,
|
||||
misc-definitions-in-headers,
|
||||
misc-header-include-cycle,
|
||||
misc-misplaced-const,
|
||||
misc-redundant-expression,
|
||||
misc-static-assert,
|
||||
misc-throw-by-value-catch-by-reference,
|
||||
misc-unused-alias-decls,
|
||||
@@ -99,49 +95,46 @@ Checks: "-*,
|
||||
modernize-deprecated-headers,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
llvm-namespace-comment,
|
||||
performance-faster-string-find,
|
||||
performance-for-range-copy,
|
||||
performance-implicit-conversion-in-loop,
|
||||
performance-inefficient-vector-operation,
|
||||
performance-move-const-arg,
|
||||
performance-move-constructor-init,
|
||||
performance-no-automatic-move,
|
||||
performance-trivially-destructible,
|
||||
# readability-avoid-nested-conditional-operator, # has issues
|
||||
# readability-avoid-return-with-void-value, # has issues
|
||||
# readability-braces-around-statements, # has issues
|
||||
# readability-const-return-type, # has issues
|
||||
# readability-container-contains, # has issues
|
||||
# readability-container-size-empty, # has issues
|
||||
# readability-convert-member-functions-to-static, # has issues
|
||||
readability-avoid-nested-conditional-operator,
|
||||
readability-avoid-return-with-void-value,
|
||||
readability-braces-around-statements,
|
||||
readability-const-return-type,
|
||||
readability-container-contains,
|
||||
readability-container-size-empty,
|
||||
readability-duplicate-include,
|
||||
# readability-else-after-return, # has issues
|
||||
# readability-enum-initial-value, # has issues
|
||||
# readability-implicit-bool-conversion, # has issues
|
||||
# readability-make-member-function-const, # has issues
|
||||
# readability-math-missing-parentheses, # has issues
|
||||
readability-else-after-return,
|
||||
readability-enum-initial-value,
|
||||
readability-make-member-function-const,
|
||||
readability-misleading-indentation,
|
||||
readability-non-const-parameter,
|
||||
# readability-redundant-casting, # has issues
|
||||
# readability-redundant-declaration, # has issues
|
||||
# readability-redundant-inline-specifier, # has issues
|
||||
# readability-redundant-member-init, # has issues
|
||||
readability-redundant-casting,
|
||||
readability-redundant-declaration,
|
||||
readability-redundant-inline-specifier,
|
||||
readability-redundant-member-init,
|
||||
readability-redundant-string-init,
|
||||
readability-reference-to-constructed-temporary,
|
||||
# readability-simplify-boolean-expr, # has issues
|
||||
# readability-static-definition-in-anonymous-namespace, # has issues
|
||||
# readability-suspicious-call-argument, # has issues
|
||||
readability-static-definition-in-anonymous-namespace,
|
||||
readability-use-std-min-max
|
||||
"
|
||||
# ---
|
||||
# other checks that have issues that need to be resolved:
|
||||
# checks that have some issues that need to be resolved:
|
||||
#
|
||||
# llvm-namespace-comment,
|
||||
# misc-const-correctness,
|
||||
# misc-include-cleaner,
|
||||
# misc-redundant-expression,
|
||||
#
|
||||
# readability-inconsistent-declaration-parameter-name, # in this codebase this check will break a lot of arg names
|
||||
# readability-static-accessed-through-instance, # this check is probably unnecessary. it makes the code less readable
|
||||
# readability-identifier-naming, # https://github.com/XRPLF/rippled/pull/6571
|
||||
# readability-convert-member-functions-to-static,
|
||||
# readability-implicit-bool-conversion,
|
||||
# readability-inconsistent-declaration-parameter-name,
|
||||
# readability-identifier-naming,
|
||||
# readability-math-missing-parentheses,
|
||||
# readability-simplify-boolean-expr,
|
||||
# readability-suspicious-call-argument,
|
||||
# readability-static-accessed-through-instance,
|
||||
#
|
||||
# modernize-concat-nested-namespaces,
|
||||
# modernize-pass-by-value,
|
||||
@@ -155,6 +148,12 @@ Checks: "-*,
|
||||
# modernize-use-starts-ends-with,
|
||||
# modernize-use-std-numbers,
|
||||
# modernize-use-using,
|
||||
#
|
||||
# performance-faster-string-find,
|
||||
# performance-for-range-copy,
|
||||
# performance-inefficient-vector-operation,
|
||||
# performance-move-const-arg,
|
||||
# performance-no-automatic-move,
|
||||
# ---
|
||||
#
|
||||
CheckOptions:
|
||||
@@ -196,6 +195,5 @@ CheckOptions:
|
||||
bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
|
||||
# misc-include-cleaner.IgnoreHeaders: '.*/(detail|impl)/.*;.*(expected|unexpected).*;.*ranges_lower_bound\.h;time.h;stdlib.h;__chrono/.*;fmt/chrono.h;boost/uuid/uuid_hash.hpp'
|
||||
#
|
||||
HeaderFilterRegex: '^.*/(test|xrpl|xrpld)/.*\.(h|hpp)$'
|
||||
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$'
|
||||
# HeaderFilterRegex: '^.*/(src|tests)/.*\.(h|hpp)$'
|
||||
WarningsAsErrors: "*"
|
||||
|
||||
@@ -21,7 +21,6 @@ libxrpl.protocol > xrpl.json
|
||||
libxrpl.protocol > xrpl.protocol
|
||||
libxrpl.protocol_autogen > xrpl.protocol_autogen
|
||||
libxrpl.rdb > xrpl.basics
|
||||
libxrpl.rdb > xrpl.core
|
||||
libxrpl.rdb > xrpl.rdb
|
||||
libxrpl.resource > xrpl.basics
|
||||
libxrpl.resource > xrpl.json
|
||||
@@ -91,7 +90,6 @@ test.core > xrpl.server
|
||||
test.csf > xrpl.basics
|
||||
test.csf > xrpld.consensus
|
||||
test.csf > xrpl.json
|
||||
test.csf > xrpl.ledger
|
||||
test.csf > xrpl.protocol
|
||||
test.json > test.jtx
|
||||
test.json > xrpl.json
|
||||
@@ -110,6 +108,7 @@ test.jtx > xrpl.tx
|
||||
test.ledger > test.jtx
|
||||
test.ledger > test.toplevel
|
||||
test.ledger > xrpl.basics
|
||||
test.ledger > xrpld.app
|
||||
test.ledger > xrpld.core
|
||||
test.ledger > xrpl.ledger
|
||||
test.ledger > xrpl.protocol
|
||||
@@ -126,7 +125,6 @@ test.overlay > xrpl.basics
|
||||
test.overlay > xrpld.app
|
||||
test.overlay > xrpld.overlay
|
||||
test.overlay > xrpld.peerfinder
|
||||
test.overlay > xrpl.ledger
|
||||
test.overlay > xrpl.nodestore
|
||||
test.overlay > xrpl.protocol
|
||||
test.overlay > xrpl.shamap
|
||||
@@ -185,6 +183,7 @@ xrpl.conditions > xrpl.basics
|
||||
xrpl.conditions > xrpl.protocol
|
||||
xrpl.core > xrpl.basics
|
||||
xrpl.core > xrpl.json
|
||||
xrpl.core > xrpl.ledger
|
||||
xrpl.core > xrpl.protocol
|
||||
xrpl.json > xrpl.basics
|
||||
xrpl.ledger > xrpl.basics
|
||||
@@ -235,7 +234,6 @@ xrpld.app > xrpl.shamap
|
||||
xrpld.app > xrpl.tx
|
||||
xrpld.consensus > xrpl.basics
|
||||
xrpld.consensus > xrpl.json
|
||||
xrpld.consensus > xrpl.ledger
|
||||
xrpld.consensus > xrpl.protocol
|
||||
xrpld.core > xrpl.basics
|
||||
xrpld.core > xrpl.core
|
||||
|
||||
8
.github/scripts/rename/copyright.sh
vendored
8
.github/scripts/rename/copyright.sh
vendored
@@ -76,11 +76,11 @@ fi
|
||||
if ! grep -q 'Dev Null' src/test/rpc/ValidatorInfo_test.cpp; then
|
||||
echo -e "// Copyright (c) 2020 Dev Null Productions\n\n$(cat src/test/rpc/ValidatorInfo_test.cpp)" > src/test/rpc/ValidatorInfo_test.cpp
|
||||
fi
|
||||
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/server_info/Manifest.cpp; then
|
||||
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/server_info/Manifest.cpp)" > src/xrpld/rpc/handlers/server_info/Manifest.cpp
|
||||
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/DoManifest.cpp; then
|
||||
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/DoManifest.cpp)" > src/xrpld/rpc/handlers/DoManifest.cpp
|
||||
fi
|
||||
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp; then
|
||||
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp)" > src/xrpld/rpc/handlers/admin/status/ValidatorInfo.cpp
|
||||
if ! grep -q 'Dev Null' src/xrpld/rpc/handlers/ValidatorInfo.cpp; then
|
||||
echo -e "// Copyright (c) 2019 Dev Null Productions\n\n$(cat src/xrpld/rpc/handlers/ValidatorInfo.cpp)" > src/xrpld/rpc/handlers/ValidatorInfo.cpp
|
||||
fi
|
||||
if ! grep -q 'Bougalis' include/xrpl/basics/SlabAllocator.h; then
|
||||
echo -e "// Copyright (c) 2022, Nikolaos D. Bougalis <nikb@bougalis.net>\n\n$(cat include/xrpl/basics/SlabAllocator.h)" > include/xrpl/basics/SlabAllocator.h # cspell: ignore Nikolaos Bougalis nikb
|
||||
|
||||
4
.github/workflows/check-pr-commits.yml
vendored
4
.github/workflows/check-pr-commits.yml
vendored
@@ -1,7 +1,7 @@
|
||||
name: Check PR commits
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
pull_request:
|
||||
|
||||
# The action needs to have write permissions to post comments on the PR.
|
||||
permissions:
|
||||
@@ -10,4 +10,4 @@ permissions:
|
||||
|
||||
jobs:
|
||||
check_commits:
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-commits.yml@e2c7f400d1e85ae65dad552fd425169fbacca4a3
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-commits.yml@481048b78b94ac3343d1292b4ef125a813879f2b
|
||||
|
||||
2
.github/workflows/check-pr-title.yml
vendored
2
.github/workflows/check-pr-title.yml
vendored
@@ -11,4 +11,4 @@ on:
|
||||
jobs:
|
||||
check_title:
|
||||
if: ${{ github.event.pull_request.draft != true }}
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@a5d8dd35be543365e90a11358447130c8763871d
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@e2c7f400d1e85ae65dad552fd425169fbacca4a3
|
||||
|
||||
25
.github/workflows/conflicting-pr.yml
vendored
25
.github/workflows/conflicting-pr.yml
vendored
@@ -1,25 +0,0 @@
|
||||
name: Label PRs with merge conflicts
|
||||
|
||||
on:
|
||||
# So that PRs touching the same files as the push are updated.
|
||||
push:
|
||||
# So that the `dirtyLabel` is removed if conflicts are resolved.
|
||||
# We recommend `pull_request_target` so that github secrets are available.
|
||||
# In `pull_request` we wouldn't be able to change labels of fork PRs.
|
||||
pull_request_target:
|
||||
types: [synchronize]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if PRs are dirty
|
||||
uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3.0.3
|
||||
with:
|
||||
dirtyLabel: "PR: has conflicts"
|
||||
repoToken: "${{ secrets.GITHUB_TOKEN }}"
|
||||
commentOnDirty: "This PR has conflicts, please resolve them in order for the PR to be reviewed."
|
||||
commentOnClean: "All conflicts have been resolved. Assigned reviewers can now start or resume their review."
|
||||
2
.github/workflows/pre-commit.yml
vendored
2
.github/workflows/pre-commit.yml
vendored
@@ -14,7 +14,7 @@ on:
|
||||
jobs:
|
||||
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
|
||||
run-hooks:
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@9307df762265e15c745ddcdb38a581c989f7f349
|
||||
uses: XRPLF/actions/.github/workflows/pre-commit.yml@e7896f15cc60d0da1a272c77ee5c4026b424f9c7
|
||||
with:
|
||||
runs_on: ubuntu-latest
|
||||
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-41ec7c1" }'
|
||||
|
||||
11
.github/workflows/publish-docs.yml
vendored
11
.github/workflows/publish-docs.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "release*"
|
||||
paths:
|
||||
- ".github/workflows/publish-docs.yml"
|
||||
- "*.md"
|
||||
@@ -36,7 +37,7 @@ env:
|
||||
BUILD_DIR: build
|
||||
# ubuntu-latest has only 2 CPUs for private repositories
|
||||
# https://docs.github.com/en/actions/reference/runners/github-hosted-runners#standard-github-hosted-runners-for--private-repositories
|
||||
NPROC_SUBTRACT: ${{ github.event.repository.visibility == 'public' && '2' || '1' }}
|
||||
NPROC_SUBTRACT: ${{ github.event.repository.private && '1' || '2' }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -47,7 +48,7 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
|
||||
uses: XRPLF/actions/prepare-runner@2bbc2dc1abeec7bfaa886804ab86871ac201764e
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
@@ -81,13 +82,13 @@ jobs:
|
||||
cmake --build . --target docs --parallel ${BUILD_NPROC}
|
||||
|
||||
- name: Create documentation artifact
|
||||
if: ${{ (github.repository_owner == 'XRPLF' || github.event.repository.visibility == 'public') && github.event_name == 'push' }}
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0
|
||||
with:
|
||||
path: ${{ env.BUILD_DIR }}/docs/html
|
||||
|
||||
deploy:
|
||||
if: ${{ (github.repository_owner == 'XRPLF' || github.event.repository.visibility == 'public') && github.event_name == 'push' }}
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
@@ -99,4 +100,4 @@ jobs:
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deploy
|
||||
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
|
||||
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
|
||||
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
|
||||
uses: XRPLF/actions/prepare-runner@2bbc2dc1abeec7bfaa886804ab86871ac201764e
|
||||
with:
|
||||
enable_ccache: ${{ inputs.ccache_enabled }}
|
||||
|
||||
@@ -199,7 +199,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Upload the binary (Linux)
|
||||
if: ${{ (github.repository_owner == 'XRPLF' || github.event.repository.visibility == 'public') && runner.os == 'Linux' }}
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && runner.os == 'Linux' }}
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: xrpld-${{ inputs.config_name }}
|
||||
@@ -298,7 +298,7 @@ jobs:
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
|
||||
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0
|
||||
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3
|
||||
with:
|
||||
disable_search: true
|
||||
disable_telem: true
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
|
||||
uses: XRPLF/actions/prepare-runner@2bbc2dc1abeec7bfaa886804ab86871ac201764e
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
@@ -80,10 +80,10 @@ jobs:
|
||||
env:
|
||||
TARGETS: ${{ inputs.files != '' && inputs.files || 'src tests' }}
|
||||
run: |
|
||||
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -allow-no-checks ${TARGETS} 2>&1 | tee clang-tidy-output.txt
|
||||
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" ${TARGETS} 2>&1 | tee clang-tidy-output.txt
|
||||
|
||||
- name: Upload clang-tidy output
|
||||
if: ${{ (github.repository_owner == 'XRPLF' || github.event.repository.visibility == 'public') && steps.run_clang_tidy.outcome != 'success' }}
|
||||
if: steps.run_clang_tidy.outcome != 'success'
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
with:
|
||||
name: clang-tidy-results
|
||||
|
||||
2
.github/workflows/reusable-clang-tidy.yml
vendored
2
.github/workflows/reusable-clang-tidy.yml
vendored
@@ -51,5 +51,5 @@ jobs:
|
||||
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_cpp_changed == 'true' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
|
||||
uses: ./.github/workflows/reusable-clang-tidy-files.yml
|
||||
with:
|
||||
files: ${{ (needs.determine-files.outputs.clang_tidy_config_changed != 'true' && inputs.check_only_changed) && needs.determine-files.outputs.all_changed_files || '' }}
|
||||
files: ${{ needs.determine-files.outputs.clang_tidy_config_changed == 'true' && '' || (inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '') }}
|
||||
create_issue_on_failure: ${{ inputs.create_issue_on_failure }}
|
||||
|
||||
2
.github/workflows/upload-conan-deps.yml
vendored
2
.github/workflows/upload-conan-deps.yml
vendored
@@ -70,7 +70,7 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
|
||||
uses: XRPLF/actions/prepare-runner@2bbc2dc1abeec7bfaa886804ab86871ac201764e
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -71,8 +71,6 @@ DerivedData
|
||||
/.zed/
|
||||
|
||||
# AI tools.
|
||||
/.agent
|
||||
/.agents
|
||||
/.augment
|
||||
/.claude
|
||||
/CLAUDE.md
|
||||
|
||||
77
BUILD.md
77
BUILD.md
@@ -125,9 +125,9 @@ default profile.
|
||||
|
||||
### Patched recipes
|
||||
|
||||
Occasionally, we need patched recipes or recipes not present in Conan Center.
|
||||
We maintain a fork of the Conan Center Index
|
||||
[here](https://github.com/XRPLF/conan-center-index/) containing the modified and newly added recipes.
|
||||
The recipes in Conan Center occasionally need to be patched for compatibility
|
||||
with the latest version of `xrpld`. We maintain a fork of the Conan Center
|
||||
[here](https://github.com/XRPLF/conan-center-index/) containing the patches.
|
||||
|
||||
To ensure our patched recipes are used, you must add our Conan remote at a
|
||||
higher index than the default Conan Center remote, so it is consulted first. You
|
||||
@@ -137,11 +137,19 @@ can do this by running:
|
||||
conan remote add --index 0 xrplf https://conan.ripplex.io
|
||||
```
|
||||
|
||||
Alternatively, you can pull our recipes from the repository and export them locally:
|
||||
Alternatively, you can pull the patched recipes into the repository and use them
|
||||
locally:
|
||||
|
||||
```bash
|
||||
# Extract the version number from the lockfile.
|
||||
function extract_version {
|
||||
version=$(cat conan.lock | sed -nE "s@.+${1}/(.+)#.+@\1@p" | head -n1)
|
||||
echo ${version}
|
||||
}
|
||||
|
||||
# Define which recipes to export.
|
||||
recipes=('abseil' 'ed25519' 'grpc' 'm4' 'mpt-crypto' 'openssl' 'secp256k1' 'snappy' 'soci' 'wasm-xrplf' 'wasmi')
|
||||
recipes=('ed25519' 'grpc' 'nudb' 'openssl' 'secp256k1' 'snappy' 'soci')
|
||||
folders=('all' 'all' 'all' '3.x.x' 'all' 'all' 'all')
|
||||
|
||||
# Selectively check out the recipes from our CCI fork.
|
||||
cd external
|
||||
@@ -150,19 +158,29 @@ cd conan-center-index
|
||||
git init
|
||||
git remote add origin git@github.com:XRPLF/conan-center-index.git
|
||||
git sparse-checkout init
|
||||
for recipe in "${recipes[@]}"; do
|
||||
echo "Checking out recipe '${recipe}'..."
|
||||
git sparse-checkout add recipes/${recipe}
|
||||
for ((index = 1; index <= ${#recipes[@]}; index++)); do
|
||||
recipe=${recipes[index]}
|
||||
folder=${folders[index]}
|
||||
echo "Checking out recipe '${recipe}' from folder '${folder}'..."
|
||||
git sparse-checkout add recipes/${recipe}/${folder}
|
||||
done
|
||||
git fetch origin master
|
||||
git checkout master
|
||||
cd ../..
|
||||
|
||||
./export_all.sh
|
||||
cd ../../
|
||||
# Export the recipes into the local cache.
|
||||
for ((index = 1; index <= ${#recipes[@]}; index++)); do
|
||||
recipe=${recipes[index]}
|
||||
folder=${folders[index]}
|
||||
version=$(extract_version ${recipe})
|
||||
echo "Exporting '${recipe}/${version}' from '${recipe}/${folder}'..."
|
||||
conan export --version $(extract_version ${recipe}) \
|
||||
external/conan-center-index/recipes/${recipe}/${folder}
|
||||
done
|
||||
```
|
||||
|
||||
In the case we switch to a newer version of a dependency that still requires a
|
||||
patch or add a new dependency, it will be necessary for you to pull in the changes and re-export the
|
||||
patch, it will be necessary for you to pull in the changes and re-export the
|
||||
updated dependencies with the newer version. However, if we switch to a newer
|
||||
version that no longer requires a patch, no action is required on your part, as
|
||||
the new recipe will be automatically pulled from the official Conan Center.
|
||||
@@ -171,8 +189,6 @@ the new recipe will be automatically pulled from the official Conan Center.
|
||||
> You might need to add `--lockfile=""` to your `conan install` command
|
||||
> to avoid automatic use of the existing `conan.lock` file when you run
|
||||
> `conan export` manually on your machine
|
||||
>
|
||||
> This is not recommended though, as you might end up using different revisions of recipes.
|
||||
|
||||
### Conan profile tweaks
|
||||
|
||||
@@ -188,14 +204,39 @@ Possible values are ['5.0', '5.1', '6.0', '6.1', '7.0', '7.3', '8.0', '8.1',
|
||||
Read "http://docs.conan.io/2/knowledge/faq.html#error-invalid-setting"
|
||||
```
|
||||
|
||||
you need to add your compiler to the list of compiler versions in
|
||||
`$(conan config home)/settings_user.yml`, by adding the required version number(s)
|
||||
you need to amend the list of compiler versions in
|
||||
`$(conan config home)/settings.yml`, by appending the required version number(s)
|
||||
to the `version` array specific for your compiler. For example:
|
||||
|
||||
```yaml
|
||||
compiler:
|
||||
apple-clang:
|
||||
version: ["17.0"]
|
||||
apple-clang:
|
||||
version:
|
||||
[
|
||||
"5.0",
|
||||
"5.1",
|
||||
"6.0",
|
||||
"6.1",
|
||||
"7.0",
|
||||
"7.3",
|
||||
"8.0",
|
||||
"8.1",
|
||||
"9.0",
|
||||
"9.1",
|
||||
"10.0",
|
||||
"11.0",
|
||||
"12.0",
|
||||
"13",
|
||||
"13.0",
|
||||
"13.1",
|
||||
"14",
|
||||
"14.0",
|
||||
"15",
|
||||
"15.0",
|
||||
"16",
|
||||
"16.0",
|
||||
"17",
|
||||
"17.0",
|
||||
]
|
||||
```
|
||||
|
||||
#### Multiple compilers
|
||||
|
||||
@@ -259,10 +259,6 @@ There is a Continuous Integration job that runs clang-tidy on pull requests. The
|
||||
|
||||
This ensures that configuration changes don't introduce new warnings across the codebase.
|
||||
|
||||
### Installing clang-tidy
|
||||
|
||||
See the [environment setup guide](./docs/build/environment.md#clang-tidy) for platform-specific installation instructions.
|
||||
|
||||
### Running clang-tidy locally
|
||||
|
||||
Before running clang-tidy, you must build the project to generate required files (particularly protobuf headers). Refer to [`BUILD.md`](./BUILD.md) for build instructions.
|
||||
@@ -270,15 +266,10 @@ Before running clang-tidy, you must build the project to generate required files
|
||||
Then run clang-tidy on your local changes:
|
||||
|
||||
```
|
||||
run-clang-tidy -p build -allow-no-checks src tests
|
||||
run-clang-tidy -p build src tests
|
||||
```
|
||||
|
||||
This will check all source files in the `src`, `include` and `tests` directories using the compile commands from your `build` directory.
|
||||
If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix` to the above command:
|
||||
|
||||
```
|
||||
run-clang-tidy -p build -quiet -fix -allow-no-checks src tests
|
||||
```
|
||||
This will check all source files in the `src` and `tests` directories using the compile commands from your `build` directory.
|
||||
|
||||
## Contracts and instrumentation
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2011, Arthur Britto, David Schwartz, Jed McCaleb, Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant.
|
||||
Copyright (c) 2012-present, the XRP Ledger developers.
|
||||
Copyright (c) 2012-2025, the XRP Ledger developers.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
||||
@@ -140,28 +140,6 @@ function(setup_protocol_autogen)
|
||||
)
|
||||
endif()
|
||||
|
||||
# Check pip index URL configuration
|
||||
execute_process(
|
||||
COMMAND ${VENV_PIP} config get global.index-url
|
||||
OUTPUT_VARIABLE PIP_INDEX_URL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
# Default PyPI URL
|
||||
set(DEFAULT_PIP_INDEX "https://pypi.org/simple")
|
||||
|
||||
# Show warning if using non-default index
|
||||
if(PIP_INDEX_URL AND NOT PIP_INDEX_URL STREQUAL "")
|
||||
if(NOT PIP_INDEX_URL STREQUAL DEFAULT_PIP_INDEX)
|
||||
message(
|
||||
WARNING
|
||||
"Private pip index URL detected: ${PIP_INDEX_URL}\n"
|
||||
"You may need to connect to VPN to access this URL."
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Installing Python dependencies...")
|
||||
execute_process(
|
||||
COMMAND ${VENV_PIP} install --upgrade pip
|
||||
|
||||
54
conan.lock
54
conan.lock
@@ -1,57 +1,59 @@
|
||||
{
|
||||
"version": "0.5",
|
||||
"requires": [
|
||||
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1774439233.809",
|
||||
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1765850150.075",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987",
|
||||
"sqlite3/3.51.0#66aa11eabd0e34954c5c1c061ad44abe%1774467355.988",
|
||||
"soci/4.0.3#fe32b9ad5eb47e79ab9e45a68f363945%1774450067.231",
|
||||
"sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1765850149.926",
|
||||
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1765850149.46",
|
||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878",
|
||||
"secp256k1/0.7.1#481881709eb0bdd0185a12b912bbe8ad%1770910500.329",
|
||||
"secp256k1/0.7.1#3a61e95e220062ef32c48d019e9c81f7%1770306721.686",
|
||||
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1765850186.86",
|
||||
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1774398111.888",
|
||||
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12",
|
||||
"openssl/3.6.1#e6399de266349245a4542fc5f6c71552%1774458290.139",
|
||||
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1774883011.384",
|
||||
"re2/20230301#ca3b241baec15bd31ea9187150e0b333%1765850148.103",
|
||||
"protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1765850161.038",
|
||||
"openssl/3.5.5#05a4ac5b7323f7a329b2db1391d9941f%1769599205.414",
|
||||
"nudb/2.0.9#0432758a24204da08fee953ec9ea03cb%1769436073.32",
|
||||
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914",
|
||||
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492",
|
||||
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1765842973.03",
|
||||
"libarchive/3.8.1#ffee18995c706e02bf96e7a2f7042e0d%1765850144.736",
|
||||
"jemalloc/5.3.0#e951da9cf599e956cebc117880d2d9f8%1729241615.244",
|
||||
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1768312129.152",
|
||||
"grpc/1.78.1#b1a9e74b145cc471bed4dc64dc6eb2c1%1774467387.342",
|
||||
"grpc/1.72.0#f244a57bff01e708c55a1100b12e1589%1765850193.734",
|
||||
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1765850143.772",
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1765850143.772",
|
||||
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1774439234.681",
|
||||
"c-ares/1.34.5#5581c2b62a608b40bb85d965ab3ec7c8%1765850144.336",
|
||||
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1765850143.837",
|
||||
"boost/1.90.0#d5e8defe7355494953be18524a7f135b%1769454080.269",
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196"
|
||||
"abseil/20250127.0#99262a368bd01c0ccca8790dfced9719%1766517936.993"
|
||||
],
|
||||
"build_requires": [
|
||||
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1774439233.809",
|
||||
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1774447376.964",
|
||||
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12",
|
||||
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1765850150.075",
|
||||
"strawberryperl/5.32.1.1#707032463aa0620fa17ec0d887f5fe41%1765850165.196",
|
||||
"protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1765850161.038",
|
||||
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1765850144.707",
|
||||
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
|
||||
"m4/1.4.19#5d7a4994e5875d76faf7acf3ed056036%1774365463.87",
|
||||
"cmake/4.3.0#b939a42e98f593fb34d3a8c5cc860359%1774439249.183",
|
||||
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1774439233.447",
|
||||
"msys2/cci.latest#eea83308ad7e9023f7318c60d5a9e6cb%1770199879.083",
|
||||
"m4/1.4.19#70dc8bbb33e981d119d2acc0175cf381%1763158052.846",
|
||||
"cmake/4.2.0#ae0a44f44a1ef9ab68fd4b3e9a1f8671%1765850153.937",
|
||||
"cmake/3.31.10#313d16a1aa16bbdb2ca0792467214b76%1765850153.479",
|
||||
"b2/5.3.3#107c15377719889654eb9a162a673975%1765850144.355",
|
||||
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
|
||||
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196"
|
||||
"abseil/20250127.0#99262a368bd01c0ccca8790dfced9719%1766517936.993"
|
||||
],
|
||||
"python_requires": [],
|
||||
"overrides": {
|
||||
"protobuf/[>=5.27.0 <7]": [
|
||||
"protobuf/6.33.5"
|
||||
"boost/1.90.0#d5e8defe7355494953be18524a7f135b": [
|
||||
null,
|
||||
"boost/1.90.0"
|
||||
],
|
||||
"protobuf/5.27.0": [
|
||||
"protobuf/6.32.1"
|
||||
],
|
||||
"lz4/1.9.4": [
|
||||
"lz4/1.10.0"
|
||||
],
|
||||
"boost/[>=1.83.0 <1.91.0]": [
|
||||
"boost/1.90.0"
|
||||
],
|
||||
"sqlite3/[>=3.44 <4]": [
|
||||
"sqlite3/3.51.0"
|
||||
"sqlite3/3.44.2": [
|
||||
"sqlite3/3.49.1"
|
||||
],
|
||||
"boost/1.83.0": [
|
||||
"boost/1.90.0"
|
||||
|
||||
23
conanfile.py
23
conanfile.py
@@ -1,9 +1,10 @@
|
||||
import os
|
||||
import re
|
||||
import os
|
||||
|
||||
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
|
||||
|
||||
from conan import ConanFile
|
||||
from conan import __version__ as conan_version
|
||||
|
||||
|
||||
class Xrpl(ConanFile):
|
||||
@@ -29,10 +30,10 @@ class Xrpl(ConanFile):
|
||||
|
||||
requires = [
|
||||
"ed25519/2015.03",
|
||||
"grpc/1.78.1",
|
||||
"grpc/1.72.0",
|
||||
"libarchive/3.8.1",
|
||||
"nudb/2.0.9",
|
||||
"openssl/3.6.1",
|
||||
"openssl/3.5.5",
|
||||
"secp256k1/0.7.1",
|
||||
"soci/4.0.3",
|
||||
"zlib/1.3.1",
|
||||
@@ -43,7 +44,7 @@ class Xrpl(ConanFile):
|
||||
]
|
||||
|
||||
tool_requires = [
|
||||
"protobuf/6.33.5",
|
||||
"protobuf/6.32.1",
|
||||
]
|
||||
|
||||
default_options = {
|
||||
@@ -136,16 +137,20 @@ class Xrpl(ConanFile):
|
||||
self.default_options["fPIC"] = False
|
||||
|
||||
def requirements(self):
|
||||
self.requires("boost/1.90.0", force=True, transitive_headers=True)
|
||||
self.requires("date/3.0.4", transitive_headers=True)
|
||||
# Conan 2 requires transitive headers to be specified
|
||||
transitive_headers_opt = (
|
||||
{"transitive_headers": True} if conan_version.split(".")[0] == "2" else {}
|
||||
)
|
||||
self.requires("boost/1.90.0", force=True, **transitive_headers_opt)
|
||||
self.requires("date/3.0.4", **transitive_headers_opt)
|
||||
self.requires("lz4/1.10.0", force=True)
|
||||
self.requires("protobuf/6.33.5", force=True)
|
||||
self.requires("sqlite3/3.51.0", force=True)
|
||||
self.requires("protobuf/6.32.1", force=True)
|
||||
self.requires("sqlite3/3.49.1", force=True)
|
||||
if self.options.jemalloc:
|
||||
self.requires("jemalloc/5.3.0")
|
||||
if self.options.rocksdb:
|
||||
self.requires("rocksdb/10.5.1")
|
||||
self.requires("xxhash/0.8.3", transitive_headers=True)
|
||||
self.requires("xxhash/0.8.3", **transitive_headers_opt)
|
||||
|
||||
exports_sources = (
|
||||
"CMakeLists.txt",
|
||||
|
||||
@@ -297,7 +297,6 @@ words:
|
||||
- venv
|
||||
- vfalco
|
||||
- vinnie
|
||||
- wasmi
|
||||
- wextra
|
||||
- wptr
|
||||
- writeme
|
||||
|
||||
29
docs/build/environment.md
vendored
29
docs/build/environment.md
vendored
@@ -109,32 +109,3 @@ Install CMake with Homebrew too:
|
||||
```
|
||||
brew install cmake
|
||||
```
|
||||
|
||||
## Clang-tidy
|
||||
|
||||
Clang-tidy is required to run static analysis checks locally (see [CONTRIBUTING.md](../../CONTRIBUTING.md)).
|
||||
It is not required to build the project. Currently this project uses clang-tidy version 21.
|
||||
|
||||
### Linux
|
||||
|
||||
LLVM 21 is not available in the default Debian 12 (Bookworm) repositories.
|
||||
Install it using the official LLVM apt installer:
|
||||
|
||||
```
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 21
|
||||
sudo apt install --yes clang-tidy-21
|
||||
```
|
||||
|
||||
Then use `run-clang-tidy-21` when running clang-tidy locally.
|
||||
|
||||
### macOS
|
||||
|
||||
Install LLVM 21 via Homebrew:
|
||||
|
||||
```
|
||||
brew install llvm@21
|
||||
```
|
||||
|
||||
Then use `run-clang-tidy` from the LLVM 21 Homebrew prefix when running clang-tidy locally.
|
||||
|
||||
@@ -311,7 +311,7 @@ template <class T>
|
||||
bool
|
||||
set(T& target, T const& defaultValue, std::string const& name, Section const& section)
|
||||
{
|
||||
bool const found_and_valid = set<T>(target, name, section);
|
||||
bool found_and_valid = set<T>(target, name, section);
|
||||
if (!found_and_valid)
|
||||
target = defaultValue;
|
||||
return found_and_valid;
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
{
|
||||
// Insert ourselves at the front of the lock-free linked list
|
||||
CountedObjects& instance = CountedObjects::getInstance();
|
||||
Counter* head = nullptr;
|
||||
Counter* head;
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
@@ -93,7 +93,7 @@ class DecayWindow
|
||||
public:
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
explicit DecayWindow(time_point now) : when_(now)
|
||||
explicit DecayWindow(time_point now) : value_(0), when_(now)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ private:
|
||||
when_ = now;
|
||||
}
|
||||
|
||||
double value_{0};
|
||||
double value_;
|
||||
time_point when_;
|
||||
};
|
||||
|
||||
|
||||
@@ -84,8 +84,7 @@ public:
|
||||
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
SharedIntrusive(
|
||||
SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
SharedIntrusive(SharedIntrusive<TT>&& rhs);
|
||||
|
||||
SharedIntrusive&
|
||||
operator=(SharedIntrusive const& rhs);
|
||||
@@ -107,8 +106,7 @@ public:
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
SharedIntrusive&
|
||||
operator=(
|
||||
SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
operator=(SharedIntrusive<TT>&& rhs);
|
||||
|
||||
/** Adopt the raw pointer. The strong reference may or may not be
|
||||
incremented, depending on the TAdoptTag
|
||||
@@ -316,8 +314,7 @@ public:
|
||||
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
SharedWeakUnion(
|
||||
SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
SharedWeakUnion(SharedIntrusive<TT>&& rhs);
|
||||
|
||||
SharedWeakUnion&
|
||||
operator=(SharedWeakUnion const& rhs);
|
||||
@@ -330,8 +327,7 @@ public:
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
SharedWeakUnion&
|
||||
operator=(
|
||||
SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
operator=(SharedIntrusive<TT>&& rhs);
|
||||
|
||||
~SharedWeakUnion();
|
||||
|
||||
|
||||
@@ -68,7 +68,9 @@ SharedIntrusive<T>::operator=(SharedIntrusive const& rhs)
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format off
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format on
|
||||
SharedIntrusive<T>&
|
||||
SharedIntrusive<T>::operator=(SharedIntrusive<TT> const& rhs)
|
||||
{
|
||||
@@ -99,7 +101,9 @@ SharedIntrusive<T>::operator=(SharedIntrusive&& rhs)
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format off
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format on
|
||||
SharedIntrusive<T>&
|
||||
SharedIntrusive<T>::operator=(SharedIntrusive<TT>&& rhs)
|
||||
{
|
||||
@@ -303,7 +307,9 @@ WeakIntrusive<T>::WeakIntrusive(SharedIntrusive<T> const& rhs) : ptr_{rhs.unsafe
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format off
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format on
|
||||
WeakIntrusive<T>&
|
||||
WeakIntrusive<T>::operator=(SharedIntrusive<TT> const& rhs)
|
||||
{
|
||||
@@ -448,7 +454,9 @@ SharedWeakUnion<T>::operator=(SharedWeakUnion const& rhs)
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format off
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format on
|
||||
SharedWeakUnion<T>&
|
||||
SharedWeakUnion<T>::operator=(SharedIntrusive<TT> const& rhs)
|
||||
{
|
||||
@@ -462,7 +470,9 @@ SharedWeakUnion<T>::operator=(SharedIntrusive<TT> const& rhs)
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format off
|
||||
requires std::convertible_to<TT*, T*>
|
||||
// clang-format on
|
||||
SharedWeakUnion<T>&
|
||||
SharedWeakUnion<T>::operator=(SharedIntrusive<TT>&& rhs)
|
||||
{
|
||||
|
||||
@@ -448,7 +448,7 @@ inline void
|
||||
partialDestructorFinished(T** o)
|
||||
{
|
||||
T& self = **o;
|
||||
IntrusiveRefCounts::RefCountPair const p =
|
||||
IntrusiveRefCounts::RefCountPair p =
|
||||
self.refCounts.fetch_or(IntrusiveRefCounts::partialDestroyFinishedMask);
|
||||
XRPL_ASSERT(
|
||||
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit && !p.strong),
|
||||
|
||||
@@ -73,12 +73,12 @@ struct MantissaRange
|
||||
enum mantissa_scale { small, large };
|
||||
|
||||
explicit constexpr MantissaRange(mantissa_scale scale_)
|
||||
: min(getMin(scale_)), log(logTen(min).value_or(-1)), scale(scale_)
|
||||
: min(getMin(scale_)), max(min * 10 - 1), log(logTen(min).value_or(-1)), scale(scale_)
|
||||
{
|
||||
}
|
||||
|
||||
rep min;
|
||||
rep max{min * 10 - 1};
|
||||
rep max;
|
||||
int log;
|
||||
mantissa_scale scale;
|
||||
|
||||
|
||||
@@ -91,10 +91,10 @@ class SlabAllocator
|
||||
std::uint8_t*
|
||||
allocate() noexcept
|
||||
{
|
||||
std::uint8_t* ret = nullptr; // NOLINT(misc-const-correctness)
|
||||
std::uint8_t* ret;
|
||||
|
||||
{
|
||||
std::lock_guard const l(m_);
|
||||
std::lock_guard l(m_);
|
||||
|
||||
ret = l_;
|
||||
|
||||
@@ -123,7 +123,7 @@ class SlabAllocator
|
||||
{
|
||||
XRPL_ASSERT(own(ptr), "xrpl::SlabAllocator::SlabBlock::deallocate : own input");
|
||||
|
||||
std::lock_guard const l(m_);
|
||||
std::lock_guard l(m_);
|
||||
|
||||
// Use memcpy to avoid unaligned UB
|
||||
// (will optimize to equivalent code)
|
||||
@@ -210,13 +210,16 @@ public:
|
||||
|
||||
// No slab can satisfy our request, so we attempt to allocate a new
|
||||
// one here:
|
||||
std::size_t const size = slabSize_;
|
||||
std::size_t size = slabSize_;
|
||||
|
||||
// We want to allocate the memory at a 2 MiB boundary, to make it
|
||||
// possible to use hugepage mappings on Linux:
|
||||
auto buf = boost::alignment::aligned_alloc(megabytes(std::size_t(2)), size);
|
||||
|
||||
// clang-format off
|
||||
if (!buf) [[unlikely]]
|
||||
return nullptr;
|
||||
// clang-format on
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
// When allocating large blocks, attempt to leverage Linux's
|
||||
|
||||
@@ -66,12 +66,12 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end)
|
||||
|
||||
while (iter != end)
|
||||
{
|
||||
int const cHigh = digitLookupTable[*iter++];
|
||||
int cHigh = digitLookupTable[*iter++];
|
||||
|
||||
if (cHigh < 0)
|
||||
return {};
|
||||
|
||||
int const cLow = digitLookupTable[*iter++];
|
||||
int cLow = digitLookupTable[*iter++];
|
||||
|
||||
if (cLow < 0)
|
||||
return {};
|
||||
|
||||
@@ -182,7 +182,8 @@ private:
|
||||
: hook(collector->make_hook(handler))
|
||||
, size(collector->make_gauge(prefix, "size"))
|
||||
, hit_rate(collector->make_gauge(prefix, "hit_rate"))
|
||||
|
||||
, hits(0)
|
||||
, misses(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -190,8 +191,8 @@ private:
|
||||
beast::insight::Gauge size;
|
||||
beast::insight::Gauge hit_rate;
|
||||
|
||||
std::size_t hits{0};
|
||||
std::size_t misses{0};
|
||||
std::size_t hits;
|
||||
std::size_t misses;
|
||||
};
|
||||
|
||||
class KeyOnlyEntry
|
||||
@@ -293,10 +294,10 @@ private:
|
||||
clock_type::duration const m_target_age;
|
||||
|
||||
// Number of items cached
|
||||
int m_cache_count{0};
|
||||
int m_cache_count;
|
||||
cache_type m_cache; // Hold strong reference to recent objects
|
||||
std::uint64_t m_hits{0};
|
||||
std::uint64_t m_misses{0};
|
||||
std::uint64_t m_hits;
|
||||
std::uint64_t m_misses;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -36,7 +36,9 @@ inline TaggedCache<
|
||||
, m_name(name)
|
||||
, m_target_size(size)
|
||||
, m_target_age(expiration)
|
||||
|
||||
, m_cache_count(0)
|
||||
, m_hits(0)
|
||||
, m_misses(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ private:
|
||||
while (in != sv.end())
|
||||
{
|
||||
std::uint32_t accum = {};
|
||||
for (std::uint32_t const shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
|
||||
for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
|
||||
{
|
||||
if (auto const result = hexCharToUInt(*in++, shift, accum);
|
||||
result != ParseResult::okay)
|
||||
@@ -335,13 +335,11 @@ public:
|
||||
operator=(std::uint64_t uHost)
|
||||
{
|
||||
*this = beast::zero;
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
|
||||
union
|
||||
{
|
||||
unsigned u[2];
|
||||
std::uint64_t ul;
|
||||
};
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-member-init)
|
||||
// Put in least significant bits.
|
||||
ul = boost::endian::native_to_big(uHost);
|
||||
data_[WIDTH - 2] = u[0];
|
||||
@@ -446,7 +444,7 @@ public:
|
||||
|
||||
for (int i = WIDTH; i--;)
|
||||
{
|
||||
std::uint64_t const n = carry + boost::endian::big_to_native(data_[i]) +
|
||||
std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) +
|
||||
boost::endian::big_to_native(b.data_[i]);
|
||||
|
||||
data_[i] = boost::endian::native_to_big(static_cast<std::uint32_t>(n));
|
||||
@@ -623,7 +621,7 @@ template <>
|
||||
inline std::size_t
|
||||
extract(uint256 const& key)
|
||||
{
|
||||
std::size_t result = 0;
|
||||
std::size_t result;
|
||||
// Use memcpy to avoid unaligned UB
|
||||
// (will optimize to equivalent code)
|
||||
std::memcpy(&result, key.data(), sizeof(std::size_t));
|
||||
|
||||
@@ -54,7 +54,7 @@ Throw(Args&&... args)
|
||||
|
||||
E e(std::forward<Args>(args)...);
|
||||
LogThrow(std::string("Throwing exception of type " + beast::type_name<E>() + ": ") + e.what());
|
||||
throw std::move(e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
/** Called when faulty logic causes a broken invariant. */
|
||||
|
||||
@@ -32,7 +32,7 @@ make_seed_pair() noexcept
|
||||
// state_t& operator=(state_t const&) = delete;
|
||||
};
|
||||
static state_t state;
|
||||
std::lock_guard const lock(state.mutex);
|
||||
std::lock_guard lock(state.mutex);
|
||||
return {state.dist(state.gen), state.dist(state.gen)};
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,11 @@ namespace xrpl {
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
static_assert(
|
||||
// NOLINTNEXTLINE(misc-redundant-expression)
|
||||
std::is_integral<beast::xor_shift_engine::result_type>::value &&
|
||||
std::is_unsigned<beast::xor_shift_engine::result_type>::value,
|
||||
"The Ripple default PRNG engine must return an unsigned integral type.");
|
||||
|
||||
static_assert(
|
||||
// NOLINTNEXTLINE(misc-redundant-expression)
|
||||
std::numeric_limits<beast::xor_shift_engine::result_type>::max() >=
|
||||
std::numeric_limits<std::uint64_t>::max(),
|
||||
"The Ripple default PRNG engine return must be at least 64 bits wide.");
|
||||
@@ -58,9 +56,9 @@ default_prng()
|
||||
|
||||
// The thread-specific PRNGs:
|
||||
thread_local beast::xor_shift_engine engine = [] {
|
||||
std::uint64_t seed = 0;
|
||||
std::uint64_t seed;
|
||||
{
|
||||
std::lock_guard const lk(m);
|
||||
std::lock_guard lk(m);
|
||||
std::uniform_int_distribution<std::uint64_t> distribution{1};
|
||||
seed = distribution(seeder);
|
||||
}
|
||||
|
||||
@@ -23,15 +23,15 @@ private:
|
||||
|
||||
std::recursive_mutex m_mutex;
|
||||
std::condition_variable_any m_cond;
|
||||
std::size_t m_count{1};
|
||||
std::size_t m_count;
|
||||
duration const m_period;
|
||||
boost::asio::io_context& m_ios;
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
|
||||
bool m_cancel{false};
|
||||
bool m_cancel;
|
||||
|
||||
public:
|
||||
io_latency_probe(duration const& period, boost::asio::io_context& ios)
|
||||
: m_period(period), m_ios(ios), m_timer(m_ios)
|
||||
: m_count(1), m_period(period), m_ios(ios), m_timer(m_ios), m_cancel(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
void
|
||||
sample_one(Handler&& handler)
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
boost::asio::post(
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
void
|
||||
sample(Handler&& handler)
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
boost::asio::post(
|
||||
@@ -122,14 +122,14 @@ private:
|
||||
void
|
||||
addref()
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::lock_guard lock(m_mutex);
|
||||
++m_count;
|
||||
}
|
||||
|
||||
void
|
||||
release()
|
||||
{
|
||||
std::lock_guard const lock(m_mutex);
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (--m_count == 0)
|
||||
m_cond.notify_all();
|
||||
}
|
||||
@@ -192,7 +192,7 @@ private:
|
||||
m_handler(elapsed);
|
||||
|
||||
{
|
||||
std::lock_guard const lock(m_probe->m_mutex);
|
||||
std::lock_guard lock(m_probe->m_mutex);
|
||||
if (m_probe->m_cancel)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -16,4 +16,4 @@ template <
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_map = detail::aged_ordered_container<false, true, Key, T, Clock, Compare, Allocator>;
|
||||
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
@@ -16,4 +16,4 @@ template <
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_multimap = detail::aged_ordered_container<true, true, Key, T, Clock, Compare, Allocator>;
|
||||
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ template <
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_multiset =
|
||||
detail::aged_ordered_container<true, false, Key, void, Clock, Compare, Allocator>;
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ template <
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_set = detail::aged_ordered_container<false, false, Key, void, Clock, Compare, Allocator>;
|
||||
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ template <
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_unordered_map =
|
||||
detail::aged_unordered_container<false, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ template <
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_unordered_multimap =
|
||||
detail::aged_unordered_container<true, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ template <
|
||||
using aged_unordered_multiset =
|
||||
detail::aged_unordered_container<true, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
@@ -16,4 +16,4 @@ template <
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_unordered_set =
|
||||
detail::aged_unordered_container<false, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
@@ -262,9 +262,7 @@ private:
|
||||
{
|
||||
}
|
||||
|
||||
config_t(
|
||||
config_t&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
Allocator const& alloc)
|
||||
config_t(config_t&& other, Allocator const& alloc)
|
||||
: KeyValueCompare(std::move(other.key_compare()))
|
||||
, beast::detail::empty_base_optimization<ElementAllocator>(alloc)
|
||||
, clock(other.clock)
|
||||
@@ -554,10 +552,7 @@ public:
|
||||
|
||||
aged_ordered_container(aged_ordered_container&& other);
|
||||
|
||||
aged_ordered_container(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
aged_ordered_container&& other,
|
||||
Allocator const& alloc);
|
||||
aged_ordered_container(aged_ordered_container&& other, Allocator const& alloc);
|
||||
|
||||
aged_ordered_container(std::initializer_list<value_type> init, clock_type& clock);
|
||||
|
||||
@@ -1295,7 +1290,7 @@ aged_ordered_container<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::aged_
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
|
||||
aged_ordered_container<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::aged_ordered_container(
|
||||
aged_ordered_container&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
aged_ordered_container&& other,
|
||||
Allocator const& alloc)
|
||||
: m_config(std::move(other.m_config), alloc)
|
||||
#if BOOST_VERSION >= 108000
|
||||
|
||||
@@ -318,9 +318,7 @@ private:
|
||||
{
|
||||
}
|
||||
|
||||
config_t(
|
||||
config_t&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
Allocator const& alloc)
|
||||
config_t(config_t&& other, Allocator const& alloc)
|
||||
: ValueHash(std::move(other.hash_function()))
|
||||
, KeyValueEqual(std::move(other.key_eq()))
|
||||
, beast::detail::empty_base_optimization<ElementAllocator>(alloc)
|
||||
@@ -776,10 +774,7 @@ public:
|
||||
|
||||
aged_unordered_container(aged_unordered_container&& other);
|
||||
|
||||
aged_unordered_container(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
aged_unordered_container&& other,
|
||||
Allocator const& alloc);
|
||||
aged_unordered_container(aged_unordered_container&& other, Allocator const& alloc);
|
||||
|
||||
aged_unordered_container(std::initializer_list<value_type> init, clock_type& clock);
|
||||
|
||||
@@ -1843,10 +1838,7 @@ template <
|
||||
class KeyEqual,
|
||||
class Allocator>
|
||||
aged_unordered_container<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::
|
||||
aged_unordered_container(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
aged_unordered_container&& other,
|
||||
Allocator const& alloc)
|
||||
aged_unordered_container(aged_unordered_container&& other, Allocator const& alloc)
|
||||
: m_config(std::move(other.m_config), alloc)
|
||||
, m_buck(alloc)
|
||||
, m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
|
||||
|
||||
@@ -449,7 +449,7 @@ public:
|
||||
iterator
|
||||
erase(iterator pos) noexcept
|
||||
{
|
||||
Node const* node = &*pos;
|
||||
Node* node = &*pos;
|
||||
++pos;
|
||||
node->m_next->m_prev = node->m_prev;
|
||||
node->m_prev->m_next = node->m_next;
|
||||
|
||||
@@ -187,7 +187,7 @@ public:
|
||||
bool
|
||||
push_front(Node* node)
|
||||
{
|
||||
bool first = false;
|
||||
bool first;
|
||||
Node* old_head = m_head.load(std::memory_order_relaxed);
|
||||
do
|
||||
{
|
||||
@@ -211,7 +211,7 @@ public:
|
||||
pop_front()
|
||||
{
|
||||
Node* node = m_head.load();
|
||||
Node* new_head = nullptr;
|
||||
Node* new_head;
|
||||
do
|
||||
{
|
||||
if (node == &m_end)
|
||||
|
||||
@@ -23,7 +23,7 @@ private:
|
||||
// A 64-byte buffer should to be big enough for us
|
||||
static constexpr std::size_t INTERNAL_BUFFER_SIZE = 64;
|
||||
|
||||
alignas(64) std::array<std::uint8_t, INTERNAL_BUFFER_SIZE> buffer_{};
|
||||
alignas(64) std::array<std::uint8_t, INTERNAL_BUFFER_SIZE> buffer_;
|
||||
std::span<std::uint8_t> readBuffer_;
|
||||
std::span<std::uint8_t> writeBuffer_;
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ enable_yield_to::spawn(F0&& f, FN&&... fn)
|
||||
boost::context::fixedsize_stack(2 * 1024 * 1024),
|
||||
[&](yield_context yield) {
|
||||
f(yield);
|
||||
std::lock_guard const lock{m_};
|
||||
std::lock_guard lock{m_};
|
||||
if (--running_ == 0)
|
||||
cv_.notify_all();
|
||||
},
|
||||
|
||||
@@ -35,10 +35,10 @@ private:
|
||||
class tests_t : public detail::const_container<std::vector<test>>
|
||||
{
|
||||
private:
|
||||
std::size_t failed_{0};
|
||||
std::size_t failed_;
|
||||
|
||||
public:
|
||||
tests_t()
|
||||
tests_t() : failed_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -167,12 +167,12 @@ public:
|
||||
class results : public detail::const_container<std::vector<suite_results>>
|
||||
{
|
||||
private:
|
||||
std::size_t m_cases{0};
|
||||
std::size_t total_{0};
|
||||
std::size_t failed_{0};
|
||||
std::size_t m_cases;
|
||||
std::size_t total_;
|
||||
std::size_t failed_;
|
||||
|
||||
public:
|
||||
results()
|
||||
results() : m_cases(0), total_(0), failed_(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ template <class>
|
||||
void
|
||||
runner::testcase(std::string const& name)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
// Name may not be empty
|
||||
BOOST_ASSERT(default_ || !name.empty());
|
||||
// Forgot to call pass or fail
|
||||
@@ -244,7 +244,7 @@ template <class>
|
||||
void
|
||||
runner::pass()
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
if (default_)
|
||||
testcase("");
|
||||
on_pass();
|
||||
@@ -255,7 +255,7 @@ template <class>
|
||||
void
|
||||
runner::fail(std::string const& reason)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
if (default_)
|
||||
testcase("");
|
||||
on_fail(reason);
|
||||
@@ -267,7 +267,7 @@ template <class>
|
||||
void
|
||||
runner::log(std::string const& s)
|
||||
{
|
||||
std::lock_guard const lock(mutex_);
|
||||
std::lock_guard lock(mutex_);
|
||||
if (default_)
|
||||
testcase("");
|
||||
on_log(s);
|
||||
|
||||
@@ -300,7 +300,7 @@ private:
|
||||
static suite**
|
||||
p_this_suite()
|
||||
{
|
||||
static suite* pts = nullptr; // NOLINT(misc-const-correctness)
|
||||
static suite* pts = nullptr;
|
||||
return &pts;
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ private:
|
||||
std::string const m_name;
|
||||
std::recursive_mutex lock_;
|
||||
Item item_;
|
||||
Source* parent_{nullptr};
|
||||
Source* parent_;
|
||||
List<Item> children_;
|
||||
|
||||
public:
|
||||
|
||||
@@ -28,7 +28,7 @@ struct Zero
|
||||
|
||||
namespace {
|
||||
static constexpr Zero zero{};
|
||||
} // namespace
|
||||
}
|
||||
|
||||
/** Default implementation of signum calls the method on the class. */
|
||||
template <typename T>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#define ALWAYS_OR_UNREACHABLE(cond, message) assert((message) && (cond))
|
||||
#define SOMETIMES(cond, message, ...)
|
||||
#define REACHABLE(message, ...)
|
||||
#define UNREACHABLE(message, ...) assert((message) && false) // NOLINT(misc-static-assert)
|
||||
#define UNREACHABLE(message, ...) assert((message) && false)
|
||||
#endif
|
||||
|
||||
#define XRPL_ASSERT ALWAYS_OR_UNREACHABLE
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
result_type s_[2]{};
|
||||
result_type s_[2];
|
||||
|
||||
static result_type
|
||||
murmurhash3(result_type x);
|
||||
|
||||
@@ -56,7 +56,7 @@ private:
|
||||
// a lock. This removes a small timing window that occurs if the
|
||||
// waiting thread is handling a spurious wakeup when closureCount_
|
||||
// drops to zero.
|
||||
std::lock_guard const lock{mutex_};
|
||||
std::lock_guard lock{mutex_};
|
||||
|
||||
// Update closureCount_. Notify if stopping and closureCount_ == 0.
|
||||
if ((--closureCount_ == 0) && waitForClosures_)
|
||||
@@ -92,9 +92,7 @@ private:
|
||||
++counter_;
|
||||
}
|
||||
|
||||
Substitute(
|
||||
ClosureCounter& counter,
|
||||
Closure&& closure) // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
Substitute(ClosureCounter& counter, Closure&& closure)
|
||||
: counter_(counter), closure_(std::forward<Closure>(closure))
|
||||
{
|
||||
++counter_;
|
||||
@@ -170,7 +168,7 @@ public:
|
||||
{
|
||||
std::optional<Substitute<Closure>> ret;
|
||||
|
||||
std::lock_guard const lock{mutex_};
|
||||
std::lock_guard lock{mutex_};
|
||||
if (!waitForClosures_)
|
||||
ret.emplace(*this, std::forward<Closure>(closure));
|
||||
|
||||
@@ -193,7 +191,7 @@ public:
|
||||
bool
|
||||
joined() const
|
||||
{
|
||||
std::lock_guard const lock{mutex_};
|
||||
std::lock_guard lock{mutex_};
|
||||
return waitForClosures_;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ JobQueue::Coro::Coro(Coro_create_t, JobQueue& jq, JobType type, std::string cons
|
||||
: jq_(jq)
|
||||
, type_(type)
|
||||
, name_(name)
|
||||
, running_(false)
|
||||
, coro_(
|
||||
// Stack size of 1MB wasn't sufficient for deep calls. ASAN tests flagged the issue. Hence
|
||||
// increasing the size to 1.5MB.
|
||||
@@ -69,24 +70,14 @@ JobQueue::Coro::resume()
|
||||
running_ = true;
|
||||
}
|
||||
{
|
||||
std::lock_guard lk(jq_.m_mutex);
|
||||
std::lock_guard lock(jq_.m_mutex);
|
||||
--jq_.nSuspend_;
|
||||
}
|
||||
auto saved = detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(&lvs_);
|
||||
std::lock_guard lock(mutex_);
|
||||
// A late resume() can arrive after the coroutine has already completed.
|
||||
// This is an expected (if rare) outcome of the race condition documented
|
||||
// in JobQueue.h:354-377 where post() schedules a resume job before the
|
||||
// coroutine yields — the mutex serializes access, but by the time this
|
||||
// resume() acquires the lock the coroutine may have already run to
|
||||
// completion. Calling operator() on a completed boost::coroutine2 is
|
||||
// undefined behavior, so we must check and skip invoking the coroutine
|
||||
// body if it has already completed.
|
||||
if (coro_)
|
||||
{
|
||||
coro_();
|
||||
}
|
||||
XRPL_ASSERT(static_cast<bool>(coro_), "xrpl::JobQueue::Coro::resume : is runnable");
|
||||
coro_();
|
||||
detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(saved);
|
||||
std::lock_guard lk(mutex_run_);
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace xrpl {
|
||||
|
||||
namespace perf {
|
||||
class PerfLog;
|
||||
} // namespace perf
|
||||
}
|
||||
|
||||
class Logs;
|
||||
struct Coro_create_t
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
JobQueue& jq_;
|
||||
JobType type_;
|
||||
std::string name_;
|
||||
bool running_{false};
|
||||
bool running_;
|
||||
std::mutex mutex_;
|
||||
std::mutex mutex_run_;
|
||||
std::condition_variable cv_;
|
||||
@@ -99,8 +99,8 @@ public:
|
||||
Effects:
|
||||
The coroutine continues execution from where it last left off
|
||||
using this same thread.
|
||||
If the coroutine has already completed, returns immediately
|
||||
(handles the documented post-before-yield race condition).
|
||||
Undefined behavior if called after the coroutine has completed
|
||||
with a return (as opposed to a yield()).
|
||||
Undefined behavior if resume() or post() called consecutively
|
||||
without a corresponding yield.
|
||||
*/
|
||||
@@ -224,7 +224,7 @@ private:
|
||||
|
||||
beast::Journal m_journal;
|
||||
mutable std::mutex m_mutex;
|
||||
std::uint64_t m_lastJob{0};
|
||||
std::uint64_t m_lastJob;
|
||||
std::set<Job> m_jobSet;
|
||||
JobCounter jobCounter_;
|
||||
std::atomic_bool stopping_{false};
|
||||
@@ -233,7 +233,7 @@ private:
|
||||
JobTypeData m_invalidJobData;
|
||||
|
||||
// The number of jobs currently in processTask()
|
||||
int m_processCount{0};
|
||||
int m_processCount;
|
||||
|
||||
// The number of suspended coroutines
|
||||
int nSuspend_ = 0;
|
||||
@@ -316,7 +316,7 @@ private:
|
||||
// Returns the limit of running jobs for the given job type.
|
||||
// For jobs with no limit, we return the largest int. Hopefully that
|
||||
// will be enough.
|
||||
static int
|
||||
int
|
||||
getJobLimit(JobType type);
|
||||
};
|
||||
|
||||
@@ -357,10 +357,8 @@ private:
|
||||
If the post() job were to be executed before yield(), undefined behavior
|
||||
would occur. The lock ensures that coro_ is not called again until we exit
|
||||
the coroutine. At which point a scheduled resume() job waiting on the lock
|
||||
would gain entry. resume() checks if the coroutine has already completed
|
||||
(coro_ converts to false) and, if so, skips invoking operator() since
|
||||
calling operator() on a completed boost::coroutine2 pull_type is undefined
|
||||
behavior.
|
||||
would gain entry, harmlessly call coro_ and immediately return as we have
|
||||
already completed the coroutine.
|
||||
|
||||
The race condition occurs as follows:
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@ public:
|
||||
JobTypeInfo const& info;
|
||||
|
||||
/* The number of jobs waiting */
|
||||
int waiting{0};
|
||||
int waiting;
|
||||
|
||||
/* The number presently running */
|
||||
int running{0};
|
||||
int running;
|
||||
|
||||
/* And the number we deferred executing because of job limits */
|
||||
int deferred{0};
|
||||
int deferred;
|
||||
|
||||
/* Notification callbacks */
|
||||
beast::insight::Event dequeue;
|
||||
@@ -35,8 +35,12 @@ public:
|
||||
JobTypeInfo const& info_,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
Logs& logs) noexcept
|
||||
: m_load(logs.journal("LoadMonitor")), m_collector(collector), info(info_)
|
||||
|
||||
: m_load(logs.journal("LoadMonitor"))
|
||||
, m_collector(collector)
|
||||
, info(info_)
|
||||
, waiting(0)
|
||||
, running(0)
|
||||
, deferred(0)
|
||||
{
|
||||
m_load.setTargetLatency(info.getAverageLatency(), info.getPeakLatency());
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ private:
|
||||
std::chrono::milliseconds{0})
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
int const maxLimit = std::numeric_limits<int>::max();
|
||||
int maxLimit = std::numeric_limits<int>::max();
|
||||
|
||||
auto add = [this](
|
||||
JobType jt,
|
||||
|
||||
@@ -36,10 +36,10 @@ public:
|
||||
{
|
||||
Stats();
|
||||
|
||||
std::uint64_t count{0};
|
||||
std::uint64_t count;
|
||||
std::chrono::milliseconds latencyAvg;
|
||||
std::chrono::milliseconds latencyPeak;
|
||||
bool isOverloaded{false};
|
||||
bool isOverloaded;
|
||||
};
|
||||
|
||||
Stats
|
||||
@@ -54,8 +54,8 @@ private:
|
||||
|
||||
std::mutex mutex_;
|
||||
|
||||
std::uint64_t mCounts{0};
|
||||
int mLatencyEvents{0};
|
||||
std::uint64_t mCounts;
|
||||
int mLatencyEvents;
|
||||
std::chrono::milliseconds mLatencyMSAvg;
|
||||
std::chrono::milliseconds mLatencyMSPeak;
|
||||
std::chrono::milliseconds mTargetLatencyAvg;
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
bool
|
||||
contains(PublicKey const& nodeId)
|
||||
{
|
||||
std::lock_guard const lock(this->mutex_);
|
||||
std::lock_guard lock(this->mutex_);
|
||||
return table_.find({nodeId}) != table_.end();
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
private:
|
||||
beast::Journal mutable journal_;
|
||||
std::mutex mutable mutex_;
|
||||
DatabaseCon* connection_{};
|
||||
DatabaseCon* connection_;
|
||||
std::unordered_set<PeerReservation, beast::uhash<>, KeyEqual> table_;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace beast {
|
||||
class Journal;
|
||||
} // namespace beast
|
||||
}
|
||||
|
||||
namespace xrpl {
|
||||
class Application;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/SHAMapHash.h>
|
||||
#include <xrpl/basics/TaggedCache.h>
|
||||
#include <xrpl/ledger/CachedSLEs.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
@@ -11,31 +12,17 @@ namespace xrpl {
|
||||
// Forward declarations
|
||||
namespace NodeStore {
|
||||
class Database;
|
||||
} // namespace NodeStore
|
||||
}
|
||||
namespace Resource {
|
||||
class Manager;
|
||||
} // namespace Resource
|
||||
}
|
||||
namespace perf {
|
||||
class PerfLog;
|
||||
} // namespace perf
|
||||
}
|
||||
|
||||
// This is temporary until we migrate all code to use ServiceRegistry.
|
||||
class Application;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
bool IsKeyCache,
|
||||
class SharedWeakUnionPointer,
|
||||
class SharedPointerType,
|
||||
class Hash,
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
class TaggedCache;
|
||||
class STLedgerEntry;
|
||||
using SLE = STLedgerEntry;
|
||||
using CachedSLEs = TaggedCache<uint256, SLE const>;
|
||||
|
||||
// Forward declarations
|
||||
class AcceptedLedger;
|
||||
class AmendmentTable;
|
||||
@@ -58,7 +45,7 @@ class NetworkIDService;
|
||||
class OpenLedger;
|
||||
class OrderBookDB;
|
||||
class Overlay;
|
||||
class PathRequestManager;
|
||||
class PathRequests;
|
||||
class PeerReservationTable;
|
||||
class PendingSaves;
|
||||
class RelationalDatabase;
|
||||
@@ -102,7 +89,7 @@ public:
|
||||
getNodeFamily() = 0;
|
||||
|
||||
virtual TimeKeeper&
|
||||
getTimeKeeper() = 0;
|
||||
timeKeeper() = 0;
|
||||
|
||||
virtual JobQueue&
|
||||
getJobQueue() = 0;
|
||||
@@ -111,7 +98,7 @@ public:
|
||||
getTempNodeCache() = 0;
|
||||
|
||||
virtual CachedSLEs&
|
||||
getCachedSLEs() = 0;
|
||||
cachedSLEs() = 0;
|
||||
|
||||
virtual NetworkIDService&
|
||||
getNetworkIDService() = 0;
|
||||
@@ -133,26 +120,26 @@ public:
|
||||
getValidations() = 0;
|
||||
|
||||
virtual ValidatorList&
|
||||
getValidators() = 0;
|
||||
validators() = 0;
|
||||
|
||||
virtual ValidatorSite&
|
||||
getValidatorSites() = 0;
|
||||
validatorSites() = 0;
|
||||
|
||||
virtual ManifestCache&
|
||||
getValidatorManifests() = 0;
|
||||
validatorManifests() = 0;
|
||||
|
||||
virtual ManifestCache&
|
||||
getPublisherManifests() = 0;
|
||||
publisherManifests() = 0;
|
||||
|
||||
// Network services
|
||||
virtual Overlay&
|
||||
getOverlay() = 0;
|
||||
overlay() = 0;
|
||||
|
||||
virtual Cluster&
|
||||
getCluster() = 0;
|
||||
cluster() = 0;
|
||||
|
||||
virtual PeerReservationTable&
|
||||
getPeerReservations() = 0;
|
||||
peerReservations() = 0;
|
||||
|
||||
virtual Resource::Manager&
|
||||
getResourceManager() = 0;
|
||||
@@ -187,13 +174,13 @@ public:
|
||||
getLedgerReplayer() = 0;
|
||||
|
||||
virtual PendingSaves&
|
||||
getPendingSaves() = 0;
|
||||
pendingSaves() = 0;
|
||||
|
||||
virtual OpenLedger&
|
||||
getOpenLedger() = 0;
|
||||
openLedger() = 0;
|
||||
|
||||
virtual OpenLedger const&
|
||||
getOpenLedger() const = 0;
|
||||
openLedger() const = 0;
|
||||
|
||||
// Transaction and operation services
|
||||
virtual NetworkOPs&
|
||||
@@ -208,8 +195,8 @@ public:
|
||||
virtual TxQ&
|
||||
getTxQ() = 0;
|
||||
|
||||
virtual PathRequestManager&
|
||||
getPathRequestManager() = 0;
|
||||
virtual PathRequests&
|
||||
getPathRequests() = 0;
|
||||
|
||||
// Server services
|
||||
virtual ServerHandler&
|
||||
@@ -223,16 +210,16 @@ public:
|
||||
isStopping() const = 0;
|
||||
|
||||
virtual beast::Journal
|
||||
getJournal(std::string const& name) = 0;
|
||||
journal(std::string const& name) = 0;
|
||||
|
||||
virtual boost::asio::io_context&
|
||||
getIOContext() = 0;
|
||||
|
||||
virtual Logs&
|
||||
getLogs() = 0;
|
||||
logs() = 0;
|
||||
|
||||
virtual std::optional<uint256> const&
|
||||
getTrapTxID() const = 0;
|
||||
trapTxID() const = 0;
|
||||
|
||||
/** Retrieve the "wallet database" */
|
||||
virtual DatabaseCon&
|
||||
@@ -241,7 +228,7 @@ public:
|
||||
// Temporary: Get the underlying Application for functions that haven't
|
||||
// been migrated yet. This should be removed once all code is migrated.
|
||||
virtual Application&
|
||||
getApp() = 0;
|
||||
app() = 0;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
enum class StartUpType { Fresh, Normal, Load, LoadFile, Replay, Network };
|
||||
enum class StartUpType { FRESH, NORMAL, LOAD, LOAD_FILE, REPLAY, NETWORK };
|
||||
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& os, StartUpType const& type)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace xrpl {
|
||||
|
||||
namespace perf {
|
||||
class PerfLog;
|
||||
} // namespace perf
|
||||
}
|
||||
|
||||
/**
|
||||
* `Workers` is effectively a thread pool. The constructor takes a "callback"
|
||||
@@ -183,8 +183,8 @@ private:
|
||||
std::thread thread_;
|
||||
std::mutex mutex_;
|
||||
std::condition_variable wakeup_;
|
||||
int wakeCount_{0}; // how many times to un-pause
|
||||
bool shouldExit_{false};
|
||||
int wakeCount_; // how many times to un-pause
|
||||
bool shouldExit_;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -197,9 +197,9 @@ private:
|
||||
std::string m_threadNames; // The name to give each thread
|
||||
std::condition_variable m_cv; // signaled when all threads paused
|
||||
std::mutex m_mut;
|
||||
bool m_allPaused{true};
|
||||
bool m_allPaused;
|
||||
semaphore m_semaphore; // each pending task is 1 resource
|
||||
int m_numberOfThreads{0}; // how many we want active now
|
||||
int m_numberOfThreads; // how many we want active now
|
||||
std::atomic<int> m_activeCount; // to know when all are paused
|
||||
std::atomic<int> m_pauseCount; // how many threads need to pause now
|
||||
std::atomic<int> m_runningTaskCount; // how many calls to processTask() active
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
void
|
||||
notify()
|
||||
{
|
||||
std::lock_guard const lock{m_mutex};
|
||||
std::lock_guard lock{m_mutex};
|
||||
++m_count;
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
@@ -103,9 +103,9 @@ private:
|
||||
public:
|
||||
explicit ErrorInfo() = default;
|
||||
|
||||
Token token_{};
|
||||
Token token_;
|
||||
std::string message_;
|
||||
Location extra_{};
|
||||
Location extra_;
|
||||
};
|
||||
|
||||
using Errors = std::deque<ErrorInfo>;
|
||||
@@ -173,11 +173,11 @@ private:
|
||||
Nodes nodes_;
|
||||
Errors errors_;
|
||||
std::string document_;
|
||||
Location begin_{};
|
||||
Location end_{};
|
||||
Location current_{};
|
||||
Location lastValueEnd_{};
|
||||
Value* lastValue_{};
|
||||
Location begin_;
|
||||
Location end_;
|
||||
Location current_;
|
||||
Location lastValueEnd_;
|
||||
Value* lastValue_;
|
||||
};
|
||||
|
||||
template <class BufferSequence>
|
||||
|
||||
@@ -641,7 +641,7 @@ public:
|
||||
SelfType
|
||||
operator++(int)
|
||||
{
|
||||
SelfType const temp(*this);
|
||||
SelfType temp(*this);
|
||||
++*this;
|
||||
return temp;
|
||||
}
|
||||
@@ -649,7 +649,7 @@ public:
|
||||
SelfType
|
||||
operator--(int)
|
||||
{
|
||||
SelfType const temp(*this);
|
||||
SelfType temp(*this);
|
||||
--*this;
|
||||
return temp;
|
||||
}
|
||||
|
||||
@@ -106,8 +106,8 @@ private:
|
||||
ChildValues childValues_;
|
||||
std::string document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_{74};
|
||||
int indentSize_{3};
|
||||
int rightMargin_;
|
||||
int indentSize_;
|
||||
bool addChildValues_{};
|
||||
};
|
||||
|
||||
@@ -171,9 +171,9 @@ private:
|
||||
using ChildValues = std::vector<std::string>;
|
||||
|
||||
ChildValues childValues_;
|
||||
std::ostream* document_{nullptr};
|
||||
std::ostream* document_;
|
||||
std::string indentString_;
|
||||
int rightMargin_{74};
|
||||
int rightMargin_;
|
||||
std::string indentation_;
|
||||
bool addChildValues_{};
|
||||
};
|
||||
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
// Inject appropriate pseudo-transactions
|
||||
for (auto const& it : actions)
|
||||
{
|
||||
STTx const amendTx(ttAMENDMENT, [&it, seq = lastClosedLedger->seq() + 1](auto& obj) {
|
||||
STTx amendTx(ttAMENDMENT, [&it, seq = lastClosedLedger->seq() + 1](auto& obj) {
|
||||
obj.setAccountID(sfAccount, AccountID());
|
||||
obj.setFieldH256(sfAmendment, it.first);
|
||||
obj.setFieldU32(sfLedgerSequence, seq);
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
|
||||
namespace xrpl {
|
||||
using CachedSLEs = TaggedCache<uint256, SLE const>;
|
||||
} // namespace xrpl
|
||||
}
|
||||
|
||||
@@ -76,33 +76,16 @@ public:
|
||||
@return true if a book from this issue to XRP exists
|
||||
*/
|
||||
virtual bool
|
||||
isBookToXRP(Issue const& issue, std::optional<Domain> const& domain = std::nullopt) = 0;
|
||||
isBookToXRP(Issue const& issue, std::optional<Domain> domain = std::nullopt) = 0;
|
||||
|
||||
/**
|
||||
* Process a transaction for order book tracking.
|
||||
* @param ledger The ledger the transaction was applied to
|
||||
* @param alTx The transaction to process
|
||||
* @param jvObj The JSON object of the transaction
|
||||
*/
|
||||
virtual void
|
||||
processTxn(
|
||||
std::shared_ptr<ReadView const> const& ledger,
|
||||
AcceptedLedgerTx const& alTx,
|
||||
MultiApiJson const& jvObj) = 0;
|
||||
|
||||
/**
|
||||
* Get the book listeners for a book.
|
||||
* @param book The book to get the listeners for
|
||||
* @return The book listeners for the book
|
||||
*/
|
||||
virtual BookListeners::pointer
|
||||
getBookListeners(Book const&) = 0;
|
||||
|
||||
/**
|
||||
* Create a new book listeners for a book.
|
||||
* @param book The book to create the listeners for
|
||||
* @return The new book listeners for the book
|
||||
*/
|
||||
virtual BookListeners::pointer
|
||||
makeBookListeners(Book const&) = 0;
|
||||
};
|
||||
|
||||
@@ -2,19 +2,28 @@
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/OfferHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/VaultHelpers.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/Rate.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -157,7 +166,7 @@ canWithdraw(
|
||||
ReadView const& view,
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
SLE::const_ref toSle,
|
||||
AccountRoot const& toWrapped,
|
||||
STAmount const& amount,
|
||||
bool hasDestinationTag);
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Rate.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
@@ -15,40 +17,110 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/** Check if the issuer has the global freeze flag set.
|
||||
@param issuer The account to check
|
||||
@return true if the account has global freeze set
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isGlobalFrozen(ReadView const& view, AccountID const& issuer);
|
||||
|
||||
// Calculate liquid XRP balance for an account.
|
||||
// This function may be used to calculate the amount of XRP that
|
||||
// the holder is able to freely spend. It subtracts reserve requirements.
|
||||
//
|
||||
// ownerCountAdj adjusts the owner count in case the caller calculates
|
||||
// before ledger entries are added or removed. Positive to add, negative
|
||||
// to subtract.
|
||||
//
|
||||
// @param ownerCountAdj positive to add to count, negative to reduce count.
|
||||
[[nodiscard]] XRPAmount
|
||||
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
|
||||
|
||||
/** Adjust the owner count up or down. */
|
||||
void
|
||||
adjustOwnerCount(
|
||||
ApplyView& view,
|
||||
std::shared_ptr<SLE> const& sle,
|
||||
std::int32_t amount,
|
||||
beast::Journal j);
|
||||
|
||||
/** Returns IOU issuer transfer fee as Rate. Rate specifies
|
||||
* the fee as fractions of 1 billion. For example, 1% transfer rate
|
||||
* is represented as 1,010,000,000.
|
||||
* @param issuer The IOU issuer
|
||||
/**
|
||||
* Read-only wrapper for AccountRoot ledger entries.
|
||||
*
|
||||
* Provides read-only access to account data.
|
||||
*/
|
||||
[[nodiscard]] Rate
|
||||
transferRate(ReadView const& view, AccountID const& issuer);
|
||||
class AccountRoot : public ReadOnlySLE
|
||||
{
|
||||
protected:
|
||||
AccountID const id_;
|
||||
|
||||
public:
|
||||
AccountRoot(AccountID const& id, ReadView const& view)
|
||||
: ReadOnlySLE(view.read(keylet::account(id)), view), id_(id)
|
||||
{
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
id() const
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
/** Check if the issuer has the global freeze flag set.
|
||||
@return true if the account has global freeze set
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isGlobalFrozen() const;
|
||||
|
||||
/** Returns IOU issuer transfer fee as Rate. Rate specifies
|
||||
* the fee as fractions of 1 billion. For example, 1% transfer rate
|
||||
* is represented as 1,010,000,000.
|
||||
*/
|
||||
[[nodiscard]] Rate
|
||||
transferRate() const;
|
||||
|
||||
// Calculate liquid XRP balance for an account.
|
||||
// This function may be used to calculate the amount of XRP that
|
||||
// the holder is able to freely spend. It subtracts reserve requirements.
|
||||
//
|
||||
// ownerCountAdj adjusts the owner count in case the caller calculates
|
||||
// before ledger entries are added or removed. Positive to add, negative
|
||||
// to subtract.
|
||||
//
|
||||
// @param ownerCountAdj positive to add to count, negative to reduce count.
|
||||
[[nodiscard]] XRPAmount
|
||||
xrpLiquid(std::int32_t ownerCountAdj, beast::Journal j) const;
|
||||
|
||||
/** Checks the destination and tag.
|
||||
|
||||
- Checks that the SLE is not null.
|
||||
- If the SLE requires a destination tag, checks that there is a tag.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkDestinationAndTag(bool hasDestinationTag) const;
|
||||
|
||||
/** Returns true if and only if sleAcct is a pseudo-account or specific
|
||||
pseudo-accounts in pseudoFieldFilter.
|
||||
|
||||
Returns false if sleAcct is:
|
||||
- NOT a pseudo-account OR
|
||||
- NOT a ltACCOUNT_ROOT OR
|
||||
- null pointer
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isPseudoAccount(std::set<SField const*> const& pseudoFieldFilter = {}) const;
|
||||
|
||||
[[nodiscard]] bool
|
||||
operator==(AccountRoot const& other) const
|
||||
{
|
||||
return id_ == other.id_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
operator==(AccountID const& other) const
|
||||
{
|
||||
return id_ == other;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Writable wrapper for AccountRoot ledger entries.
|
||||
*
|
||||
* Provides read-write access to account data.
|
||||
* Inherits from AccountRoot to reuse read-only methods,
|
||||
* and adds write capabilities.
|
||||
*/
|
||||
class WritableAccountRoot : public AccountRoot, public WritableSLE
|
||||
{
|
||||
public:
|
||||
WritableAccountRoot(AccountID const& id, ApplyView& view)
|
||||
: AccountRoot(id, view), WritableSLE(keylet::account(id), view)
|
||||
{
|
||||
}
|
||||
|
||||
// Resolve ambiguity: use writable operator-> for non-const, read-only for const
|
||||
using WritableSLE::operator->;
|
||||
using AccountRoot::operator->;
|
||||
using WritableSLE::operator*;
|
||||
using AccountRoot::operator*;
|
||||
|
||||
/** Adjust the owner count up or down. */
|
||||
void
|
||||
adjustOwnerCount(std::int32_t amount, beast::Journal j);
|
||||
};
|
||||
|
||||
/** Generate a pseudo-account address from a pseudo owner key.
|
||||
@param pseudoOwnerKey The key to generate the address from
|
||||
@@ -87,7 +159,10 @@ isPseudoAccount(
|
||||
AccountID const& accountId,
|
||||
std::set<SField const*> const& pseudoFieldFilter = {})
|
||||
{
|
||||
return isPseudoAccount(view.read(keylet::account(accountId)), pseudoFieldFilter);
|
||||
AccountRoot const acct(accountId, view);
|
||||
if (!acct)
|
||||
return false;
|
||||
return acct.isPseudoAccount(pseudoFieldFilter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,12 +176,4 @@ isPseudoAccount(
|
||||
[[nodiscard]] Expected<std::shared_ptr<SLE>, TER>
|
||||
createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField);
|
||||
|
||||
/** Checks the destination and tag.
|
||||
|
||||
- Checks that the SLE is not null.
|
||||
- If the SLE requires a destination tag, checks that there is a tag.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
@@ -73,8 +74,7 @@ verifyDepositPreauth(
|
||||
STTx const& tx,
|
||||
ApplyView& view,
|
||||
AccountID const& src,
|
||||
AccountID const& dst,
|
||||
std::shared_ptr<SLE const> const& sleDst,
|
||||
AccountRoot const& dst,
|
||||
beast::Journal j);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
128
include/xrpl/ledger/helpers/MPToken.h
Normal file
128
include/xrpl/ledger/helpers/MPToken.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHolderBase.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class MPToken : public virtual TokenHolderBase
|
||||
{
|
||||
public:
|
||||
MPToken(MPTokenIssuance const& issuance, AccountID const& holder)
|
||||
: ReadOnlySLE(
|
||||
issuance.readView().read(keylet::mptoken(issuance.getMptID(), holder)),
|
||||
issuance.readView())
|
||||
, TokenHolderBase(
|
||||
issuance.readView(),
|
||||
issuance.readView().read(keylet::mptoken(issuance.getMptID(), holder)),
|
||||
issuance,
|
||||
holder)
|
||||
, issuance_(issuance)
|
||||
{
|
||||
}
|
||||
|
||||
MPTokenIssuance const&
|
||||
getIssuance() const
|
||||
{
|
||||
return issuance_;
|
||||
}
|
||||
|
||||
MPTIssue
|
||||
getMptIssue() const
|
||||
{
|
||||
return issuance_.getMptIssue();
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkSpendable(
|
||||
STAmount const& amount,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
AuthHandling zeroIfUnauthorized,
|
||||
beast::Journal j) const override
|
||||
{
|
||||
STAmount const spendableAmount = accountHolds(zeroIfFrozen, zeroIfUnauthorized, j);
|
||||
|
||||
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount <= beast::zero)
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
// If the spendable amount is less than the amount, return tecINSUFFICIENT_FUNDS
|
||||
if (!canSubtract(spendableAmount, amount))
|
||||
return tecINSUFFICIENT_FUNDS;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
protected:
|
||||
MPTokenIssuance const& issuance_;
|
||||
};
|
||||
|
||||
class WritableMPToken : public virtual WritableTokenHolderBase, public virtual MPToken
|
||||
{
|
||||
public:
|
||||
WritableMPToken(WritableMPTokenIssuance& issuance, AccountID const& holder)
|
||||
: ReadOnlySLE(
|
||||
issuance.applyView().peek(keylet::mptoken(issuance.getMptID(), holder)),
|
||||
issuance.applyView())
|
||||
, TokenHolderBase(
|
||||
issuance.applyView(),
|
||||
issuance.applyView().peek(keylet::mptoken(issuance.getMptID(), holder)),
|
||||
issuance,
|
||||
holder)
|
||||
, WritableSLE(
|
||||
issuance.applyView().peek(keylet::mptoken(issuance.getMptID(), holder)),
|
||||
issuance.applyView())
|
||||
, WritableTokenHolderBase(
|
||||
issuance.applyView(),
|
||||
issuance.applyView().peek(keylet::mptoken(issuance.getMptID(), holder)),
|
||||
issuance,
|
||||
holder)
|
||||
, MPToken(issuance, holder)
|
||||
, writableIssuance_(issuance)
|
||||
{
|
||||
}
|
||||
|
||||
// Resolve ambiguity: use writable operator-> for non-const, read-only for const
|
||||
using WritableSLE::operator->;
|
||||
using MPToken::operator->;
|
||||
using WritableSLE::operator*;
|
||||
using MPToken::operator*;
|
||||
|
||||
WritableMPTokenIssuance&
|
||||
getWritableIssuance()
|
||||
{
|
||||
return writableIssuance_;
|
||||
}
|
||||
|
||||
static TER
|
||||
createMPToken(
|
||||
WritableMPTokenIssuance& issuance,
|
||||
AccountID const& account,
|
||||
std::uint32_t const flags)
|
||||
{
|
||||
WritableMPToken mptoken(issuance, account);
|
||||
|
||||
auto const ownerNode = mptoken.applyView().dirInsert(
|
||||
keylet::ownerDir(account), mptoken.key(), describeOwnerDir(account));
|
||||
|
||||
if (!ownerNode)
|
||||
return tecDIR_FULL; // LCOV_EXCL_LINE
|
||||
|
||||
mptoken.newSLE();
|
||||
|
||||
(*mptoken)[sfAccount] = account;
|
||||
(*mptoken)[sfMPTokenIssuanceID] = issuance.getMptID();
|
||||
(*mptoken)[sfFlags] = flags;
|
||||
(*mptoken)[sfOwnerNode] = *ownerNode;
|
||||
|
||||
mptoken.insert();
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
protected:
|
||||
WritableMPTokenIssuance& writableIssuance_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -14,126 +14,241 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Freeze checking (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
class MPTokenIssuance : public virtual TokenBase
|
||||
{
|
||||
public:
|
||||
MPTokenIssuance(ReadView const& view, MPTIssue const& mptIssue)
|
||||
: ReadOnlySLE(view.read(keylet::mptIssuance(mptIssue.getMptID())), view)
|
||||
, TokenBase(view, view.read(keylet::mptIssuance(mptIssue.getMptID())))
|
||||
, mptID_(mptIssue.getMptID())
|
||||
, mptIssue_(mptIssue)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue);
|
||||
MPTokenIssuance(ReadView const& view, MPTID const& mptID)
|
||||
: ReadOnlySLE(view.read(keylet::mptIssuance(mptID)), view)
|
||||
, TokenBase(view, view.read(keylet::mptIssuance(mptID)))
|
||||
, mptID_(mptID)
|
||||
, mptIssue_(MPTIssue(mptID_))
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue);
|
||||
MPTID const&
|
||||
getMptID() const
|
||||
{
|
||||
return mptID_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue, int depth = 0);
|
||||
MPTIssue const&
|
||||
getMptIssue() const
|
||||
{
|
||||
return mptIssue_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isAnyFrozen(
|
||||
ReadView const& view,
|
||||
std::initializer_list<AccountID> const& accounts,
|
||||
MPTIssue const& mptIssue,
|
||||
int depth = 0);
|
||||
AccountID const&
|
||||
getIssuer() const override
|
||||
{
|
||||
return mptIssue_.getIssuer();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Transfer rate (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Freeze checking (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Returns MPT transfer fee as Rate. Rate specifies
|
||||
* the fee as fractions of 1 billion. For example, 1% transfer rate
|
||||
* is represented as 1,010,000,000.
|
||||
* @param issuanceID MPTokenIssuanceID of MPTTokenIssuance object
|
||||
*/
|
||||
[[nodiscard]] Rate
|
||||
transferRate(ReadView const& view, MPTID const& issuanceID);
|
||||
[[nodiscard]] bool
|
||||
isGlobalFrozen() const override;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Holding checks (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
[[nodiscard]] bool
|
||||
isIndividualFrozen(AccountID const& account) const override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
canAddHolding(ReadView const& view, MPTIssue const& mptIssue);
|
||||
[[nodiscard]] bool
|
||||
isFrozen(AccountID const& account, int depth = 0) const override;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Authorization (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
[[nodiscard]] TER
|
||||
checkFrozen(AccountID const& account) const override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
authorizeMPToken(
|
||||
ApplyView& view,
|
||||
XRPAmount const& priorBalance,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
beast::Journal journal,
|
||||
std::uint32_t flags = 0,
|
||||
std::optional<AccountID> holderID = std::nullopt);
|
||||
[[nodiscard]] bool
|
||||
isAnyFrozen(std::initializer_list<AccountID> const& accounts, int depth = 0) const override;
|
||||
|
||||
/** Check if the account lacks required authorization for MPT.
|
||||
*
|
||||
* requireAuth check is recursive for MPT shares in a vault, descending to
|
||||
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
|
||||
* purely defensive, as we currently do not allow such vaults to be created.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
requireAuth(
|
||||
ReadView const& view,
|
||||
MPTIssue const& mptIssue,
|
||||
AccountID const& account,
|
||||
AuthType authType = AuthType::Legacy,
|
||||
int depth = 0);
|
||||
[[nodiscard]] bool
|
||||
isDeepFrozen(AccountID const& account, int depth = 0) const override;
|
||||
|
||||
/** Enforce account has MPToken to match its authorization.
|
||||
*
|
||||
* Called from doApply - it will check for expired (and delete if found any)
|
||||
* credentials matching DomainID set in MPTokenIssuance. Must be called if
|
||||
* requireAuth(...MPTIssue...) returned tesSUCCESS or tecEXPIRED in preclaim.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
enforceMPTokenAuthorization(
|
||||
ApplyView& view,
|
||||
MPTID const& mptIssuanceID,
|
||||
AccountID const& account,
|
||||
XRPAmount const& priorBalance,
|
||||
beast::Journal j);
|
||||
[[nodiscard]] TER
|
||||
checkDeepFrozen(AccountID const& account) const override;
|
||||
|
||||
/** Check if the destination account is allowed
|
||||
* to receive MPT. Return tecNO_AUTH if it doesn't
|
||||
* and tesSUCCESS otherwise.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
canTransfer(
|
||||
ReadView const& view,
|
||||
MPTIssue const& mptIssue,
|
||||
AccountID const& from,
|
||||
AccountID const& to);
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Transfer rate (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Empty holding operations (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
/** Returns MPT transfer fee as Rate. Rate specifies
|
||||
* the fee as fractions of 1 billion. For example, 1% transfer rate
|
||||
* is represented as 1,010,000,000.
|
||||
* @param issuanceID MPTokenIssuanceID of MPTTokenIssuance object
|
||||
*/
|
||||
[[nodiscard]] Rate
|
||||
transferRate() const override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
AccountID const& accountID,
|
||||
XRPAmount priorBalance,
|
||||
MPTIssue const& mptIssue,
|
||||
beast::Journal journal);
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Holding checks (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] TER
|
||||
removeEmptyHolding(
|
||||
ApplyView& view,
|
||||
AccountID const& accountID,
|
||||
MPTIssue const& mptIssue,
|
||||
beast::Journal journal);
|
||||
[[nodiscard]] TER
|
||||
canAddHolding() const override;
|
||||
|
||||
/** Check if the account lacks required authorization for MPT.
|
||||
*
|
||||
* requireAuth check is recursive for MPT shares in a vault, descending to
|
||||
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
|
||||
* purely defensive, as we currently do not allow such vaults to be created.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
requireAuth(AccountID const& account, AuthType authType = AuthType::Legacy, int depth = 0)
|
||||
const override;
|
||||
|
||||
/** Check if the destination account is allowed
|
||||
* to receive MPT. Return tecNO_AUTH if it doesn't
|
||||
* and tesSUCCESS otherwise.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
canTransfer(AccountID const& from, AccountID const& to) const override;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Token capability checks (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] bool
|
||||
canClawback() const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
canEscrow() const override
|
||||
{
|
||||
return sle_->isFlag(lsfMPTCanEscrow);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
requiresAuth() const override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkExists() const override
|
||||
{
|
||||
if (!exists())
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
if (sle_->getAccountID(sfIssuer) != mptIssue_.getIssuer())
|
||||
return tecINTERNAL;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
hasHolder(AccountID const& holder) const override
|
||||
{
|
||||
return readView_.exists(keylet::mptoken(mptID_, holder));
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkHolder(AccountID const& holder) const override
|
||||
{
|
||||
if (!hasHolder(holder))
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<TokenHolderBase>
|
||||
getHolder(AccountID const& holder) const override;
|
||||
|
||||
STAmount
|
||||
accountHolds(
|
||||
AccountID const& account,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const override;
|
||||
|
||||
[[nodiscard]] STAmount
|
||||
accountHolds(
|
||||
AccountID const& account,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
AuthHandling zeroIfUnauthorized,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const override;
|
||||
|
||||
protected:
|
||||
MPTID const mptID_;
|
||||
MPTIssue const mptIssue_;
|
||||
};
|
||||
|
||||
class WritableMPTokenIssuance : public virtual WritableTokenBase, public virtual MPTokenIssuance
|
||||
{
|
||||
public:
|
||||
WritableMPTokenIssuance(ApplyView& view, MPTIssue const& mptIssue)
|
||||
: ReadOnlySLE(view.peek(keylet::mptIssuance(mptIssue.getMptID())), view)
|
||||
, TokenBase(view, view.peek(keylet::mptIssuance(mptIssue.getMptID())))
|
||||
, WritableSLE(view.peek(keylet::mptIssuance(mptIssue.getMptID())), view)
|
||||
, WritableTokenBase(view, view.peek(keylet::mptIssuance(mptIssue.getMptID())))
|
||||
, MPTokenIssuance(view, mptIssue)
|
||||
{
|
||||
}
|
||||
|
||||
WritableMPTokenIssuance(ApplyView& view, MPTID const& mptID)
|
||||
: ReadOnlySLE(view.peek(keylet::mptIssuance(mptID)), view)
|
||||
, TokenBase(view, view.peek(keylet::mptIssuance(mptID)))
|
||||
, WritableSLE(view.peek(keylet::mptIssuance(mptID)), view)
|
||||
, WritableTokenBase(view, view.peek(keylet::mptIssuance(mptID)))
|
||||
, MPTokenIssuance(view, mptID)
|
||||
{
|
||||
}
|
||||
|
||||
// Resolve ambiguity: use writable operator-> for non-const, read-only for const
|
||||
using WritableSLE::operator->;
|
||||
using MPTokenIssuance::operator->;
|
||||
using WritableSLE::operator*;
|
||||
using MPTokenIssuance::operator*;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Authorization (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] TER
|
||||
authorizeMPToken(
|
||||
XRPAmount const& priorBalance,
|
||||
AccountID const& account,
|
||||
beast::Journal journal,
|
||||
std::uint32_t flags = 0,
|
||||
std::optional<AccountID> holderID = std::nullopt);
|
||||
|
||||
/** Enforce account has MPToken to match its authorization.
|
||||
*
|
||||
* Called from doApply - it will check for expired (and delete if found any)
|
||||
* credentials matching DomainID set in MPTokenIssuance. Must be called if
|
||||
* requireAuth(...MPTIssue...) returned tesSUCCESS or tecEXPIRED in preclaim.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
enforceMPTokenAuthorization(
|
||||
AccountID const& account,
|
||||
XRPAmount const& priorBalance,
|
||||
beast::Journal j);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Empty holding operations (MPT-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(AccountID const& accountID, XRPAmount priorBalance, beast::Journal journal)
|
||||
override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
removeEmptyHolding(AccountID const& accountID, beast::Journal journal) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
39
include/xrpl/ledger/helpers/README.md
Normal file
39
include/xrpl/ledger/helpers/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Ledger Entry Helpers (`entries/`)
|
||||
|
||||
## Overview
|
||||
|
||||
This folder contains helper classes and free functions for working with **Serialized Ledger Entries (SLEs)**. Its centerpiece is `SLEBase.h`, which defines two base classes — `ReadOnlySLE` and `WritableSLE` — that provide a type-safe, context-aware wrapper around the raw `std::shared_ptr<SLE>` used throughout the rest of the codebase.
|
||||
|
||||
## The Problem: Untyped SLE Access
|
||||
|
||||
Historically, ledger entries are passed around as bare `std::shared_ptr<SLE>` (or `std::shared_ptr<SLE const>`). This has several drawbacks:
|
||||
|
||||
1. **No compile-time entry-type safety.** Any code holding an `std::shared_ptr<SLE>` can read or write _any_ field on _any_ ledger entry type. Nothing prevents you from calling `sle->getFieldU32(sfOwnerCount)` on an Offer SLE, even though Offers don't have that field.
|
||||
|
||||
2. **No read/write distinction.** A function that only needs to _read_ an entry still receives a mutable `std::shared_ptr<SLE>`, making it easy to accidentally mutate state. Conversely, a function that _must_ write has no way to express that requirement in its signature.
|
||||
|
||||
3. **No association with the view.** The SLE and the `ReadView` / `ApplyView` it came from travel as separate arguments, so callers must manually keep them in sync and remember to call `view.update(sle)` after mutations.
|
||||
|
||||
## The Solution: `SLEBase.h`
|
||||
|
||||
`SLEBase.h` introduces two base classes that pair an SLE with its view context and enforce read/write semantics at compile time.
|
||||
|
||||
**`ReadOnlySLE`** bundles a `std::shared_ptr<SLE const>` with the `ReadView` it was read from. It provides existence checks and const-only access to the underlying entry. Derived classes add domain-specific read-only accessors (e.g. `AccountRoot::isGlobalFrozen()`).
|
||||
|
||||
**`WritableSLE`** bundles a mutable `std::shared_ptr<SLE>` with the `ApplyView` used for writes. It provides helpers to insert, update, and erase the entry in the view, keeping the SLE and its view in sync automatically.
|
||||
|
||||
### Dual-Inheritance Pattern
|
||||
|
||||
Concrete writable wrappers inherit from _both_ the read-only wrapper and `WritableSLE`:
|
||||
|
||||
```
|
||||
WritableAccountRoot
|
||||
├── AccountRoot (extends ReadOnlySLE) — read-only domain methods
|
||||
└── WritableSLE — write capabilities
|
||||
```
|
||||
|
||||
This lets a writable wrapper reuse all read-only domain logic from its parent while gaining mutation and persistence operations from `WritableSLE`.
|
||||
|
||||
## Migration Status
|
||||
|
||||
This migration is still in progress and is still in the early stages. New code should prefer the wrapper style where possible; existing free functions will be migrated incrementally.
|
||||
184
include/xrpl/ledger/helpers/RippleState.h
Normal file
184
include/xrpl/ledger/helpers/RippleState.h
Normal file
@@ -0,0 +1,184 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Expected.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHolderBase.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class RippleState : public virtual TokenHolderBase
|
||||
{
|
||||
public:
|
||||
RippleState(IOUToken const& token, AccountID const& holder)
|
||||
: ReadOnlySLE(
|
||||
token.readView().read(keylet::line(holder, token.getIssuer(), token.getCurrency())),
|
||||
token.readView())
|
||||
, TokenHolderBase(
|
||||
token.readView(),
|
||||
token.readView().read(keylet::line(holder, token.getIssuer(), token.getCurrency())),
|
||||
token,
|
||||
holder)
|
||||
, iouToken_(token)
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor with explicit SLE (for when SLE is already available) */
|
||||
RippleState(
|
||||
ReadView const& view,
|
||||
std::shared_ptr<SLE const> sle,
|
||||
IOUToken const& token,
|
||||
AccountID const& holder)
|
||||
: ReadOnlySLE(sle, view), TokenHolderBase(view, sle, token, holder), iouToken_(token)
|
||||
{
|
||||
}
|
||||
|
||||
IOUToken const&
|
||||
getIOUToken() const
|
||||
{
|
||||
return iouToken_;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkSpendable(
|
||||
STAmount const& amount,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
AuthHandling zeroIfUnauthorized,
|
||||
beast::Journal j) const override
|
||||
{
|
||||
STAmount const balance = (*sle_)[sfBalance];
|
||||
AccountID const& issuer = iouToken_.getIssuer();
|
||||
|
||||
// If balance is positive, issuer must have higher address than account
|
||||
if (balance > beast::zero && issuer < holder_)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
// If balance is negative, issuer must have lower address than account
|
||||
if (balance < beast::zero && issuer > holder_)
|
||||
return tecNO_PERMISSION; // LCOV_EXCL_LINE
|
||||
|
||||
STAmount const spendableAmount = accountHolds(zeroIfFrozen, zeroIfUnauthorized, j);
|
||||
|
||||
// If the balance is less than or equal to 0, return tecINSUFFICIENT_FUNDS
|
||||
if (spendableAmount <= beast::zero)
|
||||
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;
|
||||
}
|
||||
|
||||
protected:
|
||||
IOUToken const& iouToken_;
|
||||
};
|
||||
|
||||
class WritableRippleState : public virtual WritableTokenHolderBase, public virtual RippleState
|
||||
{
|
||||
public:
|
||||
WritableRippleState(ApplyView& view, WritableIOUToken& token, AccountID const& holder)
|
||||
: ReadOnlySLE(view.peek(keylet::line(holder, token.getIssuer(), token.getCurrency())), view)
|
||||
, TokenHolderBase(
|
||||
view,
|
||||
view.peek(keylet::line(holder, token.getIssuer(), token.getCurrency())),
|
||||
token,
|
||||
holder)
|
||||
, WritableSLE(view.peek(keylet::line(holder, token.getIssuer(), token.getCurrency())), view)
|
||||
, WritableTokenHolderBase(
|
||||
view,
|
||||
view.peek(keylet::line(holder, token.getIssuer(), token.getCurrency())),
|
||||
token,
|
||||
holder)
|
||||
, RippleState(token, holder)
|
||||
, writableIOUToken_(token)
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor with explicit SLE (for creation or when SLE is already available) */
|
||||
WritableRippleState(
|
||||
ApplyView& view,
|
||||
std::shared_ptr<SLE> sle,
|
||||
WritableIOUToken& token,
|
||||
AccountID const& holder)
|
||||
: ReadOnlySLE(sle, view)
|
||||
, TokenHolderBase(view, sle, token, holder)
|
||||
, WritableSLE(sle, view)
|
||||
, WritableTokenHolderBase(view, sle, token, holder)
|
||||
, RippleState(view, sle, token, holder)
|
||||
, writableIOUToken_(token)
|
||||
{
|
||||
}
|
||||
|
||||
// Resolve ambiguity: use writable operator-> for non-const, read-only for const
|
||||
using WritableSLE::operator->;
|
||||
using RippleState::operator->;
|
||||
using WritableSLE::operator*;
|
||||
using RippleState::operator*;
|
||||
|
||||
WritableIOUToken&
|
||||
getWritableIOUToken()
|
||||
{
|
||||
return writableIOUToken_;
|
||||
}
|
||||
|
||||
static Expected<std::unique_ptr<WritableRippleState>, TER>
|
||||
createHolding(
|
||||
ApplyView& view,
|
||||
WritableIOUToken& token,
|
||||
AccountID const& accountID,
|
||||
beast::Journal journal)
|
||||
{
|
||||
auto const ter = token.addEmptyHolding(accountID, XRPAmount{0}, journal);
|
||||
if (ter != tesSUCCESS)
|
||||
return Unexpected(ter);
|
||||
return std::make_unique<WritableRippleState>(view, token, accountID);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Trust line operations
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Create a trust line
|
||||
|
||||
This can set an initial balance.
|
||||
*/
|
||||
[[nodiscard]] static TER
|
||||
trustCreate(
|
||||
ApplyView& view,
|
||||
bool const bSrcHigh,
|
||||
AccountID const& uSrcAccountID,
|
||||
AccountID const& uDstAccountID,
|
||||
uint256 const& uIndex, // ripple state entry
|
||||
WritableAccountRoot& wrappedAcct, // the account being set.
|
||||
bool const bAuth, // authorize account.
|
||||
bool const bNoRipple, // others cannot ripple through
|
||||
bool const bFreeze, // funds cannot leave
|
||||
bool bDeepFreeze, // can neither receive nor send funds
|
||||
STAmount const& saBalance, // balance of account being set.
|
||||
// Issuer should be noAccount()
|
||||
STAmount const& saLimit, // limit for account being set.
|
||||
// Issuer should be the account being set.
|
||||
std::uint32_t uQualityIn,
|
||||
std::uint32_t uQualityOut,
|
||||
beast::Journal j);
|
||||
|
||||
[[nodiscard]] static TER
|
||||
trustDelete(
|
||||
ApplyView& view,
|
||||
std::shared_ptr<SLE> const& sleRippleState,
|
||||
AccountID const& uLowAccountID,
|
||||
AccountID const& uHighAccountID,
|
||||
beast::Journal j);
|
||||
|
||||
protected:
|
||||
WritableIOUToken& writableIOUToken_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/IOUAmount.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
@@ -18,6 +19,194 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class IOUToken : public virtual TokenBase
|
||||
{
|
||||
public:
|
||||
IOUToken(ReadView const& view, Issue const& issue)
|
||||
: ReadOnlySLE(view.read(keylet::account(issue.getIssuer())), view)
|
||||
, TokenBase(view, view.read(keylet::account(issue.getIssuer())))
|
||||
, issue_(issue)
|
||||
, issuer_(issue.getIssuer())
|
||||
, issuerAccount_(issuer_, view)
|
||||
, currency_(issue.currency)
|
||||
{
|
||||
}
|
||||
|
||||
IOUToken(ReadView const& view, AccountID const& issuer, Currency const& currency)
|
||||
: IOUToken(view, Issue{currency, issuer})
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] AccountID const&
|
||||
getIssuer() const override
|
||||
{
|
||||
return issuer_;
|
||||
}
|
||||
|
||||
[[nodiscard]] Currency const&
|
||||
getCurrency() const
|
||||
{
|
||||
return currency_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isGlobalFrozen() const override
|
||||
{
|
||||
return issuerAccount_.isGlobalFrozen();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isIndividualFrozen(AccountID const& account) const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isFrozen(AccountID const& account, int depth = 0) const override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkFrozen(AccountID const& account) const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isAnyFrozen(std::initializer_list<AccountID> const& accounts, int depth = 0) const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isDeepFrozen(AccountID const& account, int depth = 0) const override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkDeepFrozen(AccountID const& account) const override;
|
||||
|
||||
[[nodiscard]] Rate
|
||||
transferRate() const override;
|
||||
|
||||
STAmount
|
||||
accountHolds(
|
||||
AccountID const& account,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const override;
|
||||
|
||||
[[nodiscard]] STAmount
|
||||
accountHolds(
|
||||
AccountID const& account,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
AuthHandling zeroIfUnauthorized,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const override;
|
||||
|
||||
/** Returns the funds available for account to pay for an amount.
|
||||
*
|
||||
* If the account is the issuer of the currency, it can always
|
||||
* afford to pay (returns saDefault as-is). Otherwise, returns
|
||||
* the result of accountHolds.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
accountFunds(
|
||||
AccountID const& id,
|
||||
STAmount const& saDefault,
|
||||
FreezeHandling freezeHandling,
|
||||
beast::Journal j) const;
|
||||
|
||||
[[nodiscard]] TER
|
||||
canAddHolding() const override;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Authorization and transfer checks (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] TER
|
||||
requireAuth(AccountID const& account, AuthType authType = AuthType::Legacy, int depth = 0)
|
||||
const override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
canTransfer(AccountID const& from, AccountID const& to) const override;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Token capability checks (IOU-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] bool
|
||||
canClawback() const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
canEscrow() const override
|
||||
{
|
||||
return issuerAccount_->isFlag(lsfAllowTrustLineLocking);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
requiresAuth() const override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkExists() const override
|
||||
{
|
||||
if (!exists())
|
||||
return tecNO_ISSUER;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
hasHolder(AccountID const& holder) const override
|
||||
{
|
||||
return readView_.exists(keylet::line(issuer_, holder, currency_));
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkHolder(AccountID const& holder) const override
|
||||
{
|
||||
if (!hasHolder(holder))
|
||||
return tecNO_LINE;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<TokenHolderBase>
|
||||
getHolder(AccountID const& holder) const override;
|
||||
|
||||
protected:
|
||||
Issue const issue_;
|
||||
AccountID const issuer_;
|
||||
AccountRoot const issuerAccount_;
|
||||
Currency const currency_;
|
||||
};
|
||||
|
||||
class WritableIOUToken : public virtual WritableTokenBase, public virtual IOUToken
|
||||
{
|
||||
public:
|
||||
WritableIOUToken(ApplyView& view, Issue const& issue)
|
||||
: ReadOnlySLE(view.peek(keylet::account(issue.getIssuer())), view)
|
||||
, TokenBase(view, view.peek(keylet::account(issue.getIssuer())))
|
||||
, WritableSLE(view.peek(keylet::account(issue.getIssuer())), view)
|
||||
, WritableTokenBase(view, view.peek(keylet::account(issue.getIssuer())))
|
||||
, IOUToken(view, issue)
|
||||
{
|
||||
}
|
||||
|
||||
WritableIOUToken(ApplyView& view, AccountID const& issuer, Currency const& currency)
|
||||
: WritableIOUToken(view, Issue{currency, issuer})
|
||||
{
|
||||
}
|
||||
|
||||
// Resolve ambiguity: use writable operator-> for non-const, read-only for const
|
||||
using WritableSLE::operator->;
|
||||
using IOUToken::operator->;
|
||||
using WritableSLE::operator*;
|
||||
using IOUToken::operator*;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Holding management (WritableTokenBase interface)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(AccountID const& accountID, XRPAmount priorBalance, beast::Journal journal)
|
||||
override;
|
||||
|
||||
[[nodiscard]] TER
|
||||
removeEmptyHolding(AccountID const& accountID, beast::Journal journal) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Credit functions (from Credit.h)
|
||||
@@ -58,107 +247,6 @@ creditBalance(
|
||||
Currency const& currency);
|
||||
/** @} */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Freeze checking (IOU-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] bool
|
||||
isIndividualFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
Currency const& currency,
|
||||
AccountID const& issuer);
|
||||
|
||||
[[nodiscard]] inline bool
|
||||
isIndividualFrozen(ReadView const& view, AccountID const& account, Issue const& issue)
|
||||
{
|
||||
return isIndividualFrozen(view, account, issue.currency, issue.account);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
Currency const& currency,
|
||||
AccountID const& issuer);
|
||||
|
||||
[[nodiscard]] inline bool
|
||||
isFrozen(ReadView const& view, AccountID const& account, Issue const& issue)
|
||||
{
|
||||
return isFrozen(view, account, issue.currency, issue.account);
|
||||
}
|
||||
|
||||
// Overload with depth parameter for uniformity with MPTIssue version.
|
||||
// The depth parameter is ignored for IOUs since they don't have vault recursion.
|
||||
[[nodiscard]] inline bool
|
||||
isFrozen(ReadView const& view, AccountID const& account, Issue const& issue, int /*depth*/)
|
||||
{
|
||||
return isFrozen(view, account, issue);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isDeepFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
Currency const& currency,
|
||||
AccountID const& issuer);
|
||||
|
||||
[[nodiscard]] inline bool
|
||||
isDeepFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
Issue const& issue,
|
||||
int = 0 /*ignored*/)
|
||||
{
|
||||
return isDeepFrozen(view, account, issue.currency, issue.account);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline TER
|
||||
checkDeepFrozen(ReadView const& view, AccountID const& account, Issue const& issue)
|
||||
{
|
||||
return isDeepFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Trust line operations
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Create a trust line
|
||||
|
||||
This can set an initial balance.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
trustCreate(
|
||||
ApplyView& view,
|
||||
bool const bSrcHigh,
|
||||
AccountID const& uSrcAccountID,
|
||||
AccountID const& uDstAccountID,
|
||||
uint256 const& uIndex, // --> ripple state entry
|
||||
SLE::ref sleAccount, // --> the account being set.
|
||||
bool const bAuth, // --> authorize account.
|
||||
bool const bNoRipple, // --> others cannot ripple through
|
||||
bool const bFreeze, // --> funds cannot leave
|
||||
bool bDeepFreeze, // --> can neither receive nor send funds
|
||||
STAmount const& saBalance, // --> balance of account being set.
|
||||
// Issuer should be noAccount()
|
||||
STAmount const& saLimit, // --> limit for account being set.
|
||||
// Issuer should be the account being set.
|
||||
std::uint32_t uQualityIn,
|
||||
std::uint32_t uQualityOut,
|
||||
beast::Journal j);
|
||||
|
||||
[[nodiscard]] TER
|
||||
trustDelete(
|
||||
ApplyView& view,
|
||||
std::shared_ptr<SLE> const& sleRippleState,
|
||||
AccountID const& uLowAccountID,
|
||||
AccountID const& uHighAccountID,
|
||||
beast::Journal j);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// IOU issuance/redemption
|
||||
@@ -181,43 +269,6 @@ redeemIOU(
|
||||
Issue const& issue,
|
||||
beast::Journal j);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Authorization and transfer checks (IOU-specific)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Check if the account lacks required authorization.
|
||||
*
|
||||
* Return tecNO_AUTH or tecNO_LINE if it does
|
||||
* and tesSUCCESS otherwise.
|
||||
*
|
||||
* If StrongAuth then return tecNO_LINE if the RippleState doesn't exist. Return
|
||||
* tecNO_AUTH if lsfRequireAuth is set on the issuer's AccountRoot, and the
|
||||
* RippleState does exist, and the RippleState is not authorized.
|
||||
*
|
||||
* If WeakAuth then return tecNO_AUTH if lsfRequireAuth is set, and the
|
||||
* RippleState exists, and is not authorized. Return tecNO_LINE if
|
||||
* lsfRequireAuth is set and the RippleState doesn't exist. Consequently, if
|
||||
* WeakAuth and lsfRequireAuth is *not* set, this function will return
|
||||
* tesSUCCESS even if RippleState does *not* exist.
|
||||
*
|
||||
* The default "Legacy" auth type is equivalent to WeakAuth.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
requireAuth(
|
||||
ReadView const& view,
|
||||
Issue const& issue,
|
||||
AccountID const& account,
|
||||
AuthType authType = AuthType::Legacy);
|
||||
|
||||
/** Check if the destination account is allowed
|
||||
* to receive IOU. Return terNO_RIPPLE if rippling is
|
||||
* disabled on both sides and tesSUCCESS otherwise.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, AccountID const& to);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Empty holding operations (IOU-specific)
|
||||
|
||||
200
include/xrpl/ledger/helpers/SLEBase.h
Normal file
200
include/xrpl/ledger/helpers/SLEBase.h
Normal file
@@ -0,0 +1,200 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Read-only base class for all ledger entry view classes.
|
||||
*
|
||||
* Provides common functionality for existence checking and raw SLE read access.
|
||||
* Supports read-only (ReadView) contexts.
|
||||
*
|
||||
* Derived classes should provide domain-specific accessors that hide
|
||||
* implementation details of the underlying ledger entry format.
|
||||
*/
|
||||
class ReadOnlySLE
|
||||
{
|
||||
public:
|
||||
virtual ~ReadOnlySLE() = default;
|
||||
|
||||
// Copy/move constructors are fine (reference can be initialized from another)
|
||||
ReadOnlySLE(ReadOnlySLE const&) = default;
|
||||
ReadOnlySLE(ReadOnlySLE&&) = default;
|
||||
// Assignment operators are deleted (cannot rebind reference members)
|
||||
ReadOnlySLE&
|
||||
operator=(ReadOnlySLE const&) = delete;
|
||||
ReadOnlySLE&
|
||||
operator=(ReadOnlySLE&&) = delete;
|
||||
|
||||
/** Returns true if the ledger entry exists */
|
||||
bool
|
||||
exists() const
|
||||
{
|
||||
return sle_ != nullptr;
|
||||
}
|
||||
|
||||
/** Explicit conversion to bool for convenient existence checking */
|
||||
explicit
|
||||
operator bool() const
|
||||
{
|
||||
return exists();
|
||||
}
|
||||
|
||||
/** Returns the underlying SLE for read access (always available) */
|
||||
std::shared_ptr<SLE const> const&
|
||||
sle() const
|
||||
{
|
||||
return sle_;
|
||||
}
|
||||
|
||||
/** Returns the read view (always available) */
|
||||
ReadView const&
|
||||
readView() const
|
||||
{
|
||||
return readView_;
|
||||
}
|
||||
|
||||
STLedgerEntry const*
|
||||
operator->() const
|
||||
{
|
||||
XRPL_ASSERT(exists(), "xrpl::ReadOnlySLE::operator-> : exists");
|
||||
return sle_.get();
|
||||
}
|
||||
|
||||
STLedgerEntry const&
|
||||
operator*() const
|
||||
{
|
||||
XRPL_ASSERT(exists(), "xrpl::ReadOnlySLE::operator* : exists");
|
||||
return *sle_;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Default constructor is deleted (cannot leave reference uninitialized)
|
||||
ReadOnlySLE() = delete;
|
||||
|
||||
/** Constructor for read-only context (ReadView) */
|
||||
explicit ReadOnlySLE(std::shared_ptr<SLE const> sle, ReadView const& view)
|
||||
: sle_(std::move(sle)), readView_(view)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE const> sle_; // Always valid (const view)
|
||||
ReadView const& readView_; // Always valid
|
||||
};
|
||||
|
||||
/**
|
||||
* Writable base class for all ledger entry view classes.
|
||||
*
|
||||
* Extends ReadOnlySLE with write access capabilities.
|
||||
* Supports read-write (ApplyView) contexts.
|
||||
*
|
||||
* Derived classes should provide domain-specific accessors that hide
|
||||
* implementation details of the underlying ledger entry format.
|
||||
*/
|
||||
class WritableSLE
|
||||
{
|
||||
public:
|
||||
virtual ~WritableSLE() = default;
|
||||
|
||||
// Copy/move constructors are fine (reference can be initialized from another)
|
||||
WritableSLE(WritableSLE const&) = default;
|
||||
WritableSLE(WritableSLE&&) = default;
|
||||
// Assignment operators are deleted (cannot rebind reference members)
|
||||
WritableSLE&
|
||||
operator=(WritableSLE const&) = delete;
|
||||
WritableSLE&
|
||||
operator=(WritableSLE&&) = delete;
|
||||
|
||||
/** Returns a mutable SLE for write operations */
|
||||
std::shared_ptr<SLE> const&
|
||||
mutableSle() const
|
||||
{
|
||||
return mutableSle_;
|
||||
}
|
||||
|
||||
/** Returns true if this wrapper supports write operations */
|
||||
bool
|
||||
canModify() const
|
||||
{
|
||||
return mutableSle_ != nullptr;
|
||||
}
|
||||
|
||||
/** Returns the apply view for write operations */
|
||||
ApplyView&
|
||||
applyView() const
|
||||
{
|
||||
return applyView_;
|
||||
}
|
||||
|
||||
STLedgerEntry*
|
||||
operator->()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::operator-> : can modify");
|
||||
return mutableSle_.get();
|
||||
}
|
||||
|
||||
STLedgerEntry&
|
||||
operator*()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::operator* : can modify");
|
||||
return *mutableSle_;
|
||||
}
|
||||
|
||||
void
|
||||
insert()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::insert : can modify");
|
||||
applyView_.insert(mutableSle_);
|
||||
}
|
||||
|
||||
void
|
||||
erase()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::erase : can modify");
|
||||
applyView_.erase(mutableSle_);
|
||||
}
|
||||
|
||||
void
|
||||
update()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::update : can modify");
|
||||
applyView_.update(mutableSle_);
|
||||
}
|
||||
|
||||
void
|
||||
newSLE()
|
||||
{
|
||||
XRPL_ASSERT(!canModify(), "xrpl::WritableSLE::newSLE : mutableSle_ is not null");
|
||||
mutableSle_ = std::make_shared<SLE>(key_);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Default constructor is deleted (cannot leave reference uninitialized)
|
||||
WritableSLE() = delete;
|
||||
|
||||
/** Constructor for read-write context (ApplyView) */
|
||||
explicit WritableSLE(std::shared_ptr<SLE> sle, ApplyView& view)
|
||||
: applyView_(view)
|
||||
, key_(sle ? Keylet(sle->getType(), sle->key()) : Keylet(ltANY, uint256{}))
|
||||
, mutableSle_(std::move(sle))
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor for read-write context (ApplyView) */
|
||||
explicit WritableSLE(Keylet const& key, ApplyView& view)
|
||||
: applyView_(view), key_(key), mutableSle_(applyView_.peek(key))
|
||||
{
|
||||
}
|
||||
|
||||
ApplyView& applyView_; // ApplyView for write contexts (first for init order)
|
||||
Keylet const key_;
|
||||
std::shared_ptr<SLE> mutableSle_; // Mutable SLE for write contexts
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/WrappedSLEBase.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Rate.h>
|
||||
@@ -10,6 +11,7 @@
|
||||
#include <xrpl/protocol/TER.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -42,88 +44,176 @@ enum class WaiveTransferFee : bool { No = false, Yes };
|
||||
*/
|
||||
enum class AuthType { StrongAuth, WeakAuth, Legacy };
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Freeze checking (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
class TokenHolderBase;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isGlobalFrozen(ReadView const& view, Asset const& asset);
|
||||
class TokenBase : public virtual ReadOnlySLE
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] virtual AccountID const&
|
||||
getIssuer() const = 0;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isIndividualFrozen(ReadView const& view, AccountID const& account, Asset const& asset);
|
||||
[[nodiscard]] virtual bool
|
||||
isGlobalFrozen() const = 0;
|
||||
|
||||
/**
|
||||
* isFrozen check is recursive for MPT shares in a vault, descending to
|
||||
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
|
||||
* purely defensive, as we currently do not allow such vaults to be created.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0);
|
||||
[[nodiscard]] virtual bool
|
||||
isIndividualFrozen(AccountID const& account) const = 0;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue);
|
||||
/**
|
||||
* isFrozen check is recursive for MPT shares in a vault, descending to
|
||||
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
|
||||
* purely defensive, as we currently do not allow such vaults to be created.
|
||||
*/
|
||||
[[nodiscard]] virtual bool
|
||||
isFrozen(AccountID const& account, int depth = 0) const;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue);
|
||||
[[nodiscard]] virtual TER
|
||||
checkFrozen(AccountID const& account) const = 0;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkFrozen(ReadView const& view, AccountID const& account, Asset const& asset);
|
||||
[[nodiscard]] virtual bool
|
||||
isAnyFrozen(std::initializer_list<AccountID> const& accounts, int depth = 0) const = 0;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isAnyFrozen(
|
||||
ReadView const& view,
|
||||
std::initializer_list<AccountID> const& accounts,
|
||||
Issue const& issue);
|
||||
/**
|
||||
* isFrozen check is recursive for MPT shares in a vault, descending to
|
||||
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
|
||||
* purely defensive, as we currently do not allow such vaults to be created.
|
||||
*/
|
||||
[[nodiscard]] virtual bool
|
||||
isDeepFrozen(AccountID const& account, int depth = 0) const = 0;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isAnyFrozen(
|
||||
ReadView const& view,
|
||||
std::initializer_list<AccountID> const& accounts,
|
||||
Asset const& asset,
|
||||
int depth = 0);
|
||||
[[nodiscard]] virtual TER
|
||||
checkDeepFrozen(AccountID const& account) const = 0;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isDeepFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
MPTIssue const& mptIssue,
|
||||
int depth = 0);
|
||||
/** Returns the transfer fee as Rate based on the type of token
|
||||
* @param view The ledger view
|
||||
* @param amount The amount to transfer
|
||||
*/
|
||||
[[nodiscard]] virtual Rate
|
||||
transferRate() const = 0;
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Account balance functions (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* isFrozen check is recursive for MPT shares in a vault, descending to
|
||||
* assets in the vault, up to maxAssetCheckDepth recursion depth. This is
|
||||
* purely defensive, as we currently do not allow such vaults to be created.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset, int depth = 0);
|
||||
// Returns the amount an account can spend.
|
||||
//
|
||||
// If shSIMPLE_BALANCE is specified, this is the amount the account can spend
|
||||
// without going into debt.
|
||||
//
|
||||
// If shFULL_BALANCE is specified, this is the amount the account can spend
|
||||
// total. Specifically:
|
||||
// * The account can go into debt if using a trust line, and the other side has
|
||||
// a non-zero limit.
|
||||
// * If the account is the asset issuer the limit is defined by the asset /
|
||||
// issuance.
|
||||
//
|
||||
// <-- saAmount: amount of currency held by account. May be negative.
|
||||
virtual STAmount
|
||||
accountHolds(
|
||||
AccountID const& account,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const = 0;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue);
|
||||
[[nodiscard]] virtual STAmount
|
||||
accountHolds(
|
||||
AccountID const& account,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
AuthHandling zeroIfUnauthorized,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const = 0;
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset);
|
||||
[[nodiscard]] virtual TER
|
||||
canAddHolding() const = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Account balance functions (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Authorization and transfer checks (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Returns the amount an account can spend.
|
||||
//
|
||||
// If shSIMPLE_BALANCE is specified, this is the amount the account can spend
|
||||
// without going into debt.
|
||||
//
|
||||
// If shFULL_BALANCE is specified, this is the amount the account can spend
|
||||
// total. Specifically:
|
||||
// * The account can go into debt if using a trust line, and the other side has
|
||||
// a non-zero limit.
|
||||
// * If the account is the asset issuer the limit is defined by the asset /
|
||||
// issuance.
|
||||
//
|
||||
// <-- saAmount: amount of currency held by account. May be negative.
|
||||
[[nodiscard]] virtual TER
|
||||
requireAuth(AccountID const& account, AuthType authType = AuthType::Legacy, int depth = 0)
|
||||
const = 0;
|
||||
|
||||
[[nodiscard]] virtual TER
|
||||
canTransfer(AccountID const& from, AccountID const& to) const = 0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Token capability checks (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Check if the token issuer has enabled clawback capability.
|
||||
* For IOUs, checks lsfAllowTrustLineClawback on issuer's AccountRoot.
|
||||
* For MPTs, checks lsfMPTCanClawback on the issuance.
|
||||
*/
|
||||
[[nodiscard]] virtual bool
|
||||
canClawback() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool
|
||||
canEscrow() const = 0;
|
||||
|
||||
/** Check if the token requires authorization for holders.
|
||||
* For IOUs, checks lsfRequireAuth on issuer's AccountRoot.
|
||||
* For MPTs, checks lsfMPTRequireAuth on the issuance.
|
||||
*/
|
||||
[[nodiscard]] virtual bool
|
||||
requiresAuth() const = 0;
|
||||
|
||||
[[nodiscard]] virtual TER
|
||||
checkExists() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool
|
||||
hasHolder(AccountID const& holder) const = 0;
|
||||
|
||||
[[nodiscard]] virtual TER
|
||||
checkHolder(AccountID const& holder) const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::unique_ptr<TokenHolderBase>
|
||||
getHolder(AccountID const& holder) const = 0;
|
||||
|
||||
protected:
|
||||
TokenBase(ReadView const& view, std::shared_ptr<SLE const> sle) : ReadOnlySLE(sle, view)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class WritableTokenBase : public virtual TokenBase, public virtual WritableSLE
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Holding operations (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] virtual TER
|
||||
addEmptyHolding(AccountID const& accountID, XRPAmount priorBalance, beast::Journal journal) = 0;
|
||||
|
||||
[[nodiscard]] virtual TER
|
||||
removeEmptyHolding(AccountID const& accountID, beast::Journal journal) = 0;
|
||||
|
||||
protected:
|
||||
WritableTokenBase(ApplyView& view, std::shared_ptr<SLE> sle)
|
||||
: TokenBase(view, sle), WritableSLE(sle, view)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<TokenBase>
|
||||
makeTokenBase(ReadView const& view, Asset const& asset);
|
||||
|
||||
std::unique_ptr<WritableTokenBase>
|
||||
makeWritableTokenBase(ApplyView& view, Asset const& asset);
|
||||
|
||||
// Helper function to get transfer rate from an STAmount
|
||||
[[nodiscard]] Rate
|
||||
transferRate(ReadView const& view, STAmount const& amount);
|
||||
|
||||
// Returns the amount the specified account can spend.
|
||||
// Supports both IOU and MPT via Currency/AccountID parameters.
|
||||
[[nodiscard]] STAmount
|
||||
accountHolds(
|
||||
ReadView const& view,
|
||||
@@ -134,25 +224,8 @@ accountHolds(
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE);
|
||||
|
||||
[[nodiscard]] STAmount
|
||||
accountHolds(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
Issue const& issue,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE);
|
||||
|
||||
[[nodiscard]] STAmount
|
||||
accountHolds(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
MPTIssue const& mptIssue,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
AuthHandling zeroIfUnauthorized,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE);
|
||||
|
||||
// Returns the amount the specified account can spend for a given Asset.
|
||||
// Dispatches to appropriate token wrapper based on Asset type.
|
||||
[[nodiscard]] STAmount
|
||||
accountHolds(
|
||||
ReadView const& view,
|
||||
@@ -163,66 +236,6 @@ accountHolds(
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE);
|
||||
|
||||
// Returns the amount an account can spend of the currency type saDefault, or
|
||||
// returns saDefault if this account is the issuer of the currency in
|
||||
// question. Should be used in favor of accountHolds when questioning how much
|
||||
// an account can spend while also allowing currency issuers to spend
|
||||
// unlimited amounts of their own currency (since they can always issue more).
|
||||
[[nodiscard]] STAmount
|
||||
accountFunds(
|
||||
ReadView const& view,
|
||||
AccountID const& id,
|
||||
STAmount const& saDefault,
|
||||
FreezeHandling freezeHandling,
|
||||
beast::Journal j);
|
||||
|
||||
/** Returns the transfer fee as Rate based on the type of token
|
||||
* @param view The ledger view
|
||||
* @param amount The amount to transfer
|
||||
*/
|
||||
[[nodiscard]] Rate
|
||||
transferRate(ReadView const& view, STAmount const& amount);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Holding operations (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] TER
|
||||
canAddHolding(ReadView const& view, Asset const& asset);
|
||||
|
||||
[[nodiscard]] TER
|
||||
addEmptyHolding(
|
||||
ApplyView& view,
|
||||
AccountID const& accountID,
|
||||
XRPAmount priorBalance,
|
||||
Asset const& asset,
|
||||
beast::Journal journal);
|
||||
|
||||
[[nodiscard]] TER
|
||||
removeEmptyHolding(
|
||||
ApplyView& view,
|
||||
AccountID const& accountID,
|
||||
Asset const& asset,
|
||||
beast::Journal journal);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Authorization and transfer checks (Asset-based dispatchers)
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[[nodiscard]] TER
|
||||
requireAuth(
|
||||
ReadView const& view,
|
||||
Asset const& asset,
|
||||
AccountID const& account,
|
||||
AuthType authType = AuthType::Legacy);
|
||||
|
||||
[[nodiscard]] TER
|
||||
canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, AccountID const& to);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Money Transfers (Asset-based dispatchers)
|
||||
@@ -232,7 +245,7 @@ canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, Acc
|
||||
// Direct send w/o fees:
|
||||
// - Redeeming IOUs and/or sending sender's own IOUs.
|
||||
// - Create trust line of needed.
|
||||
// --> bCheckIssuer : normally require issuer to be involved.
|
||||
// bCheckIssuer : normally require issuer to be involved.
|
||||
// [[nodiscard]] // nodiscard commented out so DirectStep.cpp compiles.
|
||||
|
||||
/** Calls static rippleCreditIOU if saAmount represents Issue.
|
||||
|
||||
163
include/xrpl/ledger/helpers/TokenHolderBase.h
Normal file
163
include/xrpl/ledger/helpers/TokenHolderBase.h
Normal file
@@ -0,0 +1,163 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/WrappedSLEBase.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class TokenHolderBase : public virtual ReadOnlySLE
|
||||
{
|
||||
public:
|
||||
TokenHolderBase(
|
||||
ReadView const& view,
|
||||
std::shared_ptr<SLE const> sle,
|
||||
TokenBase const& token,
|
||||
AccountID const& holder)
|
||||
: ReadOnlySLE(sle, view), token_(token), holder_(holder), holderAccount_(holder, view)
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor with explicit keylet (for when SLE lookup is needed) */
|
||||
TokenHolderBase(
|
||||
ReadView const& view,
|
||||
Keylet const& key,
|
||||
TokenBase const& token,
|
||||
AccountID const& holder)
|
||||
: ReadOnlySLE(key, view), token_(token), holder_(holder), holderAccount_(holder, view)
|
||||
{
|
||||
}
|
||||
|
||||
TokenHolderBase() = delete;
|
||||
|
||||
AccountID const&
|
||||
getHolder() const
|
||||
{
|
||||
return holder_;
|
||||
}
|
||||
|
||||
TokenBase const&
|
||||
getToken() const
|
||||
{
|
||||
return token_;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isFrozen(int depth = 0) const
|
||||
{
|
||||
return token_.isFrozen(holder_, depth);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isDeepFrozen(int depth = 0) const
|
||||
{
|
||||
return token_.isDeepFrozen(holder_, depth);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkFrozen() const
|
||||
{
|
||||
return token_.checkFrozen(holder_);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkDeepFrozen() const
|
||||
{
|
||||
return token_.checkDeepFrozen(holder_);
|
||||
}
|
||||
|
||||
STAmount
|
||||
accountHolds(
|
||||
FreezeHandling zeroIfFrozen,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const
|
||||
{
|
||||
return token_.accountHolds(holder_, zeroIfFrozen, j, includeFullBalance);
|
||||
}
|
||||
|
||||
[[nodiscard]] STAmount
|
||||
accountHolds(
|
||||
FreezeHandling zeroIfFrozen,
|
||||
AuthHandling zeroIfUnauthorized,
|
||||
beast::Journal j,
|
||||
SpendableHandling includeFullBalance = shSIMPLE_BALANCE) const
|
||||
{
|
||||
return token_.accountHolds(
|
||||
holder_, zeroIfFrozen, zeroIfUnauthorized, j, includeFullBalance);
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual TER
|
||||
checkSpendable(
|
||||
STAmount const& amount,
|
||||
FreezeHandling zeroIfFrozen,
|
||||
AuthHandling zeroIfUnauthorized,
|
||||
beast::Journal j) const = 0;
|
||||
|
||||
[[nodiscard]] TER
|
||||
requireAuth(AuthType authType = AuthType::Legacy, int depth = 0) const
|
||||
{
|
||||
return token_.requireAuth(holder_, authType, depth);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
canTransfer(AccountID const& to) const
|
||||
{
|
||||
return token_.canTransfer(holder_, to);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
canTransfer(TokenHolderBase const& to) const
|
||||
{
|
||||
return token_.canTransfer(holder_, to.getHolder());
|
||||
}
|
||||
|
||||
protected:
|
||||
TokenBase const& token_;
|
||||
AccountID const holder_;
|
||||
AccountRoot holderAccount_;
|
||||
};
|
||||
|
||||
class WritableTokenHolderBase : public virtual TokenHolderBase, public virtual WritableSLE
|
||||
{
|
||||
public:
|
||||
WritableTokenHolderBase(
|
||||
ApplyView& view,
|
||||
std::shared_ptr<SLE> sle,
|
||||
WritableTokenBase& token,
|
||||
AccountID const& holder)
|
||||
: ReadOnlySLE(sle, view)
|
||||
, TokenHolderBase(view, sle, token, holder)
|
||||
, WritableSLE(sle, view)
|
||||
, writableToken_(token)
|
||||
, writableHolderAccount_(holder, view)
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor with explicit keylet (for creation or lookup by key) */
|
||||
WritableTokenHolderBase(
|
||||
ApplyView& view,
|
||||
Keylet const& key,
|
||||
WritableTokenBase& token,
|
||||
AccountID const& holder)
|
||||
: ReadOnlySLE(key, view)
|
||||
, TokenHolderBase(view, key, token, holder)
|
||||
, WritableSLE(key, view)
|
||||
, writableToken_(token)
|
||||
, writableHolderAccount_(holder, view)
|
||||
{
|
||||
}
|
||||
|
||||
WritableTokenBase&
|
||||
getWritableToken()
|
||||
{
|
||||
return writableToken_;
|
||||
}
|
||||
|
||||
protected:
|
||||
WritableTokenBase& writableToken_;
|
||||
WritableAccountRoot writableHolderAccount_;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
@@ -21,7 +22,7 @@ namespace xrpl {
|
||||
[[nodiscard]] std::optional<STAmount>
|
||||
assetsToSharesDeposit(
|
||||
std::shared_ptr<SLE const> const& vault,
|
||||
std::shared_ptr<SLE const> const& issuance,
|
||||
MPTokenIssuance const& issuance,
|
||||
STAmount const& assets);
|
||||
|
||||
/** From the perspective of a vault, return the number of assets to take from
|
||||
@@ -37,7 +38,7 @@ assetsToSharesDeposit(
|
||||
[[nodiscard]] std::optional<STAmount>
|
||||
sharesToAssetsDeposit(
|
||||
std::shared_ptr<SLE const> const& vault,
|
||||
std::shared_ptr<SLE const> const& issuance,
|
||||
MPTokenIssuance const& issuance,
|
||||
STAmount const& shares);
|
||||
|
||||
/** Controls whether to truncate shares instead of rounding. */
|
||||
@@ -58,7 +59,7 @@ enum class TruncateShares : bool { no = false, yes = true };
|
||||
[[nodiscard]] std::optional<STAmount>
|
||||
assetsToSharesWithdraw(
|
||||
std::shared_ptr<SLE const> const& vault,
|
||||
std::shared_ptr<SLE const> const& issuance,
|
||||
MPTokenIssuance const& issuance,
|
||||
STAmount const& assets,
|
||||
TruncateShares truncate = TruncateShares::no);
|
||||
|
||||
@@ -75,7 +76,7 @@ assetsToSharesWithdraw(
|
||||
[[nodiscard]] std::optional<STAmount>
|
||||
sharesToAssetsWithdraw(
|
||||
std::shared_ptr<SLE const> const& vault,
|
||||
std::shared_ptr<SLE const> const& issuance,
|
||||
MPTokenIssuance const& issuance,
|
||||
STAmount const& shares);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
215
include/xrpl/ledger/helpers/WrappedSLEBase.h
Normal file
215
include/xrpl/ledger/helpers/WrappedSLEBase.h
Normal file
@@ -0,0 +1,215 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* Read-only base class for all ledger entry view classes.
|
||||
*
|
||||
* Provides common functionality for existence checking and raw SLE read access.
|
||||
* Supports read-only (ReadView) contexts.
|
||||
*
|
||||
* Derived classes should provide domain-specific accessors that hide
|
||||
* implementation details of the underlying ledger entry format.
|
||||
*/
|
||||
class ReadOnlySLE
|
||||
{
|
||||
public:
|
||||
virtual ~ReadOnlySLE() = default;
|
||||
|
||||
// Copy/move constructors are fine (reference can be initialized from another)
|
||||
ReadOnlySLE(ReadOnlySLE const&) = default;
|
||||
ReadOnlySLE(ReadOnlySLE&&) = default;
|
||||
// Assignment operators are deleted (cannot rebind reference members)
|
||||
ReadOnlySLE&
|
||||
operator=(ReadOnlySLE const&) = delete;
|
||||
ReadOnlySLE&
|
||||
operator=(ReadOnlySLE&&) = delete;
|
||||
|
||||
/** Returns true if the ledger entry exists */
|
||||
bool
|
||||
exists() const
|
||||
{
|
||||
return sle_ != nullptr;
|
||||
}
|
||||
|
||||
/** Explicit conversion to bool for convenient existence checking */
|
||||
explicit
|
||||
operator bool() const
|
||||
{
|
||||
return exists();
|
||||
}
|
||||
|
||||
/** Returns the underlying SLE for read access (always available) */
|
||||
std::shared_ptr<SLE const> const&
|
||||
sle() const
|
||||
{
|
||||
return sle_;
|
||||
}
|
||||
|
||||
/** Returns the read view (always available) */
|
||||
ReadView const&
|
||||
readView() const
|
||||
{
|
||||
return readView_;
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
key() const
|
||||
{
|
||||
return key_;
|
||||
}
|
||||
|
||||
STLedgerEntry const*
|
||||
operator->() const
|
||||
{
|
||||
XRPL_ASSERT(exists(), "xrpl::ReadOnlySLE::operator-> : exists");
|
||||
return sle_.get();
|
||||
}
|
||||
|
||||
STLedgerEntry const&
|
||||
operator*() const
|
||||
{
|
||||
XRPL_ASSERT(exists(), "xrpl::ReadOnlySLE::operator* : exists");
|
||||
return *sle_;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Default constructor is deleted (cannot leave reference uninitialized)
|
||||
ReadOnlySLE() = delete;
|
||||
|
||||
/** Constructor for read-only context (ReadView) */
|
||||
explicit ReadOnlySLE(std::shared_ptr<SLE const> sle, ReadView const& view)
|
||||
: sle_(std::move(sle))
|
||||
, readView_(view)
|
||||
, key_(sle_ ? Keylet(sle_->getType(), sle_->key()) : Keylet(ltANY, uint256{}))
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor for read-only context (ReadView) with explicit keylet */
|
||||
explicit ReadOnlySLE(Keylet const& key, ReadView const& view)
|
||||
: sle_(view.read(key)), readView_(view), key_(key)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<SLE const> sle_; // Always valid (const view)
|
||||
ReadView const& readView_; // Always valid
|
||||
Keylet key_; // Keylet for this entry
|
||||
};
|
||||
|
||||
/**
|
||||
* Writable base class for all ledger entry view classes.
|
||||
*
|
||||
* Extends ReadOnlySLE with write access capabilities.
|
||||
* Supports read-write (ApplyView) contexts.
|
||||
*
|
||||
* Derived classes should provide domain-specific accessors that hide
|
||||
* implementation details of the underlying ledger entry format.
|
||||
*/
|
||||
class WritableSLE
|
||||
{
|
||||
public:
|
||||
virtual ~WritableSLE() = default;
|
||||
|
||||
// Copy/move constructors are fine (reference can be initialized from another)
|
||||
WritableSLE(WritableSLE const&) = default;
|
||||
WritableSLE(WritableSLE&&) = default;
|
||||
// Assignment operators are deleted (cannot rebind reference members)
|
||||
WritableSLE&
|
||||
operator=(WritableSLE const&) = delete;
|
||||
WritableSLE&
|
||||
operator=(WritableSLE&&) = delete;
|
||||
|
||||
/** Returns a mutable SLE for write operations */
|
||||
std::shared_ptr<SLE> const&
|
||||
mutableSle() const
|
||||
{
|
||||
return mutableSle_;
|
||||
}
|
||||
|
||||
/** Returns true if this wrapper supports write operations */
|
||||
bool
|
||||
canModify() const
|
||||
{
|
||||
return mutableSle_ != nullptr;
|
||||
}
|
||||
|
||||
/** Returns the apply view for write operations */
|
||||
ApplyView&
|
||||
applyView() const
|
||||
{
|
||||
return applyView_;
|
||||
}
|
||||
|
||||
STLedgerEntry*
|
||||
operator->()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::operator-> : can modify");
|
||||
return mutableSle_.get();
|
||||
}
|
||||
|
||||
STLedgerEntry&
|
||||
operator*()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::operator* : can modify");
|
||||
return *mutableSle_;
|
||||
}
|
||||
|
||||
void
|
||||
insert()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::insert : can modify");
|
||||
applyView_.insert(mutableSle_);
|
||||
}
|
||||
|
||||
void
|
||||
erase()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::erase : can modify");
|
||||
applyView_.erase(mutableSle_);
|
||||
}
|
||||
|
||||
void
|
||||
update()
|
||||
{
|
||||
XRPL_ASSERT(canModify(), "xrpl::WritableSLE::update : can modify");
|
||||
applyView_.update(mutableSle_);
|
||||
}
|
||||
|
||||
void
|
||||
newSLE()
|
||||
{
|
||||
XRPL_ASSERT(!canModify(), "xrpl::WritableSLE::newSLE : mutableSle_ is not null");
|
||||
mutableSle_ = std::make_shared<SLE>(key_);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Default constructor is deleted (cannot leave reference uninitialized)
|
||||
WritableSLE() = delete;
|
||||
|
||||
/** Constructor for read-write context (ApplyView) */
|
||||
explicit WritableSLE(std::shared_ptr<SLE> sle, ApplyView& view)
|
||||
: applyView_(view)
|
||||
, key_(sle ? Keylet(sle->getType(), sle->key()) : Keylet(ltANY, uint256{}))
|
||||
, mutableSle_(std::move(sle))
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor for read-write context (ApplyView) */
|
||||
explicit WritableSLE(Keylet const& key, ApplyView& view)
|
||||
: applyView_(view), key_(key), mutableSle_(applyView_.peek(key))
|
||||
{
|
||||
}
|
||||
|
||||
ApplyView& applyView_; // ApplyView for write contexts (first for init order)
|
||||
Keylet key_; // Keylet for this entry
|
||||
std::shared_ptr<SLE> mutableSle_; // Mutable SLE for write contexts
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -16,7 +16,7 @@ struct FetchReport
|
||||
{
|
||||
}
|
||||
|
||||
std::chrono::milliseconds elapsed{};
|
||||
std::chrono::milliseconds elapsed;
|
||||
FetchType const fetchType;
|
||||
bool wasFound = false;
|
||||
};
|
||||
|
||||
@@ -71,8 +71,8 @@ private:
|
||||
Scheduler& m_scheduler;
|
||||
LockType mWriteMutex;
|
||||
CondvarType mWriteCondition;
|
||||
int mWriteLoad{0};
|
||||
bool mWritePending{false};
|
||||
int mWriteLoad;
|
||||
bool mWritePending;
|
||||
Batch mWriteSet;
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace NodeStore {
|
||||
class EncodedBlob
|
||||
{
|
||||
/** The 32-byte key of the serialized object. */
|
||||
std::array<std::uint8_t, 32> key_{};
|
||||
std::array<std::uint8_t, 32> key_;
|
||||
|
||||
/** A pre-allocated buffer for the serialized object.
|
||||
|
||||
@@ -43,8 +43,7 @@ class EncodedBlob
|
||||
1024 more bytes. The precise size is calculated automatically
|
||||
at compile time so as to avoid wasting space on padding bytes.
|
||||
*/
|
||||
std::array<std::uint8_t, boost::alignment::align_up(9 + 1024, alignof(std::uint32_t))>
|
||||
payload_{};
|
||||
std::array<std::uint8_t, boost::alignment::align_up(9 + 1024, alignof(std::uint32_t))> payload_;
|
||||
|
||||
/** The size of the serialized data. */
|
||||
std::uint32_t size_;
|
||||
|
||||
@@ -56,7 +56,7 @@ lz4_compress(void const* in, std::size_t in_size, BufferFactory&& bf)
|
||||
using std::runtime_error;
|
||||
using namespace nudb::detail;
|
||||
std::pair<void const*, std::size_t> result;
|
||||
std::array<std::uint8_t, varint_traits<std::size_t>::max> vi{};
|
||||
std::array<std::uint8_t, varint_traits<std::size_t>::max> vi;
|
||||
auto const n = write_varint(vi.data(), in_size);
|
||||
auto const out_max = LZ4_compressBound(in_size);
|
||||
std::uint8_t* out = reinterpret_cast<std::uint8_t*>(bf(n + out_max));
|
||||
@@ -88,7 +88,7 @@ nodeobject_decompress(void const* in, std::size_t in_size, BufferFactory&& bf)
|
||||
using namespace nudb::detail;
|
||||
|
||||
std::uint8_t const* p = reinterpret_cast<std::uint8_t const*>(in);
|
||||
std::size_t type = 0;
|
||||
std::size_t type;
|
||||
auto const vn = read_varint(p, in_size, type);
|
||||
if (vn == 0)
|
||||
Throw<std::runtime_error>("nodeobject decompress");
|
||||
@@ -117,7 +117,7 @@ nodeobject_decompress(void const* in, std::size_t in_size, BufferFactory&& bf)
|
||||
"nodeobject codec v1: short inner node size: " + std::string("in_size = ") +
|
||||
std::to_string(in_size) + " hs = " + std::to_string(hs));
|
||||
istream is(p, in_size);
|
||||
std::uint16_t mask = 0;
|
||||
std::uint16_t mask;
|
||||
read<std::uint16_t>(is, mask); // Mask
|
||||
in_size -= hs;
|
||||
result.second = 525;
|
||||
@@ -196,10 +196,10 @@ nodeobject_compress(void const* in, std::size_t in_size, BufferFactory&& bf)
|
||||
if (in_size == 525)
|
||||
{
|
||||
istream is(in, in_size);
|
||||
std::uint32_t index = 0;
|
||||
std::uint32_t unused = 0;
|
||||
std::uint8_t kind = 0;
|
||||
std::uint32_t prefix = 0;
|
||||
std::uint32_t index;
|
||||
std::uint32_t unused;
|
||||
std::uint8_t kind;
|
||||
std::uint32_t prefix;
|
||||
read<std::uint32_t>(is, index);
|
||||
read<std::uint32_t>(is, unused);
|
||||
read<std::uint8_t>(is, kind);
|
||||
@@ -208,7 +208,7 @@ nodeobject_compress(void const* in, std::size_t in_size, BufferFactory&& bf)
|
||||
{
|
||||
std::size_t n = 0;
|
||||
std::uint16_t mask = 0;
|
||||
std::array<std::uint8_t, 512> vh{};
|
||||
std::array<std::uint8_t, 512> vh;
|
||||
for (unsigned bit = 0x8000; bit; bit >>= 1)
|
||||
{
|
||||
void const* const h = is(32);
|
||||
@@ -247,7 +247,7 @@ nodeobject_compress(void const* in, std::size_t in_size, BufferFactory&& bf)
|
||||
}
|
||||
}
|
||||
|
||||
std::array<std::uint8_t, varint_traits<std::size_t>::max> vi{};
|
||||
std::array<std::uint8_t, varint_traits<std::size_t>::max> vi;
|
||||
|
||||
constexpr std::size_t codecType = 1;
|
||||
auto const vn = write_varint(vi.data(), codecType);
|
||||
@@ -257,7 +257,7 @@ nodeobject_compress(void const* in, std::size_t in_size, BufferFactory&& bf)
|
||||
// case 0 was uncompressed data; we always compress now.
|
||||
case 1: // lz4
|
||||
{
|
||||
std::uint8_t* p = nullptr;
|
||||
std::uint8_t* p;
|
||||
auto const lzr = NodeStore::lz4_compress(in, in_size, [&p, &vn, &bf](std::size_t n) {
|
||||
p = reinterpret_cast<std::uint8_t*>(bf(vn + n));
|
||||
return p + vn;
|
||||
@@ -287,10 +287,10 @@ filter_inner(void* in, std::size_t in_size)
|
||||
if (in_size == 525)
|
||||
{
|
||||
istream is(in, in_size);
|
||||
std::uint32_t index = 0;
|
||||
std::uint32_t unused = 0;
|
||||
std::uint8_t kind = 0;
|
||||
std::uint32_t prefix = 0;
|
||||
std::uint32_t index;
|
||||
std::uint32_t unused;
|
||||
std::uint8_t kind;
|
||||
std::uint32_t prefix;
|
||||
read<std::uint32_t>(is, index);
|
||||
read<std::uint32_t>(is, unused);
|
||||
read<std::uint8_t>(is, kind);
|
||||
|
||||
@@ -82,7 +82,6 @@ template <class = void>
|
||||
std::size_t
|
||||
write_varint(void* p0, std::size_t v)
|
||||
{
|
||||
// NOLINTNEXTLINE(misc-const-correctness)
|
||||
std::uint8_t* p = reinterpret_cast<std::uint8_t*>(p0);
|
||||
do
|
||||
{
|
||||
|
||||
@@ -102,7 +102,7 @@ template <typename T>
|
||||
T
|
||||
toAmount(Issue const& issue, Number const& n, Number::rounding_mode mode = Number::getround())
|
||||
{
|
||||
saveNumberRoundMode const rm(Number::getround());
|
||||
saveNumberRoundMode rm(Number::getround());
|
||||
if (isXRP(issue))
|
||||
Number::setround(mode);
|
||||
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Deprecated constant for backwards compatibility with pre-XRPFees amendment.
|
||||
// This was the reference fee units used in the old fee calculation.
|
||||
inline constexpr std::uint32_t FEE_UNITS_DEPRECATED = 10;
|
||||
|
||||
/** Reflects the fee settings for a particular ledger.
|
||||
|
||||
The fees are always the same for any transactions applied
|
||||
@@ -15,25 +11,15 @@ inline constexpr std::uint32_t FEE_UNITS_DEPRECATED = 10;
|
||||
*/
|
||||
struct Fees
|
||||
{
|
||||
/** @brief Cost of a reference transaction in drops. */
|
||||
XRPAmount base{0};
|
||||
|
||||
/** @brief Minimum XRP an account must hold to exist on the ledger. */
|
||||
XRPAmount reserve{0};
|
||||
|
||||
/** @brief Additional XRP reserve required per owned ledger object. */
|
||||
XRPAmount increment{0};
|
||||
XRPAmount base{0}; // Reference tx cost (drops)
|
||||
XRPAmount reserve{0}; // Reserve base (drops)
|
||||
XRPAmount increment{0}; // Reserve increment (drops)
|
||||
|
||||
explicit Fees() = default;
|
||||
Fees(Fees const&) = default;
|
||||
Fees&
|
||||
operator=(Fees const&) = default;
|
||||
|
||||
Fees(XRPAmount base_, XRPAmount reserve_, XRPAmount increment_)
|
||||
: base(base_), reserve(reserve_), increment(increment_)
|
||||
{
|
||||
}
|
||||
|
||||
/** Returns the account reserve given the owner count, in drops.
|
||||
|
||||
The reserve is calculated as the reserve base plus
|
||||
|
||||
@@ -26,8 +26,8 @@ class IOUAmount : private boost::totally_ordered<IOUAmount>, private boost::addi
|
||||
private:
|
||||
using mantissa_type = std::int64_t;
|
||||
using exponent_type = int;
|
||||
mantissa_type mantissa_{};
|
||||
exponent_type exponent_{};
|
||||
mantissa_type mantissa_;
|
||||
exponent_type exponent_;
|
||||
|
||||
/** Adjusts the mantissa and exponent to the proper range.
|
||||
|
||||
|
||||
@@ -363,12 +363,11 @@ uint256
|
||||
getTicketIndex(AccountID const& account, SeqProxy ticketSeq);
|
||||
|
||||
template <class... keyletParams>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
struct keyletDesc
|
||||
{
|
||||
std::function<Keylet(keyletParams...)> function;
|
||||
Json::StaticString expectedLEName;
|
||||
bool includeInTests{};
|
||||
bool includeInTests;
|
||||
};
|
||||
|
||||
// This list should include all of the keylet functions that take a single
|
||||
|
||||
@@ -96,7 +96,7 @@ operator<=>(Issue const& lhs, Issue const& rhs)
|
||||
inline Issue const&
|
||||
xrpIssue()
|
||||
{
|
||||
static Issue const issue{xrpCurrency(), xrpAccount()};
|
||||
static Issue issue{xrpCurrency(), xrpAccount()};
|
||||
return issue;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ xrpIssue()
|
||||
inline Issue const&
|
||||
noIssue()
|
||||
{
|
||||
static Issue const issue{noCurrency(), noAccount()};
|
||||
static Issue issue{noCurrency(), noAccount()};
|
||||
return issue;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,8 +72,4 @@ deserializeHeader(Slice data, bool hasHash = false);
|
||||
LedgerHeader
|
||||
deserializePrefixedHeader(Slice data, bool hasHash = false);
|
||||
|
||||
/** Calculate the hash of a ledger header. */
|
||||
uint256
|
||||
calculateLedgerHash(LedgerHeader const& info);
|
||||
|
||||
} // 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