mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-01 19:42:12 +00:00
Compare commits
3 Commits
dangell7/f
...
mvadari/te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
537c520e32 | ||
|
|
310bfc7b94 | ||
|
|
afc0b7ab8c |
289
.clang-tidy
289
.clang-tidy
@@ -1,140 +1,161 @@
|
||||
---
|
||||
Checks: "-*,
|
||||
bugprone-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-exception-escape,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-throwing-static-initialization,
|
||||
|
||||
cppcoreguidelines-*,
|
||||
-cppcoreguidelines-avoid-c-arrays,
|
||||
-cppcoreguidelines-avoid-capturing-lambda-coroutines,
|
||||
-cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||
-cppcoreguidelines-avoid-do-while,
|
||||
-cppcoreguidelines-avoid-goto,
|
||||
-cppcoreguidelines-avoid-magic-numbers,
|
||||
-cppcoreguidelines-avoid-non-const-global-variables,
|
||||
-cppcoreguidelines-avoid-reference-coroutine-parameters,
|
||||
-cppcoreguidelines-c-copy-assignment-signature,
|
||||
-cppcoreguidelines-explicit-virtual-functions,
|
||||
-cppcoreguidelines-interfaces-global-init,
|
||||
-cppcoreguidelines-macro-to-enum,
|
||||
-cppcoreguidelines-macro-usage,
|
||||
-cppcoreguidelines-missing-std-forward,
|
||||
-cppcoreguidelines-narrowing-conversions,
|
||||
-cppcoreguidelines-no-malloc,
|
||||
-cppcoreguidelines-noexcept-destructor,
|
||||
-cppcoreguidelines-noexcept-move-operations,
|
||||
-cppcoreguidelines-noexcept-swap,
|
||||
-cppcoreguidelines-non-private-member-variables-in-classes,
|
||||
-cppcoreguidelines-owning-memory,
|
||||
-cppcoreguidelines-prefer-member-initializer,
|
||||
-cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
||||
-cppcoreguidelines-pro-bounds-avoid-unchecked-container-access,
|
||||
-cppcoreguidelines-pro-bounds-constant-array-index,
|
||||
-cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
||||
-cppcoreguidelines-pro-type-const-cast,
|
||||
-cppcoreguidelines-pro-type-cstyle-cast,
|
||||
-cppcoreguidelines-pro-type-reinterpret-cast,
|
||||
-cppcoreguidelines-pro-type-union-access,
|
||||
-cppcoreguidelines-pro-type-vararg,
|
||||
-cppcoreguidelines-slicing,
|
||||
-cppcoreguidelines-special-member-functions,
|
||||
|
||||
bugprone-argument-comment,
|
||||
bugprone-assert-side-effect,
|
||||
bugprone-bad-signal-to-kill-thread,
|
||||
bugprone-bool-pointer-implicit-conversion,
|
||||
bugprone-capturing-this-in-member-variable,
|
||||
bugprone-casting-through-void,
|
||||
bugprone-chained-comparison,
|
||||
bugprone-compare-pointer-to-member-virtual-function,
|
||||
bugprone-copy-constructor-init,
|
||||
bugprone-crtp-constructor-accessibility,
|
||||
bugprone-dangling-handle,
|
||||
bugprone-derived-method-shadowing-base-method,
|
||||
bugprone-dynamic-static-initializers,
|
||||
bugprone-empty-catch,
|
||||
bugprone-fold-init-type,
|
||||
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-invalid-enum-default-initialization,
|
||||
bugprone-lambda-function-name,
|
||||
bugprone-macro-parentheses,
|
||||
bugprone-macro-repeated-side-effects,
|
||||
bugprone-misleading-setter-of-reference,
|
||||
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,
|
||||
bugprone-multiple-new-in-one-expression,
|
||||
bugprone-multiple-statement-macro,
|
||||
bugprone-no-escape,
|
||||
bugprone-non-zero-enum-to-bool-conversion,
|
||||
bugprone-optional-value-conversion,
|
||||
bugprone-parent-virtual-call,
|
||||
bugprone-pointer-arithmetic-on-polymorphic-object,
|
||||
bugprone-posix-return,
|
||||
bugprone-redundant-branch-condition,
|
||||
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,
|
||||
bugprone-spuriously-wake-up-functions,
|
||||
bugprone-standalone-empty,
|
||||
bugprone-string-constructor,
|
||||
bugprone-string-integer-assignment,
|
||||
bugprone-string-literal-with-embedded-nul,
|
||||
bugprone-stringview-nullptr,
|
||||
bugprone-suspicious-enum-usage,
|
||||
bugprone-suspicious-include,
|
||||
bugprone-suspicious-memory-comparison,
|
||||
bugprone-suspicious-memset-usage,
|
||||
bugprone-suspicious-missing-comma,
|
||||
bugprone-suspicious-realloc-usage,
|
||||
bugprone-suspicious-semicolon,
|
||||
bugprone-suspicious-string-compare,
|
||||
bugprone-suspicious-stringview-data-usage,
|
||||
bugprone-swapped-arguments,
|
||||
bugprone-switch-missing-default-case,
|
||||
bugprone-terminating-continue,
|
||||
bugprone-throw-keyword-missing,
|
||||
bugprone-too-small-loop-variable,
|
||||
bugprone-unchecked-optional-access,
|
||||
bugprone-undefined-memory-manipulation,
|
||||
bugprone-undelegated-constructor,
|
||||
bugprone-unhandled-exception-at-new,
|
||||
bugprone-unhandled-self-assignment,
|
||||
bugprone-unique-ptr-array-mismatch,
|
||||
bugprone-unsafe-functions,
|
||||
bugprone-unused-local-non-trivial-variable,
|
||||
bugprone-unused-raii,
|
||||
bugprone-unused-return-value,
|
||||
bugprone-use-after-move,
|
||||
bugprone-virtual-near-miss,
|
||||
cppcoreguidelines-init-variables,
|
||||
cppcoreguidelines-misleading-capture-default-by-value,
|
||||
cppcoreguidelines-no-suspend-with-lock,
|
||||
cppcoreguidelines-pro-type-member-init,
|
||||
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||
cppcoreguidelines-rvalue-reference-param-not-moved,
|
||||
cppcoreguidelines-use-default-member-init,
|
||||
cppcoreguidelines-use-enum-class,
|
||||
cppcoreguidelines-virtual-class-destructor,
|
||||
hicpp-ignored-remove-result,
|
||||
llvm-namespace-comment,
|
||||
|
||||
misc-*,
|
||||
-misc-anonymous-namespace-in-header,
|
||||
-misc-confusable-identifiers,
|
||||
-misc-coroutine-hostile-raii,
|
||||
-misc-misleading-bidirectional,
|
||||
-misc-misleading-identifier,
|
||||
-misc-multiple-inheritance,
|
||||
-misc-new-delete-overloads,
|
||||
-misc-no-recursion,
|
||||
-misc-non-copyable-objects,
|
||||
-misc-non-private-member-variables-in-classes,
|
||||
-misc-override-with-different-visibility,
|
||||
-misc-predictable-rand,
|
||||
-misc-unconventional-assign-operator,
|
||||
-misc-uniqueptr-reset-release,
|
||||
-misc-unused-parameters,
|
||||
-misc-use-anonymous-namespace,
|
||||
-misc-use-internal-linkage,
|
||||
|
||||
modernize-*,
|
||||
-modernize-avoid-bind,
|
||||
-modernize-avoid-c-arrays,
|
||||
-modernize-avoid-c-style-cast,
|
||||
-modernize-avoid-setjmp-longjmp,
|
||||
-modernize-avoid-variadic-functions,
|
||||
-modernize-deprecated-ios-base-aliases,
|
||||
-modernize-loop-convert,
|
||||
-modernize-macro-to-enum,
|
||||
-modernize-min-max-use-initializer-list,
|
||||
-modernize-raw-string-literal,
|
||||
-modernize-redundant-void-arg,
|
||||
-modernize-replace-auto-ptr,
|
||||
-modernize-replace-disallow-copy-and-assign-macro,
|
||||
-modernize-replace-random-shuffle,
|
||||
-modernize-return-braced-init-list,
|
||||
-modernize-shrink-to-fit,
|
||||
-modernize-unary-static-assert,
|
||||
-modernize-use-auto,
|
||||
-modernize-use-bool-literals,
|
||||
-modernize-use-constraints,
|
||||
-modernize-use-default-member-init,
|
||||
-modernize-use-integer-sign-comparison,
|
||||
-modernize-use-noexcept,
|
||||
-modernize-use-nullptr,
|
||||
-modernize-use-std-format,
|
||||
-modernize-use-std-print,
|
||||
-modernize-use-trailing-return-type,
|
||||
-modernize-use-transparent-functors,
|
||||
-modernize-use-uncaught-exceptions,
|
||||
|
||||
performance-*,
|
||||
-performance-avoid-endl,
|
||||
-performance-enum-size,
|
||||
-performance-inefficient-algorithm,
|
||||
-performance-inefficient-string-concatenation,
|
||||
-performance-no-int-to-ptr,
|
||||
-performance-noexcept-destructor,
|
||||
-performance-noexcept-move-constructor,
|
||||
-performance-noexcept-swap,
|
||||
-performance-type-promotion-in-math-fn,
|
||||
-performance-unnecessary-copy-initialization,
|
||||
-performance-unnecessary-value-param,
|
||||
|
||||
readability-*,
|
||||
-readability-avoid-const-params-in-decls,
|
||||
-readability-avoid-unconditional-preprocessor-if,
|
||||
-readability-container-data-pointer,
|
||||
-readability-delete-null-pointer,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-function-size,
|
||||
-readability-identifier-length,
|
||||
-readability-inconsistent-declaration-parameter-name,
|
||||
-readability-isolate-declaration,
|
||||
-readability-magic-numbers,
|
||||
-readability-misplaced-array-index,
|
||||
-readability-named-parameter,
|
||||
-readability-operators-representation,
|
||||
-readability-qualified-auto,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-redundant-control-flow,
|
||||
-readability-redundant-function-ptr-dereference,
|
||||
-readability-redundant-preprocessor,
|
||||
-readability-redundant-smartptr-get,
|
||||
-readability-redundant-string-cstr,
|
||||
-readability-simplify-subscript-expr,
|
||||
-readability-static-accessed-through-instance,
|
||||
-readability-string-compare,
|
||||
-readability-uniqueptr-delete-release,
|
||||
-readability-uppercase-literal-suffix,
|
||||
-readability-use-anyofallof,
|
||||
-readability-use-concise-preprocessor-directives
|
||||
misc-const-correctness,
|
||||
misc-definitions-in-headers,
|
||||
misc-header-include-cycle,
|
||||
misc-include-cleaner,
|
||||
misc-misplaced-const,
|
||||
misc-redundant-expression,
|
||||
misc-static-assert,
|
||||
misc-throw-by-value-catch-by-reference,
|
||||
misc-unused-alias-decls,
|
||||
misc-unused-using-decls,
|
||||
modernize-concat-nested-namespaces,
|
||||
modernize-deprecated-headers,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
modernize-pass-by-value,
|
||||
modernize-type-traits,
|
||||
modernize-use-designated-initializers,
|
||||
modernize-use-emplace,
|
||||
modernize-use-equals-default,
|
||||
modernize-use-equals-delete,
|
||||
modernize-use-nodiscard,
|
||||
modernize-use-override,
|
||||
modernize-use-ranges,
|
||||
modernize-use-scoped-lock,
|
||||
modernize-use-starts-ends-with,
|
||||
modernize-use-std-numbers,
|
||||
modernize-use-using,
|
||||
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-ambiguous-smartptr-reset-call,
|
||||
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-convert-member-functions-to-static,
|
||||
readability-duplicate-include,
|
||||
readability-else-after-return,
|
||||
readability-enum-initial-value,
|
||||
readability-identifier-naming,
|
||||
readability-implicit-bool-conversion,
|
||||
readability-inconsistent-ifelse-braces,
|
||||
readability-make-member-function-const,
|
||||
readability-math-missing-parentheses,
|
||||
readability-misleading-indentation,
|
||||
readability-non-const-parameter,
|
||||
readability-redundant-casting,
|
||||
readability-redundant-declaration,
|
||||
readability-redundant-inline-specifier,
|
||||
readability-redundant-member-init,
|
||||
readability-redundant-parentheses,
|
||||
readability-redundant-string-init,
|
||||
readability-redundant-typename,
|
||||
readability-reference-to-constructed-temporary,
|
||||
readability-simplify-boolean-expr,
|
||||
readability-static-definition-in-anonymous-namespace,
|
||||
readability-suspicious-call-argument,
|
||||
readability-use-std-min-max
|
||||
"
|
||||
# ---
|
||||
# bugprone-narrowing-conversions, # This will break a lot of code but we should enable it in the future because it can eliminate a lot of bugs
|
||||
|
||||
2
.github/actions/setup-conan/action.yml
vendored
2
.github/actions/setup-conan/action.yml
vendored
@@ -9,7 +9,7 @@ inputs:
|
||||
remote_url:
|
||||
description: "The URL of the Conan endpoint to use."
|
||||
required: false
|
||||
default: https://conan.xrplf.org/repository/conan/
|
||||
default: https://conan.ripplex.io
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
|
||||
2
.github/scripts/strategy-matrix/macos.json
vendored
2
.github/scripts/strategy-matrix/macos.json
vendored
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"platform": "macos/arm64",
|
||||
"runner": ["self-hosted", "macOS", "ARM64", "macos-26-apple-clang-21"],
|
||||
"runner": ["self-hosted", "macOS", "ARM64", "mac-runner-m1"],
|
||||
"configs": [
|
||||
{
|
||||
"build_type": "Release",
|
||||
|
||||
5
.github/workflows/on-pr.yml
vendored
5
.github/workflows/on-pr.yml
vendored
@@ -122,6 +122,7 @@ jobs:
|
||||
issues: write
|
||||
contents: read
|
||||
with:
|
||||
check_only_changed: true
|
||||
create_issue_on_failure: false
|
||||
|
||||
build-test:
|
||||
@@ -153,8 +154,8 @@ jobs:
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && needs.should-run.outputs.go == 'true' && github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release') }}
|
||||
uses: ./.github/workflows/reusable-upload-recipe.yml
|
||||
secrets:
|
||||
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
|
||||
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
|
||||
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
|
||||
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
|
||||
|
||||
notify-clio:
|
||||
needs: upload-recipe
|
||||
|
||||
4
.github/workflows/on-tag.yml
vendored
4
.github/workflows/on-tag.yml
vendored
@@ -20,8 +20,8 @@ jobs:
|
||||
if: ${{ github.repository == 'XRPLF/rippled' }}
|
||||
uses: ./.github/workflows/reusable-upload-recipe.yml
|
||||
secrets:
|
||||
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
|
||||
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
|
||||
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
|
||||
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
|
||||
|
||||
build-test:
|
||||
if: ${{ github.repository == 'XRPLF/rippled' }}
|
||||
|
||||
5
.github/workflows/on-trigger.yml
vendored
5
.github/workflows/on-trigger.yml
vendored
@@ -72,6 +72,7 @@ jobs:
|
||||
issues: write
|
||||
contents: read
|
||||
with:
|
||||
check_only_changed: false
|
||||
create_issue_on_failure: ${{ github.event_name == 'schedule' }}
|
||||
|
||||
build-test:
|
||||
@@ -97,8 +98,8 @@ jobs:
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
|
||||
uses: ./.github/workflows/reusable-upload-recipe.yml
|
||||
secrets:
|
||||
remote_username: ${{ secrets.NEXUS_REMOTE_USERNAME }}
|
||||
remote_password: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
|
||||
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
|
||||
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
|
||||
|
||||
package:
|
||||
needs: build-test
|
||||
|
||||
2
.github/workflows/publish-docs.yml
vendored
2
.github/workflows/publish-docs.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@9355d190fd7d4de80fadfd161e6edddc9702cd9f
|
||||
uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
|
||||
23
.github/workflows/reusable-build-test-config.yml
vendored
23
.github/workflows/reusable-build-test-config.yml
vendored
@@ -113,7 +113,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@9355d190fd7d4de80fadfd161e6edddc9702cd9f
|
||||
uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
|
||||
with:
|
||||
enable_ccache: ${{ inputs.ccache_enabled }}
|
||||
|
||||
@@ -227,7 +227,8 @@ jobs:
|
||||
--build . \
|
||||
--config "${BUILD_TYPE}" \
|
||||
--parallel "${BUILD_NPROC}" \
|
||||
--target "${CMAKE_TARGET}"
|
||||
--target "${CMAKE_TARGET}" \
|
||||
2>&1 | tee build.log
|
||||
|
||||
- name: Show ccache statistics
|
||||
if: ${{ inputs.ccache_enabled }}
|
||||
@@ -325,7 +326,7 @@ jobs:
|
||||
LD_PRELOAD="$PRELOAD" ./xrpld --unittest --unittest-jobs "${BUILD_NPROC}" 2>&1 | tee unittest.log
|
||||
|
||||
- name: Show test failure summary
|
||||
if: ${{ failure() && !inputs.build_only }}
|
||||
if: ${{ failure() }}
|
||||
env:
|
||||
WORKING_DIR: ${{ runner.os == 'Windows' && format('{0}\{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
|
||||
run: |
|
||||
@@ -336,13 +337,17 @@ jobs:
|
||||
|
||||
cd "${WORKING_DIR}"
|
||||
|
||||
if [ ! -f unittest.log ]; then
|
||||
if [ -f unittest.log ]; then
|
||||
if ! grep -E "failed" unittest.log | grep -vE "^I[0-9]|^[0-9]+> (ERR:|FTL:)"; then
|
||||
echo "unittest.log present but no failure lines found."
|
||||
fi
|
||||
else
|
||||
echo "unittest.log not found; embedded tests may not have run."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! grep -E "failed" unittest.log; then
|
||||
echo "Log present but no failure lines found in unittest.log."
|
||||
if [ -f build.log ]; then
|
||||
if ! grep -E "error:" build.log; then
|
||||
echo "build.log present but no compile errors found."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
- name: Debug failure (Linux)
|
||||
if: ${{ failure() && runner.os == 'Linux' && !inputs.build_only }}
|
||||
|
||||
23
.github/workflows/reusable-clang-tidy.yml
vendored
23
.github/workflows/reusable-clang-tidy.yml
vendored
@@ -3,6 +3,10 @@ name: Run clang-tidy on files
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
check_only_changed:
|
||||
description: "Check only changed files in PR. If false, checks all files in the repository."
|
||||
type: boolean
|
||||
default: false
|
||||
create_issue_on_failure:
|
||||
description: "Whether to create an issue if the check failed"
|
||||
type: boolean
|
||||
@@ -25,14 +29,15 @@ env:
|
||||
|
||||
jobs:
|
||||
determine-files:
|
||||
if: ${{ inputs.check_only_changed }}
|
||||
permissions:
|
||||
contents: read
|
||||
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@d041ac9f1fa9f07a4ba335eb4c1c82233fb3fef6
|
||||
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@c7045074aafe9fb92fa537aa4446f81fbfc17e8b
|
||||
|
||||
run-clang-tidy:
|
||||
name: Run clang tidy
|
||||
needs: [determine-files]
|
||||
if: ${{ needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.need_full_run == 'true' }}
|
||||
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: "ghcr.io/xrplf/xrpld/nix-debian:sha-e29b523"
|
||||
permissions:
|
||||
@@ -43,7 +48,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@9355d190fd7d4de80fadfd161e6edddc9702cd9f
|
||||
uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
@@ -91,15 +96,15 @@ jobs:
|
||||
id: run_clang_tidy
|
||||
continue-on-error: true
|
||||
env:
|
||||
TARGETS: ${{ needs.determine-files.outputs.need_full_run != 'true' && needs.determine-files.outputs.cpp_changed_files || 'src tests' }}
|
||||
TARGETS: ${{ (needs.determine-files.outputs.clang_tidy_config_changed != 'true' && inputs.check_only_changed) && needs.determine-files.outputs.cpp_changed_files || 'src tests' }}
|
||||
run: |
|
||||
set -o pipefail
|
||||
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -fix -allow-no-checks ${TARGETS} 2>&1 | tee "${OUTPUT_FILE}"
|
||||
|
||||
- name: Print filtered clang-tidy errors
|
||||
- name: Print errors
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
bin/filter-clang-tidy.py "${OUTPUT_FILE}"
|
||||
sed '/error\||/!d' "${OUTPUT_FILE}"
|
||||
|
||||
- name: Upload clang-tidy output
|
||||
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
|
||||
@@ -143,12 +148,12 @@ jobs:
|
||||
\`\`\`
|
||||
EOF
|
||||
|
||||
- name: Append filtered clang-tidy output to issue body
|
||||
- name: Append clang-tidy output to issue body (filter for errors and warnings)
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
if [ -f "${OUTPUT_FILE}" ]; then
|
||||
# Filter to the unique errors with their source context.
|
||||
bin/filter-clang-tidy.py "${OUTPUT_FILE}" >"${FILTERED_OUTPUT_FILE}" || true
|
||||
# Extract lines containing 'error:', 'warning:', or 'note:'
|
||||
grep -E '(error:|warning:|note:)' "${OUTPUT_FILE}" >"${FILTERED_OUTPUT_FILE}" || true
|
||||
|
||||
# If filtered output is empty, use original (might be a different error format)
|
||||
if [ ! -s "${FILTERED_OUTPUT_FILE}" ]; then
|
||||
|
||||
20
.github/workflows/reusable-upload-recipe.yml
vendored
20
.github/workflows/reusable-upload-recipe.yml
vendored
@@ -14,7 +14,7 @@ on:
|
||||
description: "The URL of the Conan endpoint to use."
|
||||
required: false
|
||||
type: string
|
||||
default: https://conan.xrplf.org/repository/conan/
|
||||
default: https://conan.ripplex.io
|
||||
|
||||
secrets:
|
||||
remote_username:
|
||||
@@ -41,10 +41,6 @@ jobs:
|
||||
upload:
|
||||
runs-on: ubuntu-latest
|
||||
container: ghcr.io/xrplf/xrpld/nix-ubuntu:sha-e29b523
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.remote_username }}
|
||||
CONAN_PASSWORD_XRPLF: ${{ secrets.remote_password }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
@@ -60,9 +56,15 @@ jobs:
|
||||
remote_url: ${{ inputs.remote_url }}
|
||||
|
||||
- name: Log into Conan remote
|
||||
run: conan remote login "${REMOTE_NAME}" "${CONAN_LOGIN_USERNAME_XRPLF}" --password "${CONAN_PASSWORD_XRPLF}"
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
REMOTE_USERNAME: ${{ secrets.remote_username }}
|
||||
REMOTE_PASSWORD: ${{ secrets.remote_password }}
|
||||
run: conan remote login "${REMOTE_NAME}" "${REMOTE_USERNAME}" --password "${REMOTE_PASSWORD}"
|
||||
|
||||
- name: Upload Conan recipe (version)
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
run: |
|
||||
conan export . --version=${{ steps.version.outputs.version }}
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.version.outputs.version }}
|
||||
@@ -71,6 +73,8 @@ jobs:
|
||||
# 'develop' branch, see on-trigger.yml.
|
||||
- name: Upload Conan recipe (develop)
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
run: |
|
||||
conan export . --version=develop
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/develop
|
||||
@@ -79,6 +83,8 @@ jobs:
|
||||
# one of the 'release' branches, see on-pr.yml.
|
||||
- name: Upload Conan recipe (rc)
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
run: |
|
||||
conan export . --version=rc
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/rc
|
||||
@@ -87,6 +93,8 @@ jobs:
|
||||
# release, see on-tag.yml.
|
||||
- name: Upload Conan recipe (release)
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
run: |
|
||||
conan export . --version=release
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/release
|
||||
|
||||
8
.github/workflows/upload-conan-deps.yml
vendored
8
.github/workflows/upload-conan-deps.yml
vendored
@@ -34,7 +34,7 @@ on:
|
||||
|
||||
env:
|
||||
CONAN_REMOTE_NAME: xrplf
|
||||
CONAN_REMOTE_URL: https://conan.xrplf.org/repository/conan/
|
||||
CONAN_REMOTE_URL: https://conan.ripplex.io
|
||||
NPROC_SUBTRACT: 2
|
||||
|
||||
concurrency:
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@9355d190fd7d4de80fadfd161e6edddc9702cd9f
|
||||
uses: XRPLF/actions/prepare-runner@c47daebb2f9db64ffbac71b47d68a661498d5ce8
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
@@ -108,12 +108,10 @@ jobs:
|
||||
|
||||
- name: Log into Conan remote
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
|
||||
run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.NEXUS_REMOTE_USERNAME }}" --password "${{ secrets.NEXUS_REMOTE_PASSWORD }}"
|
||||
run: conan remote login "${CONAN_REMOTE_NAME}" "${{ secrets.CONAN_REMOTE_USERNAME }}" --password "${{ secrets.CONAN_REMOTE_PASSWORD }}"
|
||||
|
||||
- name: Upload Conan packages
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
|
||||
env:
|
||||
FORCE_OPTION: ${{ github.event.inputs.force_upload == 'true' && '--force' || '' }}
|
||||
CONAN_LOGIN_USERNAME_XRPLF: ${{ secrets.NEXUS_REMOTE_USERNAME }}
|
||||
CONAN_PASSWORD_XRPLF: ${{ secrets.NEXUS_REMOTE_PASSWORD }}
|
||||
run: conan upload "*" --remote="${CONAN_REMOTE_NAME}" --confirm ${FORCE_OPTION}
|
||||
|
||||
2
BUILD.md
2
BUILD.md
@@ -101,7 +101,7 @@ More information on customizing Conan can be found in the [Advanced Conan config
|
||||
Run the following command to add the `xrplf` remote, which hosts some of our dependencies:
|
||||
|
||||
```bash
|
||||
conan remote add --index 0 --force xrplf https://conan.xrplf.org/repository/conan/
|
||||
conan remote add --index 0 --force xrplf https://conan.ripplex.io
|
||||
```
|
||||
|
||||
### Set Up Ccache
|
||||
|
||||
@@ -90,7 +90,6 @@ find_package(ed25519 REQUIRED)
|
||||
find_package(gRPC REQUIRED)
|
||||
find_package(LibArchive REQUIRED)
|
||||
find_package(lz4 REQUIRED)
|
||||
find_package(mpt-crypto REQUIRED)
|
||||
find_package(nudb REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(secp256k1 REQUIRED)
|
||||
@@ -103,7 +102,6 @@ target_link_libraries(
|
||||
INTERFACE
|
||||
ed25519::ed25519
|
||||
lz4::lz4
|
||||
mpt-crypto::mpt-crypto
|
||||
OpenSSL::Crypto
|
||||
OpenSSL::SSL
|
||||
secp256k1::secp256k1
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Reduce run-clang-tidy output to its unique errors.
|
||||
|
||||
It does two things:
|
||||
|
||||
1. Filters the raw output down to diagnostics and their source-context lines
|
||||
(the indented " 103 | ..." / " | ^" lines clang-tidy prints),
|
||||
matching the "path:line:col: error:" diagnostic shape.
|
||||
|
||||
2. Deduplicates. The same diagnostic in a header is reported once per
|
||||
translation unit that includes it, so identical error blocks are collapsed
|
||||
to their first occurrence.
|
||||
|
||||
An "error block" is an "error:" line together with the indented context lines
|
||||
and any "note:" lines that follow it (up to the next "error:" line). Blocks are
|
||||
compared as a whole, so an error stays attached to its own context, and
|
||||
first-occurrence order is preserved.
|
||||
|
||||
The deduplicated output goes to stdout; a summary of unique error counts per
|
||||
check is printed to stderr.
|
||||
|
||||
Usage:
|
||||
bin/filter-clang-tidy.py [INPUT_FILE] # read from file, or
|
||||
run-clang-tidy ... | bin/filter-clang-tidy.py # read from stdin
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
from collections import Counter
|
||||
|
||||
# A clang-tidy diagnostic line looks like "path:line:col: error: msg [check]".
|
||||
# Matching on that shape (rather than a loose "error" substring) avoids treating
|
||||
# progress lines whose paths contain "error" as diagnostics, e.g.
|
||||
# [284/850][0.7s] /nix/.../clang-tidy ... src/.../error.cpp
|
||||
DIAG_RE = re.compile(r":\d+:\d+: (?:error|warning|note):")
|
||||
ERROR_RE = re.compile(r":\d+:\d+: error:")
|
||||
CHECK_RE = re.compile(r" error: .*\[([^\],]+)")
|
||||
|
||||
|
||||
def filter_and_dedup(lines: list[str]) -> list[str]:
|
||||
"""Keep diagnostics with their context, then drop duplicate error blocks."""
|
||||
blocks: list[str] = []
|
||||
seen: set[str] = set()
|
||||
current: list[str] = []
|
||||
|
||||
def flush() -> None:
|
||||
if not current:
|
||||
return
|
||||
block = "".join(current)
|
||||
if block not in seen:
|
||||
seen.add(block)
|
||||
blocks.append(block)
|
||||
|
||||
for line in lines:
|
||||
# Keep only diagnostics and their indented source-context lines; drop
|
||||
# progress/status output and blank lines.
|
||||
if not (DIAG_RE.search(line) or line[:1] in (" ", "\t")):
|
||||
continue
|
||||
# An "error:" line starts a new block; its context and any following
|
||||
# "note:" lines (and their context) belong to it.
|
||||
if ERROR_RE.search(line):
|
||||
flush()
|
||||
current = []
|
||||
current.append(line)
|
||||
flush()
|
||||
|
||||
return blocks
|
||||
|
||||
|
||||
def summarize(blocks: list[str]) -> Counter[str]:
|
||||
"""Count unique errors per check name (e.g. "bugprone-branch-clone")."""
|
||||
counts: Counter[str] = Counter()
|
||||
for block in blocks:
|
||||
# The error line is the first line of the block.
|
||||
match = CHECK_RE.search(block.splitlines()[0])
|
||||
if match:
|
||||
counts[match.group(1)] += 1
|
||||
return counts
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if len(sys.argv) > 1 and sys.argv[1] != "-":
|
||||
with open(sys.argv[1], encoding="utf-8") as f:
|
||||
lines = f.readlines()
|
||||
else:
|
||||
lines = sys.stdin.readlines()
|
||||
|
||||
blocks = filter_and_dedup(lines)
|
||||
# Blank line between blocks so distinct errors are easy to tell apart.
|
||||
sys.stdout.write("\n".join(blocks))
|
||||
|
||||
print("\nUnique errors per check:", file=sys.stderr)
|
||||
for check, count in summarize(blocks).most_common():
|
||||
print(f"{count:>4} {check}", file=sys.stderr)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
65
conan.lock
65
conan.lock
@@ -1,44 +1,43 @@
|
||||
{
|
||||
"version": "0.5",
|
||||
"requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
|
||||
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
|
||||
"soci/4.0.3#e726491a03468795453f7c83fc924a96%1782392402.679521",
|
||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1782307151.633168",
|
||||
"secp256k1/0.7.1#b1f450b7f78a36fff75bb6934a356f3a%1782338841.3729",
|
||||
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1782392413.075713",
|
||||
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
|
||||
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
|
||||
"openssl/3.6.3#1163d4ddc603907084d08a6a0c6e580f%1782307150.583886",
|
||||
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1782392402.297166",
|
||||
"mpt-crypto/0.4.0-rc2#a580f2f9ad0e795de696aa62d54fb9af%1782425834.488828",
|
||||
"lz4/1.10.0#982d9b673900f665a1da109e09c17cab%1782392402.164188",
|
||||
"libiconv/1.17#9923bc6dc6f106646d6967e0039a5ada%1782392792.775744",
|
||||
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1782392402.420732",
|
||||
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1782392403.066892",
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1778091116.056",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987",
|
||||
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1778091117.311",
|
||||
"soci/4.0.3#fe32b9ad5eb47e79ab9e45a68f363945%1774450067.231",
|
||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878",
|
||||
"secp256k1/0.7.1#481881709eb0bdd0185a12b912bbe8ad%1770910500.329",
|
||||
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1765850186.86",
|
||||
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1774398111.888",
|
||||
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12",
|
||||
"openssl/3.6.2#4789bbf131b77d0515d15e094c8f697f%1778071755.506",
|
||||
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1775040983.408",
|
||||
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914",
|
||||
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492",
|
||||
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1765842973.03",
|
||||
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1778091117.848",
|
||||
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
|
||||
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1782392402.791979",
|
||||
"grpc/1.81.1#5217e6ef0544c42b46f4af35d5e7f649%1782307148.845616",
|
||||
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1782307148.15562",
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1782392402.538492",
|
||||
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1782392402.681654",
|
||||
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1782392402.296732",
|
||||
"boost/1.91.0#ea540ca2133d831b560036aa24dece3c%1782392419.475605",
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1782307147.395833"
|
||||
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1768312129.152",
|
||||
"grpc/1.81.0#2fb144aeb47e7f35c6ebb0e5f35bed31%1781620605.685",
|
||||
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1765850143.772",
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1765850143.772",
|
||||
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1774439234.681",
|
||||
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1765850143.837",
|
||||
"boost/1.91.0#ea540ca2133d831b560036aa24dece3c%1778091165.282",
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196"
|
||||
],
|
||||
"build_requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1782395692.540639",
|
||||
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
|
||||
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1782395690.33162",
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1778091116.056",
|
||||
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1774447376.964",
|
||||
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12",
|
||||
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1765850144.707",
|
||||
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
|
||||
"m4/1.4.19#34c4bbc3eeebe98ca6edf2f52d602e7d%1777282960.259",
|
||||
"cmake/4.3.3#840cf00ea09777e05c2050a50a82c722%1782392418.696091",
|
||||
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1782392402.624226",
|
||||
"m4/1.4.19#4523e4347b55cd26ae918bd5770cab9a%1778062762.471",
|
||||
"cmake/4.3.0#b939a42e98f593fb34d3a8c5cc860359%1774439249.183",
|
||||
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1774439233.447",
|
||||
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
|
||||
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1782307147.395833"
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196"
|
||||
],
|
||||
"python_requires": [],
|
||||
"overrides": {
|
||||
@@ -58,7 +57,7 @@
|
||||
"boost/1.91.0"
|
||||
],
|
||||
"lz4/[>=1.9.4 <2]": [
|
||||
"lz4/1.10.0#982d9b673900f665a1da109e09c17cab"
|
||||
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504"
|
||||
]
|
||||
},
|
||||
"config_requires": []
|
||||
|
||||
@@ -14,7 +14,7 @@ export CONAN_HOME="$TEMP_DIR"
|
||||
# Ensure that the xrplf remote is the first to be consulted, so any recipes we
|
||||
# patched are used. We also add it there to not created huge diff when the
|
||||
# official Conan Center Index is updated.
|
||||
conan remote add --force --index 0 xrplf https://conan.xrplf.org/repository/conan/
|
||||
conan remote add --force --index 0 xrplf https://conan.ripplex.io
|
||||
|
||||
# Delete any existing lockfile.
|
||||
rm -f conan.lock
|
||||
|
||||
14
conanfile.py
14
conanfile.py
@@ -28,10 +28,11 @@ class Xrpl(ConanFile):
|
||||
|
||||
requires = [
|
||||
"ed25519/2015.03",
|
||||
"grpc/1.81.1",
|
||||
"grpc/1.81.0",
|
||||
"libarchive/3.8.7",
|
||||
"nudb/2.0.9",
|
||||
"openssl/3.6.3",
|
||||
"openssl/3.6.2",
|
||||
"secp256k1/0.7.1",
|
||||
"soci/4.0.3",
|
||||
"zlib/1.3.2",
|
||||
]
|
||||
@@ -131,15 +132,13 @@ class Xrpl(ConanFile):
|
||||
def requirements(self):
|
||||
self.requires("boost/1.91.0", force=True, transitive_headers=True)
|
||||
self.requires("date/3.0.4", transitive_headers=True)
|
||||
self.requires("lz4/1.10.0", force=True)
|
||||
self.requires("protobuf/6.33.5", force=True)
|
||||
self.requires("sqlite3/3.53.0", force=True)
|
||||
if self.options.jemalloc:
|
||||
self.requires("jemalloc/5.3.1")
|
||||
self.requires("lz4/1.10.0", force=True)
|
||||
self.requires("mpt-crypto/0.4.0-rc2", transitive_headers=True)
|
||||
self.requires("protobuf/6.33.5", force=True)
|
||||
if self.options.rocksdb:
|
||||
self.requires("rocksdb/10.5.1")
|
||||
self.requires("secp256k1/0.7.1", transitive_headers=True)
|
||||
self.requires("sqlite3/3.53.0", force=True)
|
||||
self.requires("xxhash/0.8.3", transitive_headers=True)
|
||||
|
||||
exports_sources = (
|
||||
@@ -209,7 +208,6 @@ class Xrpl(ConanFile):
|
||||
"grpc::grpc++",
|
||||
"libarchive::libarchive",
|
||||
"lz4::lz4",
|
||||
"mpt-crypto::mpt-crypto",
|
||||
"nudb::nudb",
|
||||
"openssl::crypto",
|
||||
"protobuf::libprotobuf",
|
||||
|
||||
@@ -60,7 +60,6 @@ words:
|
||||
- autobridging
|
||||
- bimap
|
||||
- bindir
|
||||
- blindings
|
||||
- bookdir
|
||||
- Bougalis
|
||||
- Britto
|
||||
@@ -96,7 +95,6 @@ words:
|
||||
- daria
|
||||
- dcmake
|
||||
- dearmor
|
||||
- decryptor
|
||||
- dedented
|
||||
- deleteme
|
||||
- demultiplexer
|
||||
@@ -108,7 +106,6 @@ words:
|
||||
- distro
|
||||
- doxyfile
|
||||
- dxrpl
|
||||
- elgamal
|
||||
- enabled
|
||||
- enablerepo
|
||||
- endmacro
|
||||
@@ -122,7 +119,6 @@ words:
|
||||
- fmtdur
|
||||
- fsanitize
|
||||
- funclets
|
||||
- Gamal
|
||||
- gcov
|
||||
- gcovr
|
||||
- ghead
|
||||
@@ -220,7 +216,6 @@ words:
|
||||
- partitioner
|
||||
- paychan
|
||||
- paychans
|
||||
- Pedersen
|
||||
- permdex
|
||||
- perminute
|
||||
- permissioned
|
||||
@@ -244,10 +239,6 @@ words:
|
||||
- Raphson
|
||||
- rcflags
|
||||
- replayer
|
||||
- rerandomize
|
||||
- rerandomization
|
||||
- rerandomized
|
||||
- rerandomizes
|
||||
- rerere
|
||||
- retriable
|
||||
- RIPD
|
||||
@@ -264,7 +255,6 @@ words:
|
||||
- sahyadri
|
||||
- Satoshi
|
||||
- scons
|
||||
- Schnorr
|
||||
- secp
|
||||
- sendq
|
||||
- seqit
|
||||
@@ -295,7 +285,6 @@ words:
|
||||
- stvar
|
||||
- stvector
|
||||
- stxchainattestations
|
||||
- summands
|
||||
- superpeer
|
||||
- superpeers
|
||||
- takergets
|
||||
|
||||
2
docs/build/advanced_conan.md
vendored
2
docs/build/advanced_conan.md
vendored
@@ -34,7 +34,7 @@ higher index than the default Conan Center remote, so it is consulted first. You
|
||||
can do this by running:
|
||||
|
||||
```bash
|
||||
conan remote add --index 0 --force xrplf https://conan.xrplf.org/repository/conan/
|
||||
conan remote add --index 0 --force xrplf https://conan.ripplex.io
|
||||
```
|
||||
|
||||
Alternatively, you can pull our recipes from the repository and export them locally:
|
||||
|
||||
@@ -298,8 +298,7 @@ set(T& target, std::string const& name, Section const& section)
|
||||
try
|
||||
{
|
||||
auto const val = section.get<T>(name);
|
||||
foundAndValid = val.has_value();
|
||||
if (foundAndValid)
|
||||
if ((foundAndValid = val.has_value()))
|
||||
target = *val;
|
||||
}
|
||||
catch (boost::bad_lexical_cast const&) // NOLINT(bugprone-empty-catch)
|
||||
|
||||
@@ -19,14 +19,12 @@ enum class HashRouterFlags : std::uint16_t {
|
||||
HELD = 0x08, // Held by LedgerMaster after potential processing failure
|
||||
TRUSTED = 0x10, // Comes from a trusted source
|
||||
|
||||
// Private flags. Each group is owned by one file; do not read, set, or
|
||||
// reuse a flag outside the file noted.
|
||||
// Used in apply.cpp
|
||||
// Private flags (used internally in apply.cpp)
|
||||
// Do not attempt to read, set, or reuse.
|
||||
PRIVATE1 = 0x0100,
|
||||
PRIVATE2 = 0x0200,
|
||||
PRIVATE3 = 0x0400,
|
||||
PRIVATE4 = 0x0800,
|
||||
// Used in EscrowFinish.cpp
|
||||
PRIVATE5 = 0x1000,
|
||||
PRIVATE6 = 0x2000
|
||||
};
|
||||
|
||||
@@ -28,7 +28,7 @@ inline constexpr struct OpenLedgerT
|
||||
/** Batch view construction tag.
|
||||
|
||||
Views constructed with this tag are part of a stack of views
|
||||
used during batch transaction application.
|
||||
used during batch transaction applied.
|
||||
*/
|
||||
inline constexpr struct BatchViewT
|
||||
{
|
||||
|
||||
@@ -63,39 +63,6 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j);
|
||||
TER
|
||||
verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, beast::Journal j);
|
||||
|
||||
/**
|
||||
* @brief Check whether src is authorized to deposit to dst.
|
||||
*
|
||||
* @param tx Transaction containing optional credential IDs.
|
||||
* @param view Read-only ledger view.
|
||||
* @param src Source account.
|
||||
* @param dst Destination account.
|
||||
* @param sleDst Destination AccountRoot, if it exists.
|
||||
* @param j Journal for diagnostics.
|
||||
* @return tesSUCCESS if the deposit is allowed, otherwise an authorization
|
||||
* error.
|
||||
*/
|
||||
TER
|
||||
checkDepositPreauth(
|
||||
STTx const& tx,
|
||||
ReadView const& view,
|
||||
AccountID const& src,
|
||||
AccountID const& dst,
|
||||
std::shared_ptr<SLE const> const& sleDst,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
* @brief Remove expired credentials referenced by the transaction.
|
||||
*
|
||||
* @param tx Transaction containing optional sfCredentialIDs.
|
||||
* @param view Mutable ledger view.
|
||||
* @param j Journal for diagnostics.
|
||||
* @return tesSUCCESS if no referenced credentials expired, tecEXPIRED if any
|
||||
* were removed, or an error from credential deletion.
|
||||
*/
|
||||
TER
|
||||
cleanupExpiredCredentials(STTx const& tx, ApplyView& view, beast::Journal j);
|
||||
|
||||
// Check expired credentials and for existing DepositPreauth ledger object
|
||||
TER
|
||||
verifyDepositPreauth(
|
||||
|
||||
@@ -42,7 +42,7 @@ escrowUnlockApplyHelper<Issue>(
|
||||
beast::Journal journal)
|
||||
{
|
||||
Issue const& issue = amount.get<Issue>();
|
||||
Keylet const trustLineKey = keylet::trustLine(receiver, issue);
|
||||
Keylet const trustLineKey = keylet::line(receiver, issue);
|
||||
bool const recvLow = issuer > receiver;
|
||||
bool const senderIssuer = issuer == sender;
|
||||
bool const receiverIssuer = issuer == receiver;
|
||||
@@ -175,7 +175,7 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
bool const receiverIssuer = issuer == receiver;
|
||||
|
||||
auto const mptID = amount.get<MPTIssue>().getMptID();
|
||||
auto const issuanceKey = keylet::mptokenIssuance(mptID);
|
||||
auto const issuanceKey = keylet::mptIssuance(mptID);
|
||||
if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && createAsset && !receiverIssuer)
|
||||
{
|
||||
if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
|
||||
|
||||
@@ -131,75 +131,6 @@ checkDeepFrozen(ReadView const& view, AccountID const& account, MPTIssue const&
|
||||
[[nodiscard]] TER
|
||||
checkDeepFrozen(ReadView const& view, AccountID const& account, Asset const& asset);
|
||||
|
||||
/**
|
||||
* Checks freeze compliance for withdrawing an asset from a pseudo-account (e.g. Vault, AMM,
|
||||
* LoanBroker) to a destination account.
|
||||
*
|
||||
* Asserts that sourceAcct is a pseudo-account and that submitterAcct and dstAcct are not.
|
||||
*
|
||||
* Issuer exemption: returns tesSUCCESS immediately when dstAcct is the asset issuer — the issuer
|
||||
* can always receive their own token, even when the pool is frozen. Callers that need to block
|
||||
* withdrawals from a frozen pool even for the issuer (e.g. because the pool math cannot handle it)
|
||||
* must check checkFrozen(sourceAcct, asset) separately before calling this function.
|
||||
*
|
||||
* Otherwise checks, in order:
|
||||
* 1. If the asset is globally frozen the remaining checks are redundant.
|
||||
* 2. For MPT shares: The pseudo-account's vault share must not be transitively frozen via its
|
||||
* underlying asset.
|
||||
* 3. The pseudo-account's trustline / MPToken must not be frozen for sending.
|
||||
* 4. Skipped when submitter == dst (self-withdrawal); a regular freeze should not prevent
|
||||
* recovering one's own funds.
|
||||
* 5. The destination must not be deep-frozen (cannot receive under any circumstance).
|
||||
*
|
||||
* For IOUs a regular individual freeze on the withdrawer does NOT block self-withdrawal; only deep
|
||||
* freeze does. For MPTs "locked" is equivalent to deep-frozen, so locked MPT holders are always
|
||||
* blocked.
|
||||
*
|
||||
* @param view Ledger view to read freeze state from.
|
||||
* @param srcAcct Pseudo-account the funds are withdrawn from (sender).
|
||||
* @param submitterAcct Account that submitted the withdrawal transaction.
|
||||
* @param dstAcct Account receiving the withdrawn funds.
|
||||
* @param asset Asset being withdrawn.
|
||||
* @return tesSUCCESS if the withdrawal is permitted, otherwise a freeze
|
||||
* result (tecFROZEN for IOUs, tecLOCKED for MPTs).
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkWithdrawFreeze(
|
||||
ReadView const& view,
|
||||
AccountID const& srcAcct,
|
||||
AccountID const& submitterAcct,
|
||||
AccountID const& dstAcct,
|
||||
Asset const& asset);
|
||||
|
||||
/**
|
||||
* Checks freeze compliance for depositing an asset into a pseudo-account (e.g. Vault, AMM,
|
||||
* LoanBroker).
|
||||
*
|
||||
*
|
||||
* Checks, in order:
|
||||
* 1. If the asset is globally frozen the remaining checks are redundant.
|
||||
* 2. For MPT shares: the pseudo-account's vault share must not be transitively frozen via its
|
||||
* underlying asset (returns tecLOCKED).
|
||||
* 3. The depositor must not be individually frozen. Skipped when srcAcct is the asset issuer,
|
||||
* since the issuer can always send its own asset.
|
||||
* 4. The pseudo-account must not be individually frozen for the asset. Unlike regular accounts,
|
||||
* pseudo-accounts cannot receive deposits under a regular freeze because the deposited funds
|
||||
* could not later be withdrawn.
|
||||
*
|
||||
* @param view Ledger view to read freeze state from.
|
||||
* @param srcAcct Depositor sending the funds.
|
||||
* @param dstAcct Pseudo-account receiving the deposit.
|
||||
* @param asset Asset being deposited.
|
||||
* @return tesSUCCESS if the deposit is permitted, otherwise a freeze result
|
||||
* (tecFROZEN for IOUs, tecLOCKED for MPTs).
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkDepositFreeze(
|
||||
ReadView const& view,
|
||||
AccountID const& srcAcct,
|
||||
AccountID const& dstAcct,
|
||||
Asset const& asset);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Account balance functions (Asset-based dispatchers)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
@@ -8,16 +7,9 @@
|
||||
namespace xrpl {
|
||||
|
||||
inline void
|
||||
serializeBatch(
|
||||
Serializer& msg,
|
||||
AccountID const& outerAccount,
|
||||
std::uint32_t outerSeqValue,
|
||||
std::uint32_t const& flags,
|
||||
std::vector<uint256> const& txids)
|
||||
serializeBatch(Serializer& msg, std::uint32_t const& flags, std::vector<uint256> const& txids)
|
||||
{
|
||||
msg.add32(HashPrefix::Batch);
|
||||
msg.addBitString(outerAccount);
|
||||
msg.add32(outerSeqValue);
|
||||
msg.add32(flags);
|
||||
msg.add32(std::uint32_t(txids.size()));
|
||||
for (auto const& txid : txids)
|
||||
|
||||
@@ -1,431 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.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/STObject.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
#include <xrpl/protocol/detail/secp256k1.h>
|
||||
|
||||
#include <secp256k1_mpt.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Bundles an ElGamal public key with its associated encrypted amount.
|
||||
*
|
||||
* Used to represent a recipient in confidential transfers, containing both
|
||||
* the recipient's ElGamal public key and the ciphertext encrypting the
|
||||
* transfer amount under that key.
|
||||
*/
|
||||
struct ConfidentialRecipient
|
||||
{
|
||||
/** @brief The recipient's ElGamal public key (size=xrpl::kEcPubKeyLength). */
|
||||
Slice publicKey;
|
||||
|
||||
/**
|
||||
* @brief The encrypted amount ciphertext
|
||||
* (size=xrpl::kEcGamalEncryptedTotalLength).
|
||||
*/
|
||||
Slice encryptedAmount;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Holds two secp256k1 public key components representing an ElGamal
|
||||
* ciphertext (C1, C2).
|
||||
*/
|
||||
struct EcPair
|
||||
{
|
||||
/** @brief First ElGamal ciphertext component. */
|
||||
secp256k1_pubkey c1;
|
||||
|
||||
/** @brief Second ElGamal ciphertext component. */
|
||||
secp256k1_pubkey c2;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Increments the confidential balance version counter on an MPToken.
|
||||
*
|
||||
* The version counter is used to prevent replay attacks by binding proofs
|
||||
* to a specific state of the account's confidential balance. Wraps to 0
|
||||
* on overflow (defined behavior for unsigned integers).
|
||||
*
|
||||
* @param mptoken The MPToken ledger entry to update.
|
||||
*/
|
||||
inline void
|
||||
incrementConfidentialVersion(STObject& mptoken)
|
||||
{
|
||||
// Retrieve current version and increment, wrapping back to 0 at UINT32_MAX.
|
||||
// The wrap is computed explicitly rather than relying on unsigned overflow
|
||||
// of `+ 1u`, as it trips the unsigned-integer-overflow sanitizer in the UBSan CI build.
|
||||
auto const current = mptoken[~sfConfidentialBalanceVersion].valueOr(0u);
|
||||
mptoken[sfConfidentialBalanceVersion] =
|
||||
current == std::numeric_limits<std::uint32_t>::max() ? 0u : current + 1u;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates the context hash for ConfidentialMPTSend transactions.
|
||||
*
|
||||
* Creates a unique 256-bit hash that binds the zero-knowledge proofs to
|
||||
* this specific send transaction, preventing proof reuse across transactions.
|
||||
*
|
||||
* @param account The sender's account ID.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param sequence The transaction sequence number or ticket number.
|
||||
* @param destination The destination account ID.
|
||||
* @param version The sender's confidential balance version.
|
||||
* @return A 256-bit context hash unique to this transaction.
|
||||
*/
|
||||
uint256
|
||||
getSendContextHash(
|
||||
AccountID const& account,
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence,
|
||||
AccountID const& destination,
|
||||
std::uint32_t version);
|
||||
|
||||
/**
|
||||
* @brief Generates the context hash for ConfidentialMPTClawback transactions.
|
||||
*
|
||||
* Creates a unique 256-bit hash that binds the equality proof to this
|
||||
* specific clawback transaction.
|
||||
*
|
||||
* @param account The issuer's account ID.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param sequence The transaction sequence number or ticket number.
|
||||
* @param holder The holder's account ID being clawed back from.
|
||||
* @return A 256-bit context hash unique to this transaction.
|
||||
*/
|
||||
uint256
|
||||
getClawbackContextHash(
|
||||
AccountID const& account,
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence,
|
||||
AccountID const& holder);
|
||||
|
||||
/**
|
||||
* @brief Generates the context hash for ConfidentialMPTConvert transactions.
|
||||
*
|
||||
* Creates a unique 256-bit hash that binds the Schnorr proof (for key
|
||||
* registration) to this specific convert transaction.
|
||||
*
|
||||
* @param account The holder's account ID.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param sequence The transaction sequence number or a ticket number.
|
||||
* @return A 256-bit context hash unique to this transaction.
|
||||
*/
|
||||
uint256
|
||||
getConvertContextHash(AccountID const& account, uint192 const& issuanceID, std::uint32_t sequence);
|
||||
|
||||
/**
|
||||
* @brief Generates the context hash for ConfidentialMPTConvertBack transactions.
|
||||
*
|
||||
* Creates a unique 256-bit hash that binds the zero-knowledge proofs to
|
||||
* this specific convert-back transaction.
|
||||
*
|
||||
* @param account The holder's account ID.
|
||||
* @param issuanceID The MPToken Issuance ID.
|
||||
* @param sequence The transaction sequence number or a ticket number.
|
||||
* @param version The holder's confidential balance version.
|
||||
* @return A 256-bit context hash unique to this transaction.
|
||||
*/
|
||||
uint256
|
||||
getConvertBackContextHash(
|
||||
AccountID const& account,
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence,
|
||||
std::uint32_t version);
|
||||
|
||||
/**
|
||||
* @brief Parses an ElGamal ciphertext into two secp256k1 public key components.
|
||||
*
|
||||
* Breaks an encrypted amount (size=xrpl::kEcGamalEncryptedTotalLength, two
|
||||
* compressed EC points of size=xrpl::kEcCiphertextComponentLength) into
|
||||
* a pair containing (C1, C2) for use in cryptographic operations.
|
||||
*
|
||||
* @param buffer The buffer containing the compressed ciphertext
|
||||
* (size=xrpl::kEcGamalEncryptedTotalLength).
|
||||
* @return The parsed pair (c1, c2) if successful, std::nullopt if the buffer is invalid.
|
||||
*/
|
||||
std::optional<EcPair>
|
||||
makeEcPair(Slice const& buffer);
|
||||
|
||||
/**
|
||||
* @brief Serializes an EcPair into compressed form.
|
||||
*
|
||||
* Converts an EcPair (C1, C2) back into a buffer
|
||||
* (size=xrpl::kEcGamalEncryptedTotalLength) containing two compressed EC
|
||||
* points (size=xrpl::kEcCiphertextComponentLength each).
|
||||
*
|
||||
* @param pair The EcPair to serialize.
|
||||
* @return The buffer (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt
|
||||
* if serialization fails.
|
||||
*/
|
||||
std::optional<Buffer>
|
||||
serializeEcPair(EcPair const& pair);
|
||||
|
||||
/**
|
||||
* @brief Verifies that a buffer contains two valid, parsable EC public keys.
|
||||
*
|
||||
* @param buffer The input buffer containing two concatenated components.
|
||||
* @return true if both components can be parsed successfully, false otherwise.
|
||||
*/
|
||||
bool
|
||||
isValidCiphertext(Slice const& buffer);
|
||||
|
||||
/**
|
||||
* @brief Verifies that a buffer contains a valid, parsable compressed EC point.
|
||||
*
|
||||
* Can be used to validate both compressed public keys and Pedersen commitments.
|
||||
* Fails early if the prefix byte is not 0x02 or 0x03.
|
||||
*
|
||||
* @param buffer The input buffer containing a compressed EC point
|
||||
* (size=xrpl::kCompressedEcPointLength).
|
||||
* @return true if the point can be parsed successfully, false otherwise.
|
||||
*/
|
||||
bool
|
||||
isValidCompressedECPoint(Slice const& buffer);
|
||||
|
||||
/**
|
||||
* @brief Homomorphically adds two ElGamal ciphertexts.
|
||||
*
|
||||
* Uses the additive homomorphic property of ElGamal encryption to compute
|
||||
* Enc(a + b) from Enc(a) and Enc(b) without decryption.
|
||||
*
|
||||
* @param a The first ciphertext (size=xrpl::kEcGamalEncryptedTotalLength).
|
||||
* @param b The second ciphertext (size=xrpl::kEcGamalEncryptedTotalLength).
|
||||
* @return The resulting ciphertext Enc(a + b), or std::nullopt on failure.
|
||||
*/
|
||||
std::optional<Buffer>
|
||||
homomorphicAdd(Slice const& a, Slice const& b);
|
||||
|
||||
/**
|
||||
* @brief Homomorphically subtracts two ElGamal ciphertexts.
|
||||
*
|
||||
* Uses the additive homomorphic property of ElGamal encryption to compute
|
||||
* Enc(a - b) from Enc(a) and Enc(b) without decryption.
|
||||
*
|
||||
* @param a The minuend ciphertext (size=xrpl::kEcGamalEncryptedTotalLength).
|
||||
* @param b The subtrahend ciphertext (size=xrpl::kEcGamalEncryptedTotalLength).
|
||||
* @return The resulting ciphertext Enc(a - b), or std::nullopt on failure.
|
||||
*/
|
||||
std::optional<Buffer>
|
||||
homomorphicSubtract(Slice const& a, Slice const& b);
|
||||
|
||||
/**
|
||||
* @brief Re-randomizes an ElGamal ciphertext without changing its plaintext.
|
||||
*
|
||||
* Adds Enc(0; randomness) under the supplied public key to the ciphertext.
|
||||
* This is used when a public, deterministic scalar must perturb ciphertext
|
||||
* randomness while preserving ledger reproducibility.
|
||||
*
|
||||
* @param ciphertext The ciphertext to re-randomize
|
||||
* (size=xrpl::kEcGamalEncryptedTotalLength).
|
||||
* @param pubKeySlice The ElGamal public key matching the ciphertext recipient.
|
||||
* @param randomness The scalar used as zero-encryption randomness
|
||||
* (size=xrpl::kEcScalarLength).
|
||||
* @return The re-randomized ciphertext, or std::nullopt on failure.
|
||||
*/
|
||||
std::optional<Buffer>
|
||||
rerandomizeCiphertext(Slice const& ciphertext, Slice const& pubKeySlice, Slice const& randomness);
|
||||
|
||||
/**
|
||||
* @brief Encrypts an amount using ElGamal encryption.
|
||||
*
|
||||
* Produces a ciphertext C = (C1, C2) where C1 = r*G and C2 = m*G + r*Pk,
|
||||
* using the provided blinding factor r.
|
||||
*
|
||||
* @param amt The plaintext amount to encrypt.
|
||||
* @param pubKeySlice The recipient's ElGamal public key (size=xrpl::kEcPubKeyLength).
|
||||
* @param blindingFactor The randomness used as blinding factor r
|
||||
* (size=xrpl::ecBlindingFactorLength).
|
||||
* @return The ciphertext (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt on failure.
|
||||
*/
|
||||
std::optional<Buffer>
|
||||
encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindingFactor);
|
||||
|
||||
/**
|
||||
* @brief Generates the canonical zero encryption for a specific MPToken.
|
||||
*
|
||||
* Creates a deterministic encryption of zero that is unique to the account
|
||||
* and MPT issuance. Used to initialize confidential balance fields.
|
||||
*
|
||||
* @param pubKeySlice The holder's ElGamal public key (size=xrpl::kEcPubKeyLength).
|
||||
* @param account The account ID of the token holder.
|
||||
* @param mptId The MPToken Issuance ID.
|
||||
* @return The canonical zero ciphertext (size=xrpl::kEcGamalEncryptedTotalLength), or std::nullopt
|
||||
* on failure.
|
||||
*/
|
||||
std::optional<Buffer>
|
||||
encryptCanonicalZeroAmount(Slice const& pubKeySlice, AccountID const& account, MPTID const& mptId);
|
||||
|
||||
/**
|
||||
* @brief Verifies a Schnorr proof of knowledge of an ElGamal private key.
|
||||
*
|
||||
* Proves that the submitter knows the secret key corresponding to the
|
||||
* provided public key, without revealing the secret key itself.
|
||||
*
|
||||
* @param pubKeySlice The ElGamal public key (size=xrpl::kEcPubKeyLength).
|
||||
* @param proofSlice The Schnorr proof (size=xrpl::ecSchnorrProofLength).
|
||||
* @param contextHash The 256-bit context hash binding the proof.
|
||||
* @return tesSUCCESS if valid, or an error code otherwise.
|
||||
*/
|
||||
TER
|
||||
verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 const& contextHash);
|
||||
|
||||
/**
|
||||
* @brief Validates the format of encrypted amount fields in a transaction.
|
||||
*
|
||||
* Checks that all ciphertext fields in the transaction object have the
|
||||
* correct length and contain valid EC points. This function is only used
|
||||
* by ConfidentialMPTConvert and ConfidentialMPTConvertBack transactions.
|
||||
*
|
||||
* @param object The transaction object containing encrypted amount fields.
|
||||
* @return tesSUCCESS if all formats are valid, temMALFORMED if required fields
|
||||
* are missing, or temBAD_CIPHERTEXT if format validation fails.
|
||||
*/
|
||||
NotTEC
|
||||
checkEncryptedAmountFormat(STObject const& object);
|
||||
|
||||
/**
|
||||
* @brief Verifies revealed amount encryptions for all recipients.
|
||||
*
|
||||
* Validates that the same amount was correctly encrypted for the holder,
|
||||
* issuer, and optionally the auditor using their respective public keys.
|
||||
*
|
||||
* @param amount The revealed plaintext amount.
|
||||
* @param blindingFactor The blinding factor used in all encryptions
|
||||
* (size=xrpl::ecBlindingFactorLength).
|
||||
* @param holder The holder's public key and encrypted amount.
|
||||
* @param issuer The issuer's public key and encrypted amount.
|
||||
* @param auditor Optional auditor's public key and encrypted amount.
|
||||
* @return tesSUCCESS if all encryptions are valid, or an error code otherwise.
|
||||
*/
|
||||
TER
|
||||
verifyRevealedAmount(
|
||||
uint64_t const amount,
|
||||
Slice const& blindingFactor,
|
||||
ConfidentialRecipient const& holder,
|
||||
ConfidentialRecipient const& issuer,
|
||||
std::optional<ConfidentialRecipient> const& auditor);
|
||||
|
||||
/**
|
||||
* @brief Returns the number of recipients in a confidential transfer.
|
||||
*
|
||||
* Returns 4 if an auditor is present (sender, destination, issuer, auditor),
|
||||
* or 3 if no auditor (sender, destination, issuer).
|
||||
*
|
||||
* @param hasAuditor Whether the issuance has an auditor configured.
|
||||
* @return The number of recipients (3 or 4).
|
||||
*/
|
||||
constexpr uint8_t
|
||||
getConfidentialRecipientCount(bool hasAuditor)
|
||||
{
|
||||
return hasAuditor ? 4 : 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Verifies a compact sigma clawback proof.
|
||||
*
|
||||
* Proves that the issuer knows the exact amount encrypted in the holder's
|
||||
* balance ciphertext. Used in ConfidentialMPTClawback to verify the issuer
|
||||
* can decrypt the balance using their private key.
|
||||
*
|
||||
* @param amount The revealed plaintext amount.
|
||||
* @param proof The zero-knowledge proof bytes (ecClawbackProofLength).
|
||||
* @param pubKeySlice The issuer's ElGamal public key (kEcPubKeyLength bytes).
|
||||
* @param ciphertext The issuer's encrypted balance on the holder's account
|
||||
* (kEcGamalEncryptedTotalLength bytes).
|
||||
* @param contextHash The 256-bit context hash binding the proof.
|
||||
* @return tesSUCCESS if the proof is valid, or an error code otherwise.
|
||||
*/
|
||||
TER
|
||||
verifyClawbackProof(
|
||||
uint64_t const amount,
|
||||
Slice const& proof,
|
||||
Slice const& pubKeySlice,
|
||||
Slice const& ciphertext,
|
||||
uint256 const& contextHash);
|
||||
|
||||
/**
|
||||
* @brief Generates a cryptographically secure blinding factor
|
||||
* (size=xrpl::kEcBlindingFactorLength).
|
||||
*
|
||||
* Produces random bytes suitable for use as an ElGamal blinding factor
|
||||
* or Pedersen commitment randomness.
|
||||
*
|
||||
* @return A buffer containing the random blinding factor
|
||||
* (size=xrpl::kEcBlindingFactorLength).
|
||||
*/
|
||||
Buffer
|
||||
generateBlindingFactor();
|
||||
|
||||
/**
|
||||
* @brief Verifies all zero-knowledge proofs for a ConfidentialMPTSend transaction.
|
||||
*
|
||||
* This function calls mpt_verify_send_proof API in the mpt-crypto utility lib, which verifies the
|
||||
* equality proof, amount linkage, balance linkage, and range proof.
|
||||
* Equality proof: Proves the same value is encrypted for the sender, receiver, issuer, and auditor.
|
||||
* Amount linkage: Proves the send amount matches the amount Pedersen commitment.
|
||||
* Balance linkage: Proves the sender's balance matches the balance Pedersen
|
||||
* commitment.
|
||||
* Range proof: Proves the amount and the remaining balance are within range [0, 2^64-1].
|
||||
*
|
||||
* @param proof The full proof blob.
|
||||
* @param sender The sender's public key and encrypted amount.
|
||||
* @param destination The destination's public key and encrypted amount.
|
||||
* @param issuer The issuer's public key and encrypted amount.
|
||||
* @param auditor The auditor's public key and encrypted amount if present.
|
||||
* @param spendingBalance The sender's current spending balance ciphertext.
|
||||
* @param amountCommitment The Pedersen commitment to the send amount.
|
||||
* @param balanceCommitment The Pedersen commitment to the sender's balance.
|
||||
* @param contextHash The context hash binding the proof.
|
||||
* @return tesSUCCESS if all proofs are valid, or an error code otherwise.
|
||||
*/
|
||||
TER
|
||||
verifySendProof(
|
||||
Slice const& proof,
|
||||
ConfidentialRecipient const& sender,
|
||||
ConfidentialRecipient const& destination,
|
||||
ConfidentialRecipient const& issuer,
|
||||
std::optional<ConfidentialRecipient> const& auditor,
|
||||
Slice const& spendingBalance,
|
||||
Slice const& amountCommitment,
|
||||
Slice const& balanceCommitment,
|
||||
uint256 const& contextHash);
|
||||
|
||||
/**
|
||||
* @brief Verifies all zero-knowledge proofs for a ConfidentialMPTConvertBack transaction.
|
||||
*
|
||||
* This function calls mpt_verify_convert_back_proof API in the mpt-crypto utility lib, which
|
||||
* verifies the balance linkage proof and range proof. Balance linkage proof: proves the balance
|
||||
* commitment matches the spending ciphertext. Range proof: proves the remaining balance after
|
||||
* convert back is within range [0, 2^64-1].
|
||||
*
|
||||
* @param proof The full proof blob.
|
||||
* @param pubKeySlice The holder's public key.
|
||||
* @param spendingBalance The holder's spending balance ciphertext.
|
||||
* @param balanceCommitment The Pedersen commitment to the balance.
|
||||
* @param amount The amount being converted back to public.
|
||||
* @param contextHash The context hash binding the proof.
|
||||
* @return tesSUCCESS if all proofs are valid, or an error code otherwise.
|
||||
*/
|
||||
TER
|
||||
verifyConvertBackProof(
|
||||
Slice const& proof,
|
||||
Slice const& pubKeySlice,
|
||||
Slice const& spendingBalance,
|
||||
Slice const& balanceCommitment,
|
||||
uint64_t amount,
|
||||
uint256 const& contextHash);
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -68,15 +68,21 @@ skip(LedgerIndex ledger) noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing the ledger fees. */
|
||||
Keylet const&
|
||||
feeSettings() noexcept;
|
||||
fees() noexcept;
|
||||
|
||||
/** The (fixed) index of the object containing the ledger negativeUNL. */
|
||||
Keylet const&
|
||||
negativeUNL() noexcept;
|
||||
|
||||
/** The beginning of an order book */
|
||||
Keylet
|
||||
book(Book const& b);
|
||||
struct BookT
|
||||
{
|
||||
explicit BookT() = default;
|
||||
|
||||
Keylet
|
||||
operator()(Book const& b) const;
|
||||
};
|
||||
static BookT const kBook{};
|
||||
|
||||
/** The index of a trust line for a given currency
|
||||
|
||||
@@ -87,12 +93,12 @@ book(Book const& b);
|
||||
*/
|
||||
/** @{ */
|
||||
Keylet
|
||||
trustLine(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept;
|
||||
line(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept;
|
||||
|
||||
inline Keylet
|
||||
trustLine(AccountID const& id, Issue const& issue) noexcept
|
||||
line(AccountID const& id, Issue const& issue) noexcept
|
||||
{
|
||||
return trustLine(id, issue.account, issue.currency);
|
||||
return line(id, issue.account, issue.currency);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@@ -113,27 +119,37 @@ Keylet
|
||||
quality(Keylet const& k, std::uint64_t q) noexcept;
|
||||
|
||||
/** The directory for the next lower quality */
|
||||
Keylet
|
||||
next(Keylet const& k);
|
||||
struct NextT
|
||||
{
|
||||
explicit NextT() = default;
|
||||
|
||||
Keylet
|
||||
operator()(Keylet const& k) const;
|
||||
};
|
||||
static NextT const kNext{};
|
||||
|
||||
/** A ticket belonging to an account */
|
||||
/** @{ */
|
||||
Keylet
|
||||
ticket(AccountID const& id, std::uint32_t ticketSeq);
|
||||
|
||||
Keylet
|
||||
ticket(AccountID const& id, SeqProxy ticketSeq);
|
||||
|
||||
inline Keylet
|
||||
ticket(uint256 const& key)
|
||||
struct TicketT
|
||||
{
|
||||
return {ltTICKET, key};
|
||||
}
|
||||
/** @} */
|
||||
explicit TicketT() = default;
|
||||
|
||||
Keylet
|
||||
operator()(AccountID const& id, std::uint32_t ticketSeq) const;
|
||||
|
||||
Keylet
|
||||
operator()(AccountID const& id, SeqProxy ticketSeq) const;
|
||||
|
||||
Keylet
|
||||
operator()(uint256 const& key) const
|
||||
{
|
||||
return {ltTICKET, key};
|
||||
}
|
||||
};
|
||||
static TicketT const kTicket{};
|
||||
|
||||
/** A SignerList */
|
||||
Keylet
|
||||
signerList(AccountID const& account) noexcept;
|
||||
signers(AccountID const& account) noexcept;
|
||||
|
||||
/** A Check */
|
||||
/** @{ */
|
||||
@@ -193,7 +209,7 @@ escrow(AccountID const& src, std::uint32_t seq) noexcept;
|
||||
|
||||
/** A PaymentChannel */
|
||||
Keylet
|
||||
payChannel(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
|
||||
payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept;
|
||||
|
||||
/** NFT page keylets
|
||||
|
||||
@@ -205,22 +221,22 @@ payChannel(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexce
|
||||
/** @{ */
|
||||
/** A keylet for the owner's first possible NFT page. */
|
||||
Keylet
|
||||
nftokenPageMin(AccountID const& owner);
|
||||
nftpageMin(AccountID const& owner);
|
||||
|
||||
/** A keylet for the owner's last possible NFT page. */
|
||||
Keylet
|
||||
nftokenPageMax(AccountID const& owner);
|
||||
nftpageMax(AccountID const& owner);
|
||||
|
||||
Keylet
|
||||
nftokenPage(Keylet const& k, uint256 const& token);
|
||||
nftpage(Keylet const& k, uint256 const& token);
|
||||
/** @} */
|
||||
|
||||
/** An offer from an account to buy or sell an NFT */
|
||||
Keylet
|
||||
nftokenOffer(AccountID const& owner, std::uint32_t seq);
|
||||
nftoffer(AccountID const& owner, std::uint32_t seq);
|
||||
|
||||
inline Keylet
|
||||
nftokenOffer(uint256 const& offer)
|
||||
nftoffer(uint256 const& offer)
|
||||
{
|
||||
return {ltNFTOKEN_OFFER, offer};
|
||||
}
|
||||
@@ -271,13 +287,13 @@ credential(uint256 const& key) noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
mptokenIssuance(std::uint32_t seq, AccountID const& issuer) noexcept;
|
||||
mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept;
|
||||
|
||||
Keylet
|
||||
mptokenIssuance(MPTID const& issuanceID) noexcept;
|
||||
mptIssuance(MPTID const& issuanceID) noexcept;
|
||||
|
||||
inline Keylet
|
||||
mptokenIssuance(uint256 const& issuanceKey)
|
||||
mptIssuance(uint256 const& issuanceKey)
|
||||
{
|
||||
return {ltMPTOKEN_ISSUANCE, issuanceKey};
|
||||
}
|
||||
@@ -304,10 +320,10 @@ vault(uint256 const& vaultKey)
|
||||
}
|
||||
|
||||
Keylet
|
||||
loanBroker(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
loanBroker(uint256 const& key)
|
||||
loanbroker(uint256 const& key)
|
||||
{
|
||||
return {ltLOAN_BROKER, key};
|
||||
}
|
||||
@@ -360,15 +376,11 @@ struct KeyletDesc
|
||||
std::array<KeyletDesc<AccountID const&>, 6> const kDirectAccountKeylets{
|
||||
{{.function = &keylet::account, .expectedLEName = jss::AccountRoot, .includeInTests = false},
|
||||
{.function = &keylet::ownerDir, .expectedLEName = jss::DirectoryNode, .includeInTests = true},
|
||||
{.function = &keylet::signerList, .expectedLEName = jss::SignerList, .includeInTests = true},
|
||||
{.function = &keylet::signers, .expectedLEName = jss::SignerList, .includeInTests = true},
|
||||
// It's normally impossible to create an item at nftpage_min, but
|
||||
// test it anyway, since the invariant checks for it.
|
||||
{.function = &keylet::nftokenPageMin,
|
||||
.expectedLEName = jss::NFTokenPage,
|
||||
.includeInTests = true},
|
||||
{.function = &keylet::nftokenPageMax,
|
||||
.expectedLEName = jss::NFTokenPage,
|
||||
.includeInTests = true},
|
||||
{.function = &keylet::nftpageMin, .expectedLEName = jss::NFTokenPage, .includeInTests = true},
|
||||
{.function = &keylet::nftpageMax, .expectedLEName = jss::NFTokenPage, .includeInTests = true},
|
||||
{.function = &keylet::did, .expectedLEName = jss::DID, .includeInTests = true}}};
|
||||
|
||||
MPTID
|
||||
|
||||
@@ -177,8 +177,7 @@ enum LedgerEntryType : std::uint16_t {
|
||||
LSF_FLAG(lsfMPTCanEscrow, 0x00000008) \
|
||||
LSF_FLAG(lsfMPTCanTrade, 0x00000010) \
|
||||
LSF_FLAG(lsfMPTCanTransfer, 0x00000020) \
|
||||
LSF_FLAG(lsfMPTCanClawback, 0x00000040) \
|
||||
LSF_FLAG(lsfMPTCanHoldConfidentialBalance, 0x00000080)) \
|
||||
LSF_FLAG(lsfMPTCanClawback, 0x00000040)) \
|
||||
\
|
||||
LEDGER_OBJECT(MPTokenIssuanceMutable, \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanLock, 0x00000002) \
|
||||
@@ -187,9 +186,8 @@ enum LedgerEntryType : std::uint16_t {
|
||||
LSF_FLAG(lsmfMPTCanEnableCanTrade, 0x00000010) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanTransfer, 0x00000020) \
|
||||
LSF_FLAG(lsmfMPTCanEnableCanClawback, 0x00000040) \
|
||||
LSF_FLAG(lsmfMPTCannotEnableCanHoldConfidentialBalance, 0x00000080) \
|
||||
LSF_FLAG(lsmfMPTCanMutateMetadata, 0x00010000) \
|
||||
LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000)) \
|
||||
LSF_FLAG(lsmfMPTCanMutateTransferFee, 0x00020000)) \
|
||||
\
|
||||
LEDGER_OBJECT(MPToken, \
|
||||
LSF_FLAG2(lsfMPTLocked, 0x00000001) \
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
txToPermissionType(TxType type);
|
||||
|
||||
// tx type value is permission value minus one
|
||||
[[nodiscard]] static std::optional<TxType>
|
||||
[[nodiscard]] static TxType
|
||||
permissionToTxType(std::uint32_t value);
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/protocol/Units.h>
|
||||
|
||||
#include <mpt_protocol.h>
|
||||
#include <secp256k1_mpt.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -311,65 +307,4 @@ constexpr std::size_t kPermissionMaxSize = 10;
|
||||
/** The maximum number of transactions that can be in a batch. */
|
||||
constexpr std::size_t kMaxBatchTxCount = 8;
|
||||
|
||||
/** The maximum number of batch signers. */
|
||||
constexpr std::size_t kMaxBatchSigners = kMaxBatchTxCount * 3;
|
||||
|
||||
/** Length of a secp256k1 scalar in bytes. */
|
||||
constexpr std::size_t kEcScalarLength = kMPT_SCALAR_SIZE;
|
||||
|
||||
/** Length of EC point (compressed) */
|
||||
constexpr std::size_t kCompressedEcPointLength = 33;
|
||||
|
||||
/** Length of one compressed EC point component in an EC ElGamal ciphertext. */
|
||||
constexpr std::size_t kEcCiphertextComponentLength = kMPT_ELGAMAL_CIPHER_SIZE;
|
||||
|
||||
/** EC ElGamal ciphertext length: two compressed EC points concatenated. */
|
||||
constexpr std::size_t kEcGamalEncryptedTotalLength = kMPT_ELGAMAL_TOTAL_SIZE;
|
||||
|
||||
/** Length of EC public key (compressed) */
|
||||
constexpr std::size_t kEcPubKeyLength = kMPT_PUBKEY_SIZE;
|
||||
|
||||
/** Length of EC private key in bytes */
|
||||
constexpr std::size_t kEcPrivKeyLength = kMPT_PRIVKEY_SIZE;
|
||||
|
||||
/** Length of the EC blinding factor in bytes */
|
||||
constexpr std::size_t kEcBlindingFactorLength = kMPT_BLINDING_FACTOR_SIZE;
|
||||
|
||||
/** Length of Schnorr ZKProof for public key registration (compact form) in bytes */
|
||||
constexpr std::size_t kEcSchnorrProofLength = kMPT_SCHNORR_PROOF_SIZE;
|
||||
|
||||
/** Length of Pedersen Commitment (compressed) */
|
||||
constexpr std::size_t kEcPedersenCommitmentLength = kMPT_PEDERSEN_COMMIT_SIZE;
|
||||
|
||||
/** Length of single bulletproof (range proof for 1 commitment) in bytes */
|
||||
constexpr std::size_t kEcSingleBulletproofLength = kMPT_SINGLE_BULLETPROOF_SIZE;
|
||||
|
||||
/** Length of double bulletproof (range proof for 2 commitments) in bytes */
|
||||
constexpr std::size_t kEcDoubleBulletproofLength = kMPT_DOUBLE_BULLETPROOF_SIZE;
|
||||
|
||||
/** Length of the compact sigma proof component for ConfidentialMPTSend. */
|
||||
constexpr std::size_t kEcSendSigmaProofLength = SECP256K1_COMPACT_STANDARD_PROOF_SIZE;
|
||||
|
||||
/** 192 bytes compact sigma proof + 754 bytes double bulletproof. */
|
||||
constexpr std::size_t kEcSendProofLength = kEcSendSigmaProofLength + kEcDoubleBulletproofLength;
|
||||
|
||||
/** Length of the compact sigma proof component for ConfidentialMPTConvertBack. */
|
||||
constexpr std::size_t kEcConvertBackSigmaProofLength = SECP256K1_COMPACT_CONVERTBACK_PROOF_SIZE;
|
||||
|
||||
/** 128 bytes compact sigma proof + 688 bytes single bulletproof. */
|
||||
constexpr std::size_t kEcConvertBackProofLength =
|
||||
kEcConvertBackSigmaProofLength + kEcSingleBulletproofLength;
|
||||
|
||||
/** Length of the ZKProof for ConfidentialMPTClawback. */
|
||||
constexpr std::size_t kEcClawbackProofLength = SECP256K1_COMPACT_CLAWBACK_PROOF_SIZE;
|
||||
|
||||
/** Extra base fee multiplier charged to confidential MPT transactions. */
|
||||
constexpr std::uint32_t kConfidentialFeeMultiplier = 9;
|
||||
|
||||
/** Compressed EC point prefix for even y-coordinate */
|
||||
constexpr std::uint8_t kEcCompressedPrefixEvenY = 0x02;
|
||||
|
||||
/** Compressed EC point prefix for odd y-coordinate */
|
||||
constexpr std::uint8_t kEcCompressedPrefixOddY = 0x03;
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -217,11 +217,6 @@ public:
|
||||
[[nodiscard]] AccountID
|
||||
getAccountID(SField const& field) const;
|
||||
|
||||
/** The account responsible for the fee and authorization: the delegate when
|
||||
sfDelegate is present, otherwise the account. */
|
||||
[[nodiscard]] AccountID
|
||||
getFeePayer() const;
|
||||
|
||||
[[nodiscard]] Blob
|
||||
getFieldVL(SField const& field) const;
|
||||
[[nodiscard]] STAmount const&
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -52,48 +51,51 @@ public:
|
||||
STTx(TxType type, std::function<void(STObject&)> assembler);
|
||||
|
||||
// STObject functions.
|
||||
[[nodiscard]] SerializedTypeID
|
||||
SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
[[nodiscard]] std::string
|
||||
std::string
|
||||
getFullText() const override;
|
||||
|
||||
// Outer transaction functions / signature functions.
|
||||
static Blob
|
||||
getSignature(STObject const& sigObject);
|
||||
|
||||
[[nodiscard]] Blob
|
||||
Blob
|
||||
getSignature() const
|
||||
{
|
||||
return getSignature(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint256
|
||||
uint256
|
||||
getSigningHash() const;
|
||||
|
||||
[[nodiscard]] TxType
|
||||
TxType
|
||||
getTxnType() const;
|
||||
|
||||
[[nodiscard]] Blob
|
||||
Blob
|
||||
getSigningPubKey() const;
|
||||
|
||||
[[nodiscard]] SeqProxy
|
||||
SeqProxy
|
||||
getSeqProxy() const;
|
||||
|
||||
/** Returns the first non-zero value of (Sequence, TicketSequence). */
|
||||
[[nodiscard]] std::uint32_t
|
||||
std::uint32_t
|
||||
getSeqValue() const;
|
||||
|
||||
[[nodiscard]] boost::container::flat_set<AccountID>
|
||||
AccountID
|
||||
getFeePayer() const;
|
||||
|
||||
boost::container::flat_set<AccountID>
|
||||
getMentionedAccounts() const;
|
||||
|
||||
[[nodiscard]] uint256
|
||||
uint256
|
||||
getTransactionID() const;
|
||||
|
||||
[[nodiscard]] json::Value
|
||||
json::Value
|
||||
getJson(JsonOptions options) const override;
|
||||
|
||||
[[nodiscard]] json::Value
|
||||
json::Value
|
||||
getJson(JsonOptions options, bool binary) const;
|
||||
|
||||
void
|
||||
@@ -106,27 +108,27 @@ public:
|
||||
@param rules The current ledger rules.
|
||||
@return `true` if valid signature. If invalid, the error message string.
|
||||
*/
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
std::expected<void, std::string>
|
||||
checkSign(Rules const& rules) const;
|
||||
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
std::expected<void, std::string>
|
||||
checkBatchSign(Rules const& rules) const;
|
||||
|
||||
// SQL Functions with metadata.
|
||||
static std::string const&
|
||||
getMetaSQLInsertReplaceHeader();
|
||||
|
||||
[[nodiscard]] std::string
|
||||
std::string
|
||||
getMetaSQL(std::uint32_t inLedger, std::string const& escapedMetaData) const;
|
||||
|
||||
[[nodiscard]] std::string
|
||||
std::string
|
||||
getMetaSQL(
|
||||
Serializer rawTxn,
|
||||
std::uint32_t inLedger,
|
||||
TxnSql status,
|
||||
std::string const& escapedMetaData) const;
|
||||
|
||||
[[nodiscard]] std::vector<uint256> const&
|
||||
std::vector<uint256> const&
|
||||
getBatchTransactionIDs() const;
|
||||
|
||||
private:
|
||||
@@ -136,31 +138,28 @@ private:
|
||||
Will be *this more often than not.
|
||||
@return `true` if valid signature. If invalid, the error message string.
|
||||
*/
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
std::expected<void, std::string>
|
||||
checkSign(Rules const& rules, STObject const& sigObject) const;
|
||||
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
std::expected<void, std::string>
|
||||
checkSingleSign(STObject const& sigObject) const;
|
||||
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
std::expected<void, std::string>
|
||||
checkMultiSign(Rules const& rules, STObject const& sigObject) const;
|
||||
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
std::expected<void, std::string>
|
||||
checkBatchSingleSign(STObject const& batchSigner) const;
|
||||
|
||||
[[nodiscard]] std::expected<void, std::string>
|
||||
std::expected<void, std::string>
|
||||
checkBatchMultiSign(STObject const& batchSigner, Rules const& rules) const;
|
||||
|
||||
void
|
||||
buildBatchTxnIds();
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
STBase*
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend class detail::STVar;
|
||||
std::optional<std::vector<uint256>> batchTxnIds_;
|
||||
mutable std::vector<uint256> batchTxnIds_;
|
||||
};
|
||||
|
||||
bool
|
||||
|
||||
@@ -128,7 +128,6 @@ enum TEMcodes : TERUnderlyingType {
|
||||
temBAD_TRANSFER_FEE,
|
||||
temINVALID_INNER_BATCH,
|
||||
temBAD_MPT,
|
||||
temBAD_CIPHERTEXT,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -175,8 +174,6 @@ enum TEFcodes : TERUnderlyingType {
|
||||
tefNO_TICKET,
|
||||
tefNFTOKEN_IS_NOT_TRANSFERABLE,
|
||||
tefINVALID_LEDGER_FIX_TYPE,
|
||||
tefNO_DST_PARTIAL,
|
||||
tefBAD_PATH_COUNT,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -361,11 +358,6 @@ enum TECcodes : TERUnderlyingType {
|
||||
tecLIMIT_EXCEEDED = 195,
|
||||
tecPSEUDO_ACCOUNT = 196,
|
||||
tecPRECISION_LOSS = 197,
|
||||
// DEPRECATED: This error code tecNO_DELEGATE_PERMISSION is reserved for
|
||||
// backward compatibility with historical data on non-prod networks, can be
|
||||
// reclaimed after those networks reset.
|
||||
tecNO_DELEGATE_PERMISSION = 198,
|
||||
tecBAD_PROOF = 199,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -140,8 +140,7 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
TF_FLAG(tfMPTCanEscrow, lsfMPTCanEscrow) \
|
||||
TF_FLAG(tfMPTCanTrade, lsfMPTCanTrade) \
|
||||
TF_FLAG(tfMPTCanTransfer, lsfMPTCanTransfer) \
|
||||
TF_FLAG(tfMPTCanClawback, lsfMPTCanClawback) \
|
||||
TF_FLAG(tfMPTCanHoldConfidentialBalance, lsfMPTCanHoldConfidentialBalance), \
|
||||
TF_FLAG(tfMPTCanClawback, lsfMPTCanClawback), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(MPTokenAuthorize, \
|
||||
@@ -350,13 +349,10 @@ inline constexpr FlagValue tmfMPTCanEnableCanTransfer = lsmfMPTCanEnableCanTrans
|
||||
inline constexpr FlagValue tmfMPTCanEnableCanClawback = lsmfMPTCanEnableCanClawback;
|
||||
inline constexpr FlagValue tmfMPTCanMutateMetadata = lsmfMPTCanMutateMetadata;
|
||||
inline constexpr FlagValue tmfMPTCanMutateTransferFee = lsmfMPTCanMutateTransferFee;
|
||||
inline constexpr FlagValue tmfMPTCannotEnableCanHoldConfidentialBalance =
|
||||
lsmfMPTCannotEnableCanHoldConfidentialBalance;
|
||||
inline constexpr FlagValue tmfMPTokenIssuanceCreateMutableMask =
|
||||
~(tmfMPTCanEnableCanLock | tmfMPTCanEnableRequireAuth | tmfMPTCanEnableCanEscrow |
|
||||
tmfMPTCanEnableCanTrade | tmfMPTCanEnableCanTransfer | tmfMPTCanEnableCanClawback |
|
||||
tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee |
|
||||
tmfMPTCannotEnableCanHoldConfidentialBalance);
|
||||
tmfMPTCanMutateMetadata | tmfMPTCanMutateTransferFee);
|
||||
|
||||
// MPTokenIssuanceSet MutableFlags:
|
||||
// Enable mutable capability flags. These flags are one-way: once enabled,
|
||||
@@ -368,10 +364,9 @@ inline constexpr FlagValue tmfMPTSetCanEscrow = 0x00000004;
|
||||
inline constexpr FlagValue tmfMPTSetCanTrade = 0x00000008;
|
||||
inline constexpr FlagValue tmfMPTSetCanTransfer = 0x00000010;
|
||||
inline constexpr FlagValue tmfMPTSetCanClawback = 0x00000020;
|
||||
inline constexpr FlagValue tmfMPTSetCanHoldConfidentialBalance = 0x00000040;
|
||||
inline constexpr FlagValue tmfMPTokenIssuanceSetMutableMask =
|
||||
~(tmfMPTSetCanLock | tmfMPTSetRequireAuth | tmfMPTSetCanEscrow | tmfMPTSetCanTrade |
|
||||
tmfMPTSetCanTransfer | tmfMPTSetCanClawback | tmfMPTSetCanHoldConfidentialBalance);
|
||||
tmfMPTSetCanTransfer | tmfMPTSetCanClawback);
|
||||
|
||||
// Prior to fixRemoveNFTokenAutoTrustLine, transfer of an NFToken between accounts allowed a
|
||||
// TrustLine to be added to the issuer of that token without explicit permission from that issuer.
|
||||
|
||||
@@ -15,13 +15,11 @@
|
||||
// Add new amendments to the top of this list.
|
||||
// Keep it sorted in reverse chronological order.
|
||||
|
||||
XRPL_FEATURE(BatchV1_1, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(LendingProtocolV1_1, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(ConfidentialTransfer, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (Cleanup3_3_0, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (Cleanup3_2_0, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(MPTokensV2, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (Cleanup3_1_3, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (BatchInnerSigs, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(LendingProtocol, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PermissionDelegationV1_1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (DirectoryLimit, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
@@ -35,6 +33,7 @@ XRPL_FEATURE(TokenEscrow, Supported::Yes, VoteBehavior::DefaultN
|
||||
XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMv1_3, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PermissionedDEX, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Batch, Supported::No, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(SingleAssetVault, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PayChanCancelAfter, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
// Check flags in Credential transactions
|
||||
@@ -59,11 +58,13 @@ XRPL_FIX (EmptyDID, Supported::Yes, VoteBehavior::DefaultNo
|
||||
XRPL_FEATURE(PriceOracle, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMOverflowOffer, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
XRPL_FIX (InnerObjTemplate, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (NFTokenReserve, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (FillOrKill, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (DisallowIncomingV1, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(AMM, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(Clawback, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XRPFees, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
|
||||
@@ -104,7 +105,6 @@ XRPL_RETIRE_FIX(CheckThreading)
|
||||
XRPL_RETIRE_FIX(MasterKeyAsRegularKey)
|
||||
XRPL_RETIRE_FIX(NonFungibleTokensV1_2)
|
||||
XRPL_RETIRE_FIX(NFTokenRemint)
|
||||
XRPL_RETIRE_FIX(NFTokenReserve)
|
||||
XRPL_RETIRE_FIX(PayChanRecipientOwnerDir)
|
||||
XRPL_RETIRE_FIX(QualityUpperBound)
|
||||
XRPL_RETIRE_FIX(ReducedOffersV1)
|
||||
@@ -116,7 +116,6 @@ XRPL_RETIRE_FIX(UniversalNumber)
|
||||
|
||||
XRPL_RETIRE_FEATURE(Checks)
|
||||
XRPL_RETIRE_FEATURE(CheckCashMakesTrustLine)
|
||||
XRPL_RETIRE_FEATURE(Clawback)
|
||||
XRPL_RETIRE_FEATURE(CryptoConditions)
|
||||
XRPL_RETIRE_FEATURE(CryptoConditionsSuite)
|
||||
XRPL_RETIRE_FEATURE(DeletableAccounts)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
/** A ledger object which identifies an offer to buy or sell an NFT.
|
||||
|
||||
\sa keylet::nftokenOffer
|
||||
\sa keylet::nftoffer
|
||||
*/
|
||||
LEDGER_ENTRY(ltNFTOKEN_OFFER, 0x0037, NFTokenOffer, nft_offer, ({
|
||||
{sfOwner, SoeRequired},
|
||||
@@ -84,7 +84,7 @@ LEDGER_ENTRY(ltNEGATIVE_UNL, 0x004e, NegativeUNL, nunl, ({
|
||||
|
||||
/** A ledger object which contains a list of NFTs
|
||||
|
||||
\sa keylet::nftokenPageMin, keylet::nftokenPageMax, keylet::nftokenPage
|
||||
\sa keylet::nftpageMin, keylet::nftpageMax, keylet::nftpage
|
||||
*/
|
||||
LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({
|
||||
{sfPreviousPageMin, SoeOptional},
|
||||
@@ -96,7 +96,7 @@ LEDGER_ENTRY(ltNFTOKEN_PAGE, 0x0050, NFTokenPage, nft_page, ({
|
||||
|
||||
/** A ledger object which contains a signer list for an account.
|
||||
|
||||
\sa keylet::signerList
|
||||
\sa keylet::signers
|
||||
*/
|
||||
// All fields are SoeRequired because there is always a SignerEntries.
|
||||
// If there are no SignerEntries the node is deleted.
|
||||
@@ -112,7 +112,7 @@ LEDGER_ENTRY(ltSIGNER_LIST, 0x0053, SignerList, signer_list, ({
|
||||
|
||||
/** A ledger object which describes a ticket.
|
||||
|
||||
\sa keylet::ticket
|
||||
\sa keylet::kTicket
|
||||
*/
|
||||
LEDGER_ENTRY(ltTICKET, 0x0054, Ticket, ticket, ({
|
||||
{sfAccount, SoeRequired},
|
||||
@@ -272,7 +272,7 @@ LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_c
|
||||
|
||||
@note Per Vinnie Falco this should be renamed to ltTRUST_LINE
|
||||
|
||||
\sa keylet::trustLine
|
||||
\sa keylet::line
|
||||
*/
|
||||
LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
{sfBalance, SoeRequired},
|
||||
@@ -292,7 +292,7 @@ LEDGER_ENTRY(ltRIPPLE_STATE, 0x0072, RippleState, state, ({
|
||||
|
||||
\note This is a singleton: only one such object exists in the ledger.
|
||||
|
||||
\sa keylet::feeSettings
|
||||
\sa keylet::fees
|
||||
*/
|
||||
LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
// Old version uses raw numbers
|
||||
@@ -346,7 +346,7 @@ LEDGER_ENTRY(ltESCROW, 0x0075, Escrow, escrow, ({
|
||||
|
||||
/** A ledger object describing a single unidirectional XRP payment channel.
|
||||
|
||||
\sa keylet::payChannel
|
||||
\sa keylet::payChan
|
||||
*/
|
||||
LEDGER_ENTRY(ltPAYCHAN, 0x0078, PayChannel, payment_channel, ({
|
||||
{sfAccount, SoeRequired},
|
||||
@@ -384,7 +384,7 @@ LEDGER_ENTRY(ltAMM, 0x0079, AMM, amm, ({
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks MPTokenIssuance
|
||||
\sa keylet::mptokenIssuance
|
||||
\sa keylet::mptIssuance
|
||||
*/
|
||||
LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
|
||||
{sfIssuer, SoeRequired},
|
||||
@@ -401,28 +401,19 @@ LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
|
||||
{sfDomainID, SoeOptional},
|
||||
{sfMutableFlags, SoeDefault},
|
||||
{sfReferenceHolding, SoeOptional},
|
||||
{sfIssuerEncryptionKey, SoeOptional},
|
||||
{sfAuditorEncryptionKey, SoeOptional},
|
||||
{sfConfidentialOutstandingAmount, SoeDefault},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks MPToken
|
||||
\sa keylet::mptoken
|
||||
*/
|
||||
LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfMPTAmount, SoeDefault},
|
||||
{sfLockedAmount, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
{sfConfidentialBalanceInbox, SoeOptional},
|
||||
{sfConfidentialBalanceSpending, SoeOptional},
|
||||
{sfConfidentialBalanceVersion, SoeDefault},
|
||||
{sfIssuerEncryptedBalance, SoeOptional},
|
||||
{sfAuditorEncryptedBalance, SoeOptional},
|
||||
{sfHolderEncryptionKey, SoeOptional},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfMPTAmount, SoeDefault},
|
||||
{sfLockedAmount, SoeOptional},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
}))
|
||||
|
||||
/** A ledger object which tracks Oracle
|
||||
@@ -508,7 +499,7 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
|
||||
|
||||
/** A ledger object representing a loan broker
|
||||
|
||||
\sa keylet::loanBroker
|
||||
\sa keylet::loanbroker
|
||||
*/
|
||||
LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
|
||||
@@ -11,10 +11,7 @@ secp256k1Context()
|
||||
struct Holder
|
||||
{
|
||||
secp256k1_context* impl;
|
||||
// SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY were deprecated.
|
||||
// All contexts support both signing and verification, so
|
||||
// SECP256K1_CONTEXT_NONE is the correct flag to use.
|
||||
Holder() : impl(secp256k1_context_create(SECP256K1_CONTEXT_NONE))
|
||||
Holder() : impl(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,6 @@ TYPED_SFIELD(sfInterestRate, UINT32, 65) // 1/10 basis points (bi
|
||||
TYPED_SFIELD(sfLateInterestRate, UINT32, 66) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfCloseInterestRate, UINT32, 67) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfOverpaymentInterestRate, UINT32, 68) // 1/10 basis points (bips)
|
||||
TYPED_SFIELD(sfConfidentialBalanceVersion, UINT32, 69)
|
||||
|
||||
// 64-bit integers (common)
|
||||
TYPED_SFIELD(sfIndexNext, UINT64, 1)
|
||||
@@ -147,7 +146,6 @@ TYPED_SFIELD(sfSubjectNode, UINT64, 28)
|
||||
TYPED_SFIELD(sfLockedAmount, UINT64, 29, SField::kSmdBaseTen|SField::kSmdDefault)
|
||||
TYPED_SFIELD(sfVaultNode, UINT64, 30)
|
||||
TYPED_SFIELD(sfLoanBrokerNode, UINT64, 31)
|
||||
TYPED_SFIELD(sfConfidentialOutstandingAmount, UINT64, 32, SField::kSmdBaseTen|SField::kSmdDefault)
|
||||
|
||||
// 128-bit
|
||||
TYPED_SFIELD(sfEmailHash, UINT128, 1)
|
||||
@@ -208,7 +206,6 @@ TYPED_SFIELD(sfLoanBrokerID, UINT256, 37,
|
||||
SField::kSmdPseudoAccount | SField::kSmdDefault)
|
||||
TYPED_SFIELD(sfLoanID, UINT256, 38)
|
||||
TYPED_SFIELD(sfReferenceHolding, UINT256, 39)
|
||||
TYPED_SFIELD(sfBlindingFactor, UINT256, 40)
|
||||
|
||||
// number (common)
|
||||
TYPED_SFIELD(sfNumber, NUMBER, 1)
|
||||
@@ -302,21 +299,6 @@ TYPED_SFIELD(sfAssetClass, VL, 28)
|
||||
TYPED_SFIELD(sfProvider, VL, 29)
|
||||
TYPED_SFIELD(sfMPTokenMetadata, VL, 30)
|
||||
TYPED_SFIELD(sfCredentialType, VL, 31)
|
||||
TYPED_SFIELD(sfConfidentialBalanceInbox, VL, 32)
|
||||
TYPED_SFIELD(sfConfidentialBalanceSpending, VL, 33)
|
||||
TYPED_SFIELD(sfIssuerEncryptedBalance, VL, 34)
|
||||
TYPED_SFIELD(sfIssuerEncryptionKey, VL, 35)
|
||||
TYPED_SFIELD(sfHolderEncryptionKey, VL, 36)
|
||||
TYPED_SFIELD(sfZKProof, VL, 37)
|
||||
TYPED_SFIELD(sfHolderEncryptedAmount, VL, 38)
|
||||
TYPED_SFIELD(sfIssuerEncryptedAmount, VL, 39)
|
||||
TYPED_SFIELD(sfSenderEncryptedAmount, VL, 40)
|
||||
TYPED_SFIELD(sfDestinationEncryptedAmount, VL, 41)
|
||||
TYPED_SFIELD(sfAuditorEncryptedBalance, VL, 42)
|
||||
TYPED_SFIELD(sfAuditorEncryptedAmount, VL, 43)
|
||||
TYPED_SFIELD(sfAuditorEncryptionKey, VL, 44)
|
||||
TYPED_SFIELD(sfAmountCommitment, VL, 45)
|
||||
TYPED_SFIELD(sfBalanceCommitment, VL, 46)
|
||||
|
||||
// account (common)
|
||||
TYPED_SFIELD(sfAccount, ACCOUNT, 1)
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
case TokenCodecErrc::InvalidEncodingChar:
|
||||
return "invalid encoding char";
|
||||
case TokenCodecErrc::Unknown:
|
||||
return "unknown";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ TRANSACTION(ttNFTOKEN_ACCEPT_OFFER, 29, NFTokenAcceptOffer,
|
||||
#endif
|
||||
TRANSACTION(ttCLAWBACK, 30, Clawback,
|
||||
Delegation::Delegable,
|
||||
uint256{},
|
||||
featureClawback,
|
||||
NoPriv,
|
||||
({
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
@@ -735,8 +735,6 @@ TRANSACTION(ttMPTOKEN_ISSUANCE_SET, 56, MPTokenIssuanceSet,
|
||||
{sfMPTokenMetadata, SoeOptional},
|
||||
{sfTransferFee, SoeOptional},
|
||||
{sfMutableFlags, SoeOptional},
|
||||
{sfIssuerEncryptionKey, SoeOptional},
|
||||
{sfAuditorEncryptionKey, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction type authorizes a MPToken instance */
|
||||
@@ -889,7 +887,6 @@ TRANSACTION(ttVAULT_DELETE, 67, VaultDelete,
|
||||
MustDeleteAcct | DestroyMptIssuance | MustModifyVault,
|
||||
({
|
||||
{sfVaultID, SoeRequired},
|
||||
{sfMemoData, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction trades assets for shares with a vault. */
|
||||
@@ -940,7 +937,7 @@ TRANSACTION(ttVAULT_CLAWBACK, 70, VaultClawback,
|
||||
#endif
|
||||
TRANSACTION(ttBATCH, 71, Batch,
|
||||
Delegation::NotDelegable,
|
||||
featureBatchV1_1,
|
||||
featureBatch,
|
||||
NoPriv,
|
||||
({
|
||||
{sfRawTransactions, SoeRequired},
|
||||
@@ -1080,91 +1077,6 @@ TRANSACTION(ttLOAN_PAY, 84, LoanPay,
|
||||
{sfAmount, SoeRequired, SoeMptSupported},
|
||||
}))
|
||||
|
||||
/** This transaction type converts into confidential MPT balance. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/token/ConfidentialMPTConvert.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONFIDENTIAL_MPT_CONVERT, 85, ConfidentialMPTConvert,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfMPTAmount, SoeRequired},
|
||||
{sfHolderEncryptionKey, SoeOptional},
|
||||
{sfHolderEncryptedAmount, SoeRequired},
|
||||
{sfIssuerEncryptedAmount, SoeRequired},
|
||||
{sfAuditorEncryptedAmount, SoeOptional},
|
||||
{sfBlindingFactor, SoeRequired},
|
||||
{sfZKProof, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction type merges MPT inbox. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/token/ConfidentialMPTMergeInbox.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONFIDENTIAL_MPT_MERGE_INBOX, 86, ConfidentialMPTMergeInbox,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction type converts back into public MPT balance. */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/token/ConfidentialMPTConvertBack.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONFIDENTIAL_MPT_CONVERT_BACK, 87, ConfidentialMPTConvertBack,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfMPTAmount, SoeRequired},
|
||||
{sfHolderEncryptedAmount, SoeRequired},
|
||||
{sfIssuerEncryptedAmount, SoeRequired},
|
||||
{sfAuditorEncryptedAmount, SoeOptional},
|
||||
{sfBlindingFactor, SoeRequired},
|
||||
{sfZKProof, SoeRequired},
|
||||
{sfBalanceCommitment, SoeRequired},
|
||||
}))
|
||||
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/token/ConfidentialMPTSend.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONFIDENTIAL_MPT_SEND, 88, ConfidentialMPTSend,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfSenderEncryptedAmount, SoeRequired},
|
||||
{sfDestinationEncryptedAmount, SoeRequired},
|
||||
{sfIssuerEncryptedAmount, SoeRequired},
|
||||
{sfAuditorEncryptedAmount, SoeOptional},
|
||||
{sfZKProof, SoeRequired},
|
||||
{sfAmountCommitment, SoeRequired},
|
||||
{sfBalanceCommitment, SoeRequired},
|
||||
{sfCredentialIDs, SoeOptional},
|
||||
}))
|
||||
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/token/ConfidentialMPTClawback.h>
|
||||
#endif
|
||||
TRANSACTION(ttCONFIDENTIAL_MPT_CLAWBACK, 89, ConfidentialMPTClawback,
|
||||
Delegation::Delegable,
|
||||
featureConfidentialTransfer,
|
||||
NoPriv,
|
||||
({
|
||||
{sfMPTokenIssuanceID, SoeRequired},
|
||||
{sfHolder, SoeRequired},
|
||||
{sfMPTAmount, SoeRequired},
|
||||
{sfZKProof, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This system-generated transaction type is used to update the status of the various amendments.
|
||||
|
||||
For details, see: https://xrpl.org/amendments.html
|
||||
|
||||
@@ -137,7 +137,6 @@ JSS(authorized_credentials); // in: ledger_entry DepositPreauth
|
||||
JSS(auth_accounts); // out: amm_info
|
||||
JSS(auth_change); // out: AccountInfo
|
||||
JSS(auth_change_queued); // out: AccountInfo
|
||||
JSS(auditor_encrypted_balance); // out: mpt_holders (confidential MPT)
|
||||
JSS(available); // out: ValidatorList
|
||||
JSS(avg_bps_recv); // out: Peers
|
||||
JSS(avg_bps_sent); // out: Peers
|
||||
@@ -162,6 +161,9 @@ JSS(build_path); // in: TransactionSign
|
||||
JSS(build_version); // out: NetworkOPs
|
||||
JSS(cancel_after); // out: AccountChannels
|
||||
JSS(can_delete); // out: CanDelete
|
||||
JSS(mpt_amount); // out: mpt_holders
|
||||
JSS(mpt_issuance_id); // in: Payment, mpt_holders
|
||||
JSS(mptoken_index); // out: mpt_holders
|
||||
JSS(changes); // out: BookChanges
|
||||
JSS(channel_id); // out: AccountChannels
|
||||
JSS(channels); // out: AccountChannels
|
||||
@@ -183,170 +185,165 @@ JSS(command); // in: RPCHandler
|
||||
JSS(common); // out: RPC server_definitions
|
||||
JSS(complete); // out: NetworkOPs, InboundLedger
|
||||
JSS(complete_ledgers); // out: NetworkOPs, PeerImp
|
||||
JSS(confidential_balance_inbox); // out: mpt_holders (confidential MPT)
|
||||
JSS(confidential_balance_spending); // out: mpt_holders (confidential MPT)
|
||||
JSS(confidential_balance_version); // out: mpt_holders (confidential MPT)
|
||||
JSS(consensus); // out: NetworkOPs, LedgerConsensus
|
||||
JSS(converge_time); // out: NetworkOPs
|
||||
JSS(converge_time_s); // out: NetworkOPs
|
||||
JSS(cookie); // out: NetworkOPs
|
||||
JSS(count); // in: AccountTx*, ValidatorList
|
||||
JSS(counters); // in/out: retrieve counters
|
||||
JSS(credentials); // in: deposit_authorized
|
||||
JSS(credential_type); // in: LedgerEntry DepositPreauth
|
||||
JSS(ctid); // in/out: Tx RPC
|
||||
JSS(currency_a); // out: BookChanges
|
||||
JSS(currency_b); // out: BookChanges
|
||||
JSS(currency); // in: paths/PathRequest, STAmount
|
||||
// out: STPathSet, STAmount, AccountLines
|
||||
JSS(current); // out: OwnerInfo
|
||||
JSS(current_activities); //
|
||||
JSS(current_ledger_size); // out: TxQ
|
||||
JSS(current_queue_size); // out: TxQ
|
||||
JSS(data); // out: LedgerData
|
||||
JSS(date); // out: tx/Transaction, NetworkOPs
|
||||
JSS(dbKBLedger); // out: getCounts
|
||||
JSS(dbKBTotal); // out: getCounts
|
||||
JSS(dbKBTransaction); // out: getCounts
|
||||
JSS(debug_signing); // in: TransactionSign
|
||||
JSS(deletion_blockers_only); // in: AccountObjects
|
||||
JSS(delivered_amount); // out: insertDeliveredAmount
|
||||
JSS(deposit_authorized); // out: deposit_authorized
|
||||
JSS(deprecated); //
|
||||
JSS(descending); // in: AccountTx*
|
||||
JSS(description); // in/out: Reservations
|
||||
JSS(destination); // in: nft_buy_offers, nft_sell_offers
|
||||
JSS(destination_account); // in: PathRequest, RipplePathFind, account_lines
|
||||
// out: AccountChannels
|
||||
JSS(destination_amount); // in: PathRequest, RipplePathFind
|
||||
JSS(destination_currencies); // in: PathRequest, RipplePathFind
|
||||
JSS(destination_tag); // in: PathRequest
|
||||
// out: AccountChannels
|
||||
JSS(details); // out: Manifest, server_info
|
||||
JSS(dir_entry); // out: DirectoryEntryIterator
|
||||
JSS(dir_index); // out: DirectoryEntryIterator
|
||||
JSS(dir_root); // out: DirectoryEntryIterator
|
||||
JSS(discounted_fee); // out: amm_info
|
||||
JSS(domain); // out: ValidatorInfo, Manifest
|
||||
JSS(drops); // out: TxQ
|
||||
JSS(duration_us); // out: NetworkOPs
|
||||
JSS(effective); // out: ValidatorList
|
||||
// in: UNL
|
||||
JSS(enabled); // out: AmendmentTable
|
||||
JSS(engine_result); // out: NetworkOPs, TransactionSign, Submit
|
||||
JSS(engine_result_code); // out: NetworkOPs, TransactionSign, Submit
|
||||
JSS(engine_result_message); // out: NetworkOPs, TransactionSign, Submit
|
||||
JSS(entire_set); // out: get_aggregate_price
|
||||
JSS(ephemeral_key); // out: ValidatorInfo
|
||||
// in/out: Manifest
|
||||
JSS(error); // out: error
|
||||
JSS(errored); //
|
||||
JSS(error_code); // out: error
|
||||
JSS(error_exception); // out: Submit
|
||||
JSS(error_message); // out: error
|
||||
JSS(expand); // in: handler/Ledger
|
||||
JSS(expected_date); // out: any (warnings)
|
||||
JSS(expected_date_UTC); // out: any (warnings)
|
||||
JSS(expected_ledger_size); // out: TxQ
|
||||
JSS(expiration); // out: AccountOffers, AccountChannels, ValidatorList, amm_info
|
||||
JSS(fail_hard); // in: Sign, Submit
|
||||
JSS(failed); // out: InboundLedger
|
||||
JSS(feature); // in: Feature
|
||||
JSS(features); // out: Feature
|
||||
JSS(fee_base); // out: NetworkOPs
|
||||
JSS(fee_div_max); // in: TransactionSign
|
||||
JSS(fee_level); // out: AccountInfo
|
||||
JSS(fee_mult_max); // in: TransactionSign
|
||||
JSS(fee_ref); // out: NetworkOPs, DEPRECATED
|
||||
JSS(fetch_pack); // out: NetworkOPs
|
||||
JSS(FIELDS); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(first); // out: rpc/Version
|
||||
JSS(finished); //
|
||||
JSS(fix_txns); // in: LedgerCleaner
|
||||
JSS(flags); // out: AccountOffers, NetworkOPs
|
||||
JSS(forward); // in: AccountTx
|
||||
JSS(freeze); // out: AccountLines
|
||||
JSS(freeze_peer); // out: AccountLines
|
||||
JSS(deep_freeze); // out: AccountLines
|
||||
JSS(deep_freeze_peer); // out: AccountLines
|
||||
JSS(frozen_balances); // out: GatewayBalances
|
||||
JSS(full); // in: LedgerClearer, handlers/Ledger
|
||||
JSS(full_reply); // out: PathFind
|
||||
JSS(fullbelow_size); // out: GetCounts
|
||||
JSS(git); // out: server_info
|
||||
JSS(good); // out: RPCVersion
|
||||
JSS(hash); // out: NetworkOPs, InboundLedger, LedgerToJson, STTx; field
|
||||
JSS(have_header); // out: InboundLedger
|
||||
JSS(have_state); // out: InboundLedger
|
||||
JSS(have_transactions); // out: InboundLedger
|
||||
JSS(high); // out: BookChanges
|
||||
JSS(highest_sequence); // out: AccountInfo
|
||||
JSS(highest_ticket); // out: AccountInfo
|
||||
JSS(historical_perminute); // historical_perminute.
|
||||
JSS(holders); // out: MPTHolders
|
||||
JSS(holder_encryption_key); // out: mpt_holders (confidential MPT)
|
||||
JSS(hostid); // out: NetworkOPs
|
||||
JSS(hotwallet); // in: GatewayBalances
|
||||
JSS(id); // websocket.
|
||||
JSS(ident); // in: AccountCurrencies, AccountInfo, OwnerInfo
|
||||
JSS(ignore_default); // in: AccountLines
|
||||
JSS(in); // out: OverlayImpl
|
||||
JSS(inLedger); // out: tx/Transaction
|
||||
JSS(inbound); // out: PeerImp
|
||||
JSS(index); // in: LedgerEntry
|
||||
// out: STLedgerEntry, LedgerEntry, TxHistory, LedgerData
|
||||
JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo
|
||||
JSS(initial_sync_duration_us); //
|
||||
JSS(internal_command); // in: Internal
|
||||
JSS(invalid_API_version); // out: Many, when a request has an invalid version
|
||||
JSS(io_latency_ms); // out: NetworkOPs
|
||||
JSS(ip); // in: Connect, out: OverlayImpl
|
||||
JSS(is_burned); // out: nft_info (clio)
|
||||
JSS(isSerialized); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(isSigningField); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(isVLEncoded); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(issuer); // in: RipplePathFind, Subscribe, Unsubscribe, BookOffers
|
||||
// out: STPathSet, STAmount
|
||||
JSS(issuer_encrypted_balance); // out: mpt_holders (confidential MPT)
|
||||
JSS(job); //
|
||||
JSS(job_queue); //
|
||||
JSS(jobs); //
|
||||
JSS(jsonrpc); // json version
|
||||
JSS(jq_trans_overflow); // JobQueue transaction limit overflow.
|
||||
JSS(kept); // out: SubmitTransaction
|
||||
JSS(key); // out
|
||||
JSS(key_type); // in/out: WalletPropose, TransactionSign
|
||||
JSS(latency); // out: PeerImp
|
||||
JSS(last); // out: RPCVersion
|
||||
JSS(last_close); // out: NetworkOPs
|
||||
JSS(last_refresh_time); // out: ValidatorSite
|
||||
JSS(last_refresh_status); // out: ValidatorSite
|
||||
JSS(last_refresh_message); // out: ValidatorSite
|
||||
JSS(ledger); // in: NetworkOPs, LedgerCleaner, RPCHelpers
|
||||
// out: NetworkOPs, PeerImp
|
||||
JSS(ledger_current_index); // out: NetworkOPs, RPCHelpers, LedgerCurrent, LedgerAccept,
|
||||
// AccountLines
|
||||
JSS(ledger_data); // out: LedgerHeader
|
||||
JSS(ledger_hash); // in: RPCHelpers, LedgerRequest, RipplePathFind,
|
||||
// TransactionEntry, handlers/Ledger
|
||||
// out: NetworkOPs, RPCHelpers, LedgerClosed, LedgerData,
|
||||
// AccountLines
|
||||
JSS(ledger_hit_rate); // out: GetCounts
|
||||
JSS(ledger_index); // in/out: many
|
||||
JSS(ledger_index_max); // in, out: AccountTx*
|
||||
JSS(ledger_index_min); // in, out: AccountTx*
|
||||
JSS(ledger_max); // in, out: AccountTx*
|
||||
JSS(ledger_min); // in, out: AccountTx*
|
||||
JSS(ledger_time); // out: NetworkOPs
|
||||
JSS(LEDGER_ENTRY_TYPES); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(LEDGER_ENTRY_FLAGS); // out: RPC server_definitions
|
||||
JSS(LEDGER_ENTRY_FORMATS); // out: RPC server_definitions
|
||||
JSS(levels); // LogLevels
|
||||
JSS(consensus); // out: NetworkOPs, LedgerConsensus
|
||||
JSS(converge_time); // out: NetworkOPs
|
||||
JSS(converge_time_s); // out: NetworkOPs
|
||||
JSS(cookie); // out: NetworkOPs
|
||||
JSS(count); // in: AccountTx*, ValidatorList
|
||||
JSS(counters); // in/out: retrieve counters
|
||||
JSS(credentials); // in: deposit_authorized
|
||||
JSS(credential_type); // in: LedgerEntry DepositPreauth
|
||||
JSS(ctid); // in/out: Tx RPC
|
||||
JSS(currency_a); // out: BookChanges
|
||||
JSS(currency_b); // out: BookChanges
|
||||
JSS(currency); // in: paths/PathRequest, STAmount
|
||||
// out: STPathSet, STAmount, AccountLines
|
||||
JSS(current); // out: OwnerInfo
|
||||
JSS(current_activities); //
|
||||
JSS(current_ledger_size); // out: TxQ
|
||||
JSS(current_queue_size); // out: TxQ
|
||||
JSS(data); // out: LedgerData
|
||||
JSS(date); // out: tx/Transaction, NetworkOPs
|
||||
JSS(dbKBLedger); // out: getCounts
|
||||
JSS(dbKBTotal); // out: getCounts
|
||||
JSS(dbKBTransaction); // out: getCounts
|
||||
JSS(debug_signing); // in: TransactionSign
|
||||
JSS(deletion_blockers_only); // in: AccountObjects
|
||||
JSS(delivered_amount); // out: insertDeliveredAmount
|
||||
JSS(deposit_authorized); // out: deposit_authorized
|
||||
JSS(deprecated); //
|
||||
JSS(descending); // in: AccountTx*
|
||||
JSS(description); // in/out: Reservations
|
||||
JSS(destination); // in: nft_buy_offers, nft_sell_offers
|
||||
JSS(destination_account); // in: PathRequest, RipplePathFind, account_lines
|
||||
// out: AccountChannels
|
||||
JSS(destination_amount); // in: PathRequest, RipplePathFind
|
||||
JSS(destination_currencies); // in: PathRequest, RipplePathFind
|
||||
JSS(destination_tag); // in: PathRequest
|
||||
// out: AccountChannels
|
||||
JSS(details); // out: Manifest, server_info
|
||||
JSS(dir_entry); // out: DirectoryEntryIterator
|
||||
JSS(dir_index); // out: DirectoryEntryIterator
|
||||
JSS(dir_root); // out: DirectoryEntryIterator
|
||||
JSS(discounted_fee); // out: amm_info
|
||||
JSS(domain); // out: ValidatorInfo, Manifest
|
||||
JSS(drops); // out: TxQ
|
||||
JSS(duration_us); // out: NetworkOPs
|
||||
JSS(effective); // out: ValidatorList
|
||||
// in: UNL
|
||||
JSS(enabled); // out: AmendmentTable
|
||||
JSS(engine_result); // out: NetworkOPs, TransactionSign, Submit
|
||||
JSS(engine_result_code); // out: NetworkOPs, TransactionSign, Submit
|
||||
JSS(engine_result_message); // out: NetworkOPs, TransactionSign, Submit
|
||||
JSS(entire_set); // out: get_aggregate_price
|
||||
JSS(ephemeral_key); // out: ValidatorInfo
|
||||
// in/out: Manifest
|
||||
JSS(error); // out: error
|
||||
JSS(errored); //
|
||||
JSS(error_code); // out: error
|
||||
JSS(error_exception); // out: Submit
|
||||
JSS(error_message); // out: error
|
||||
JSS(expand); // in: handler/Ledger
|
||||
JSS(expected_date); // out: any (warnings)
|
||||
JSS(expected_date_UTC); // out: any (warnings)
|
||||
JSS(expected_ledger_size); // out: TxQ
|
||||
JSS(expiration); // out: AccountOffers, AccountChannels, ValidatorList, amm_info
|
||||
JSS(fail_hard); // in: Sign, Submit
|
||||
JSS(failed); // out: InboundLedger
|
||||
JSS(feature); // in: Feature
|
||||
JSS(features); // out: Feature
|
||||
JSS(fee_base); // out: NetworkOPs
|
||||
JSS(fee_div_max); // in: TransactionSign
|
||||
JSS(fee_level); // out: AccountInfo
|
||||
JSS(fee_mult_max); // in: TransactionSign
|
||||
JSS(fee_ref); // out: NetworkOPs, DEPRECATED
|
||||
JSS(fetch_pack); // out: NetworkOPs
|
||||
JSS(FIELDS); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(first); // out: rpc/Version
|
||||
JSS(finished); //
|
||||
JSS(fix_txns); // in: LedgerCleaner
|
||||
JSS(flags); // out: AccountOffers, NetworkOPs
|
||||
JSS(forward); // in: AccountTx
|
||||
JSS(freeze); // out: AccountLines
|
||||
JSS(freeze_peer); // out: AccountLines
|
||||
JSS(deep_freeze); // out: AccountLines
|
||||
JSS(deep_freeze_peer); // out: AccountLines
|
||||
JSS(frozen_balances); // out: GatewayBalances
|
||||
JSS(full); // in: LedgerClearer, handlers/Ledger
|
||||
JSS(full_reply); // out: PathFind
|
||||
JSS(fullbelow_size); // out: GetCounts
|
||||
JSS(git); // out: server_info
|
||||
JSS(good); // out: RPCVersion
|
||||
JSS(hash); // out: NetworkOPs, InboundLedger, LedgerToJson, STTx; field
|
||||
JSS(have_header); // out: InboundLedger
|
||||
JSS(have_state); // out: InboundLedger
|
||||
JSS(have_transactions); // out: InboundLedger
|
||||
JSS(high); // out: BookChanges
|
||||
JSS(highest_sequence); // out: AccountInfo
|
||||
JSS(highest_ticket); // out: AccountInfo
|
||||
JSS(historical_perminute); // historical_perminute.
|
||||
JSS(holders); // out: MPTHolders
|
||||
JSS(hostid); // out: NetworkOPs
|
||||
JSS(hotwallet); // in: GatewayBalances
|
||||
JSS(id); // websocket.
|
||||
JSS(ident); // in: AccountCurrencies, AccountInfo, OwnerInfo
|
||||
JSS(ignore_default); // in: AccountLines
|
||||
JSS(in); // out: OverlayImpl
|
||||
JSS(inLedger); // out: tx/Transaction
|
||||
JSS(inbound); // out: PeerImp
|
||||
JSS(index); // in: LedgerEntry
|
||||
// out: STLedgerEntry, LedgerEntry, TxHistory, LedgerData
|
||||
JSS(info); // out: ServerInfo, ConsensusInfo, FetchInfo
|
||||
JSS(initial_sync_duration_us); //
|
||||
JSS(internal_command); // in: Internal
|
||||
JSS(invalid_API_version); // out: Many, when a request has an invalid version
|
||||
JSS(io_latency_ms); // out: NetworkOPs
|
||||
JSS(ip); // in: Connect, out: OverlayImpl
|
||||
JSS(is_burned); // out: nft_info (clio)
|
||||
JSS(isSerialized); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(isSigningField); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(isVLEncoded); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(issuer); // in: RipplePathFind, Subscribe, Unsubscribe, BookOffers
|
||||
// out: STPathSet, STAmount
|
||||
JSS(job); //
|
||||
JSS(job_queue); //
|
||||
JSS(jobs); //
|
||||
JSS(jsonrpc); // json version
|
||||
JSS(jq_trans_overflow); // JobQueue transaction limit overflow.
|
||||
JSS(kept); // out: SubmitTransaction
|
||||
JSS(key); // out
|
||||
JSS(key_type); // in/out: WalletPropose, TransactionSign
|
||||
JSS(latency); // out: PeerImp
|
||||
JSS(last); // out: RPCVersion
|
||||
JSS(last_close); // out: NetworkOPs
|
||||
JSS(last_refresh_time); // out: ValidatorSite
|
||||
JSS(last_refresh_status); // out: ValidatorSite
|
||||
JSS(last_refresh_message); // out: ValidatorSite
|
||||
JSS(ledger); // in: NetworkOPs, LedgerCleaner, RPCHelpers
|
||||
// out: NetworkOPs, PeerImp
|
||||
JSS(ledger_current_index); // out: NetworkOPs, RPCHelpers, LedgerCurrent, LedgerAccept,
|
||||
// AccountLines
|
||||
JSS(ledger_data); // out: LedgerHeader
|
||||
JSS(ledger_hash); // in: RPCHelpers, LedgerRequest, RipplePathFind,
|
||||
// TransactionEntry, handlers/Ledger
|
||||
// out: NetworkOPs, RPCHelpers, LedgerClosed, LedgerData,
|
||||
// AccountLines
|
||||
JSS(ledger_hit_rate); // out: GetCounts
|
||||
JSS(ledger_index); // in/out: many
|
||||
JSS(ledger_index_max); // in, out: AccountTx*
|
||||
JSS(ledger_index_min); // in, out: AccountTx*
|
||||
JSS(ledger_max); // in, out: AccountTx*
|
||||
JSS(ledger_min); // in, out: AccountTx*
|
||||
JSS(ledger_time); // out: NetworkOPs
|
||||
JSS(LEDGER_ENTRY_TYPES); // out: RPC server_definitions
|
||||
// matches definitions.json format
|
||||
JSS(LEDGER_ENTRY_FLAGS); // out: RPC server_definitions
|
||||
JSS(LEDGER_ENTRY_FORMATS); // out: RPC server_definitions
|
||||
JSS(levels); // LogLevels
|
||||
JSS(limit); // in/out: AccountTx*, AccountOffers, AccountLines, AccountObjects
|
||||
// in: LedgerData, BookOffers
|
||||
JSS(limit_peer); // out: AccountLines
|
||||
@@ -404,9 +401,6 @@ JSS(min_ledger); // in: LedgerCleaner
|
||||
JSS(minimum_fee); // out: TxQ
|
||||
JSS(minimum_level); // out: TxQ
|
||||
JSS(missingCommand); // error
|
||||
JSS(mpt_amount); // out: mpt_holders
|
||||
JSS(mpt_issuance_id); // in: Payment, mpt_holders
|
||||
JSS(mptoken_index); // out: mpt_holders
|
||||
JSS(mpt_issuance_id_a); // out: BookChanges
|
||||
JSS(mpt_issuance_id_b); // out: BookChanges
|
||||
JSS(name); // out: AmendmentTableImpl, PeerImp
|
||||
|
||||
@@ -52,7 +52,7 @@ getTransferFee(uint256 const& id)
|
||||
}
|
||||
|
||||
inline std::uint32_t
|
||||
getSequence(uint256 const& id)
|
||||
getSerial(uint256 const& id)
|
||||
{
|
||||
std::uint32_t seq = 0;
|
||||
memcpy(&seq, id.begin() + 28, 4);
|
||||
@@ -92,7 +92,7 @@ getTaxon(uint256 const& id)
|
||||
|
||||
// The taxon cipher is just an XOR, so it is reversible by applying the
|
||||
// XOR a second time.
|
||||
return cipheredTaxon(getSequence(id), toTaxon(taxon));
|
||||
return cipheredTaxon(getSerial(id), toTaxon(taxon));
|
||||
}
|
||||
|
||||
inline AccountID
|
||||
|
||||
@@ -147,150 +147,6 @@ public:
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfConfidentialBalanceInbox (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getConfidentialBalanceInbox() const
|
||||
{
|
||||
if (hasConfidentialBalanceInbox())
|
||||
return this->sle_->at(sfConfidentialBalanceInbox);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfConfidentialBalanceInbox is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasConfidentialBalanceInbox() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfConfidentialBalanceInbox);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfConfidentialBalanceSpending (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getConfidentialBalanceSpending() const
|
||||
{
|
||||
if (hasConfidentialBalanceSpending())
|
||||
return this->sle_->at(sfConfidentialBalanceSpending);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfConfidentialBalanceSpending is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasConfidentialBalanceSpending() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfConfidentialBalanceSpending);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfConfidentialBalanceVersion (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getConfidentialBalanceVersion() const
|
||||
{
|
||||
if (hasConfidentialBalanceVersion())
|
||||
return this->sle_->at(sfConfidentialBalanceVersion);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfConfidentialBalanceVersion is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasConfidentialBalanceVersion() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfConfidentialBalanceVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfIssuerEncryptedBalance (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getIssuerEncryptedBalance() const
|
||||
{
|
||||
if (hasIssuerEncryptedBalance())
|
||||
return this->sle_->at(sfIssuerEncryptedBalance);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfIssuerEncryptedBalance is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasIssuerEncryptedBalance() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfIssuerEncryptedBalance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAuditorEncryptedBalance (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getAuditorEncryptedBalance() const
|
||||
{
|
||||
if (hasAuditorEncryptedBalance())
|
||||
return this->sle_->at(sfAuditorEncryptedBalance);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfAuditorEncryptedBalance is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasAuditorEncryptedBalance() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfAuditorEncryptedBalance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfHolderEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getHolderEncryptionKey() const
|
||||
{
|
||||
if (hasHolderEncryptionKey())
|
||||
return this->sle_->at(sfHolderEncryptionKey);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfHolderEncryptionKey is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasHolderEncryptionKey() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfHolderEncryptionKey);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -414,72 +270,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfConfidentialBalanceInbox (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenBuilder&
|
||||
setConfidentialBalanceInbox(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfConfidentialBalanceInbox] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfConfidentialBalanceSpending (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenBuilder&
|
||||
setConfidentialBalanceSpending(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfConfidentialBalanceSpending] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfConfidentialBalanceVersion (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenBuilder&
|
||||
setConfidentialBalanceVersion(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfConfidentialBalanceVersion] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfIssuerEncryptedBalance (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenBuilder&
|
||||
setIssuerEncryptedBalance(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfIssuerEncryptedBalance] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAuditorEncryptedBalance (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenBuilder&
|
||||
setAuditorEncryptedBalance(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAuditorEncryptedBalance] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfHolderEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenBuilder&
|
||||
setHolderEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfHolderEncryptionKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed MPToken wrapper.
|
||||
* @param index The ledger entry index.
|
||||
|
||||
@@ -302,78 +302,6 @@ public:
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfReferenceHolding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfIssuerEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getIssuerEncryptionKey() const
|
||||
{
|
||||
if (hasIssuerEncryptionKey())
|
||||
return this->sle_->at(sfIssuerEncryptionKey);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfIssuerEncryptionKey is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasIssuerEncryptionKey() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfIssuerEncryptionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAuditorEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getAuditorEncryptionKey() const
|
||||
{
|
||||
if (hasAuditorEncryptionKey())
|
||||
return this->sle_->at(sfAuditorEncryptionKey);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfAuditorEncryptionKey is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasAuditorEncryptionKey() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfAuditorEncryptionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfConfidentialOutstandingAmount (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT64::type::value_type>
|
||||
getConfidentialOutstandingAmount() const
|
||||
{
|
||||
if (hasConfidentialOutstandingAmount())
|
||||
return this->sle_->at(sfConfidentialOutstandingAmount);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfConfidentialOutstandingAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasConfidentialOutstandingAmount() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfConfidentialOutstandingAmount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -576,39 +504,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfIssuerEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceBuilder&
|
||||
setIssuerEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfIssuerEncryptionKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAuditorEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceBuilder&
|
||||
setAuditorEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAuditorEncryptionKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfConfidentialOutstandingAmount (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceBuilder&
|
||||
setConfidentialOutstandingAmount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfConfidentialOutstandingAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed MPTokenIssuance wrapper.
|
||||
* @param index The ledger entry index.
|
||||
|
||||
@@ -20,7 +20,7 @@ class BatchBuilder;
|
||||
*
|
||||
* Type: ttBATCH (71)
|
||||
* Delegable: Delegation::NotDelegable
|
||||
* Amendment: featureBatchV1_1
|
||||
* Amendment: featureBatch
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
|
||||
@@ -20,7 +20,7 @@ class ClawbackBuilder;
|
||||
*
|
||||
* Type: ttCLAWBACK (30)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: uint256{}
|
||||
* Amendment: featureClawback
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ConfidentialMPTClawbackBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ConfidentialMPTClawback
|
||||
*
|
||||
* Type: ttCONFIDENTIAL_MPT_CLAWBACK (89)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureConfidentialTransfer
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ConfidentialMPTClawbackBuilder to construct new transactions.
|
||||
*/
|
||||
class ConfidentialMPTClawback : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONFIDENTIAL_MPT_CLAWBACK;
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTClawback transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ConfidentialMPTClawback(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTClawback");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT192::type::value_type
|
||||
getMPTokenIssuanceID() const
|
||||
{
|
||||
return this->tx_->at(sfMPTokenIssuanceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfHolder (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getHolder() const
|
||||
{
|
||||
return this->tx_->at(sfHolder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMPTAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getMPTAmount() const
|
||||
{
|
||||
return this->tx_->at(sfMPTAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfZKProof (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getZKProof() const
|
||||
{
|
||||
return this->tx_->at(sfZKProof);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ConfidentialMPTClawback transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ConfidentialMPTClawbackBuilder : public TransactionBuilderBase<ConfidentialMPTClawbackBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ConfidentialMPTClawbackBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param mPTokenIssuanceID The sfMPTokenIssuanceID field value.
|
||||
* @param holder The sfHolder field value.
|
||||
* @param mPTAmount The sfMPTAmount field value.
|
||||
* @param zKProof The sfZKProof field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ConfidentialMPTClawbackBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_UINT192::type::value_type> const& mPTokenIssuanceID, std::decay_t<typename SF_ACCOUNT::type::value_type> const& holder, std::decay_t<typename SF_UINT64::type::value_type> const& mPTAmount, std::decay_t<typename SF_VL::type::value_type> const& zKProof, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ConfidentialMPTClawbackBuilder>(ttCONFIDENTIAL_MPT_CLAWBACK, account, sequence, fee)
|
||||
{
|
||||
setMPTokenIssuanceID(mPTokenIssuanceID);
|
||||
setHolder(holder);
|
||||
setMPTAmount(mPTAmount);
|
||||
setZKProof(zKProof);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTClawbackBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ConfidentialMPTClawbackBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONFIDENTIAL_MPT_CLAWBACK)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTClawbackBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTClawbackBuilder&
|
||||
setMPTokenIssuanceID(std::decay_t<typename SF_UINT192::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMPTokenIssuanceID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfHolder (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTClawbackBuilder&
|
||||
setHolder(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfHolder] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMPTAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTClawbackBuilder&
|
||||
setMPTAmount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMPTAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfZKProof (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTClawbackBuilder&
|
||||
setZKProof(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfZKProof] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ConfidentialMPTClawback wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ConfidentialMPTClawback
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ConfidentialMPTClawback{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,336 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ConfidentialMPTConvertBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ConfidentialMPTConvert
|
||||
*
|
||||
* Type: ttCONFIDENTIAL_MPT_CONVERT (85)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureConfidentialTransfer
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ConfidentialMPTConvertBuilder to construct new transactions.
|
||||
*/
|
||||
class ConfidentialMPTConvert : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONFIDENTIAL_MPT_CONVERT;
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTConvert transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ConfidentialMPTConvert(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTConvert");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT192::type::value_type
|
||||
getMPTokenIssuanceID() const
|
||||
{
|
||||
return this->tx_->at(sfMPTokenIssuanceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMPTAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getMPTAmount() const
|
||||
{
|
||||
return this->tx_->at(sfMPTAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfHolderEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getHolderEncryptionKey() const
|
||||
{
|
||||
if (hasHolderEncryptionKey())
|
||||
{
|
||||
return this->tx_->at(sfHolderEncryptionKey);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfHolderEncryptionKey is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasHolderEncryptionKey() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfHolderEncryptionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfHolderEncryptedAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getHolderEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->at(sfHolderEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfIssuerEncryptedAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getIssuerEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->at(sfIssuerEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAuditorEncryptedAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getAuditorEncryptedAmount() const
|
||||
{
|
||||
if (hasAuditorEncryptedAmount())
|
||||
{
|
||||
return this->tx_->at(sfAuditorEncryptedAmount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfAuditorEncryptedAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasAuditorEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfAuditorEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfBlindingFactor (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getBlindingFactor() const
|
||||
{
|
||||
return this->tx_->at(sfBlindingFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfZKProof (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getZKProof() const
|
||||
{
|
||||
if (hasZKProof())
|
||||
{
|
||||
return this->tx_->at(sfZKProof);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfZKProof is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasZKProof() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfZKProof);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ConfidentialMPTConvert transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ConfidentialMPTConvertBuilder : public TransactionBuilderBase<ConfidentialMPTConvertBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ConfidentialMPTConvertBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param mPTokenIssuanceID The sfMPTokenIssuanceID field value.
|
||||
* @param mPTAmount The sfMPTAmount field value.
|
||||
* @param holderEncryptedAmount The sfHolderEncryptedAmount field value.
|
||||
* @param issuerEncryptedAmount The sfIssuerEncryptedAmount field value.
|
||||
* @param blindingFactor The sfBlindingFactor field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_UINT192::type::value_type> const& mPTokenIssuanceID, std::decay_t<typename SF_UINT64::type::value_type> const& mPTAmount, std::decay_t<typename SF_VL::type::value_type> const& holderEncryptedAmount, std::decay_t<typename SF_VL::type::value_type> const& issuerEncryptedAmount, std::decay_t<typename SF_UINT256::type::value_type> const& blindingFactor, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ConfidentialMPTConvertBuilder>(ttCONFIDENTIAL_MPT_CONVERT, account, sequence, fee)
|
||||
{
|
||||
setMPTokenIssuanceID(mPTokenIssuanceID);
|
||||
setMPTAmount(mPTAmount);
|
||||
setHolderEncryptedAmount(holderEncryptedAmount);
|
||||
setIssuerEncryptedAmount(issuerEncryptedAmount);
|
||||
setBlindingFactor(blindingFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTConvertBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONFIDENTIAL_MPT_CONVERT)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTConvertBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder&
|
||||
setMPTokenIssuanceID(std::decay_t<typename SF_UINT192::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMPTokenIssuanceID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMPTAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder&
|
||||
setMPTAmount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMPTAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfHolderEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder&
|
||||
setHolderEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfHolderEncryptionKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfHolderEncryptedAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder&
|
||||
setHolderEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfHolderEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfIssuerEncryptedAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder&
|
||||
setIssuerEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfIssuerEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAuditorEncryptedAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder&
|
||||
setAuditorEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAuditorEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfBlindingFactor (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder&
|
||||
setBlindingFactor(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfBlindingFactor] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfZKProof (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBuilder&
|
||||
setZKProof(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfZKProof] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ConfidentialMPTConvert wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ConfidentialMPTConvert
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ConfidentialMPTConvert{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,310 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ConfidentialMPTConvertBackBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ConfidentialMPTConvertBack
|
||||
*
|
||||
* Type: ttCONFIDENTIAL_MPT_CONVERT_BACK (87)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureConfidentialTransfer
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ConfidentialMPTConvertBackBuilder to construct new transactions.
|
||||
*/
|
||||
class ConfidentialMPTConvertBack : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONFIDENTIAL_MPT_CONVERT_BACK;
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTConvertBack transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ConfidentialMPTConvertBack(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTConvertBack");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT192::type::value_type
|
||||
getMPTokenIssuanceID() const
|
||||
{
|
||||
return this->tx_->at(sfMPTokenIssuanceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMPTAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getMPTAmount() const
|
||||
{
|
||||
return this->tx_->at(sfMPTAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfHolderEncryptedAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getHolderEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->at(sfHolderEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfIssuerEncryptedAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getIssuerEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->at(sfIssuerEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAuditorEncryptedAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getAuditorEncryptedAmount() const
|
||||
{
|
||||
if (hasAuditorEncryptedAmount())
|
||||
{
|
||||
return this->tx_->at(sfAuditorEncryptedAmount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfAuditorEncryptedAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasAuditorEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfAuditorEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfBlindingFactor (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getBlindingFactor() const
|
||||
{
|
||||
return this->tx_->at(sfBlindingFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfZKProof (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getZKProof() const
|
||||
{
|
||||
return this->tx_->at(sfZKProof);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfBalanceCommitment (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getBalanceCommitment() const
|
||||
{
|
||||
return this->tx_->at(sfBalanceCommitment);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ConfidentialMPTConvertBack transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ConfidentialMPTConvertBackBuilder : public TransactionBuilderBase<ConfidentialMPTConvertBackBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ConfidentialMPTConvertBackBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param mPTokenIssuanceID The sfMPTokenIssuanceID field value.
|
||||
* @param mPTAmount The sfMPTAmount field value.
|
||||
* @param holderEncryptedAmount The sfHolderEncryptedAmount field value.
|
||||
* @param issuerEncryptedAmount The sfIssuerEncryptedAmount field value.
|
||||
* @param blindingFactor The sfBlindingFactor field value.
|
||||
* @param zKProof The sfZKProof field value.
|
||||
* @param balanceCommitment The sfBalanceCommitment field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_UINT192::type::value_type> const& mPTokenIssuanceID, std::decay_t<typename SF_UINT64::type::value_type> const& mPTAmount, std::decay_t<typename SF_VL::type::value_type> const& holderEncryptedAmount, std::decay_t<typename SF_VL::type::value_type> const& issuerEncryptedAmount, std::decay_t<typename SF_UINT256::type::value_type> const& blindingFactor, std::decay_t<typename SF_VL::type::value_type> const& zKProof, std::decay_t<typename SF_VL::type::value_type> const& balanceCommitment, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ConfidentialMPTConvertBackBuilder>(ttCONFIDENTIAL_MPT_CONVERT_BACK, account, sequence, fee)
|
||||
{
|
||||
setMPTokenIssuanceID(mPTokenIssuanceID);
|
||||
setMPTAmount(mPTAmount);
|
||||
setHolderEncryptedAmount(holderEncryptedAmount);
|
||||
setIssuerEncryptedAmount(issuerEncryptedAmount);
|
||||
setBlindingFactor(blindingFactor);
|
||||
setZKProof(zKProof);
|
||||
setBalanceCommitment(balanceCommitment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTConvertBackBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONFIDENTIAL_MPT_CONVERT_BACK)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTConvertBackBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder&
|
||||
setMPTokenIssuanceID(std::decay_t<typename SF_UINT192::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMPTokenIssuanceID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMPTAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder&
|
||||
setMPTAmount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMPTAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfHolderEncryptedAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder&
|
||||
setHolderEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfHolderEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfIssuerEncryptedAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder&
|
||||
setIssuerEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfIssuerEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAuditorEncryptedAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder&
|
||||
setAuditorEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAuditorEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfBlindingFactor (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder&
|
||||
setBlindingFactor(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfBlindingFactor] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfZKProof (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder&
|
||||
setZKProof(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfZKProof] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfBalanceCommitment (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTConvertBackBuilder&
|
||||
setBalanceCommitment(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfBalanceCommitment] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ConfidentialMPTConvertBack wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ConfidentialMPTConvertBack
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ConfidentialMPTConvertBack{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,129 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ConfidentialMPTMergeInboxBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ConfidentialMPTMergeInbox
|
||||
*
|
||||
* Type: ttCONFIDENTIAL_MPT_MERGE_INBOX (86)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureConfidentialTransfer
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ConfidentialMPTMergeInboxBuilder to construct new transactions.
|
||||
*/
|
||||
class ConfidentialMPTMergeInbox : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONFIDENTIAL_MPT_MERGE_INBOX;
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTMergeInbox transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ConfidentialMPTMergeInbox(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTMergeInbox");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT192::type::value_type
|
||||
getMPTokenIssuanceID() const
|
||||
{
|
||||
return this->tx_->at(sfMPTokenIssuanceID);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ConfidentialMPTMergeInbox transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ConfidentialMPTMergeInboxBuilder : public TransactionBuilderBase<ConfidentialMPTMergeInboxBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ConfidentialMPTMergeInboxBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param mPTokenIssuanceID The sfMPTokenIssuanceID field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ConfidentialMPTMergeInboxBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_UINT192::type::value_type> const& mPTokenIssuanceID, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ConfidentialMPTMergeInboxBuilder>(ttCONFIDENTIAL_MPT_MERGE_INBOX, account, sequence, fee)
|
||||
{
|
||||
setMPTokenIssuanceID(mPTokenIssuanceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTMergeInboxBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ConfidentialMPTMergeInboxBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONFIDENTIAL_MPT_MERGE_INBOX)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTMergeInboxBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTMergeInboxBuilder&
|
||||
setMPTokenIssuanceID(std::decay_t<typename SF_UINT192::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMPTokenIssuanceID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ConfidentialMPTMergeInbox wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ConfidentialMPTMergeInbox
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ConfidentialMPTMergeInbox{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,408 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBase.h>
|
||||
#include <xrpl/protocol_autogen/TransactionBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::transactions {
|
||||
|
||||
class ConfidentialMPTSendBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: ConfidentialMPTSend
|
||||
*
|
||||
* Type: ttCONFIDENTIAL_MPT_SEND (88)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureConfidentialTransfer
|
||||
* Privileges: NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use ConfidentialMPTSendBuilder to construct new transactions.
|
||||
*/
|
||||
class ConfidentialMPTSend : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttCONFIDENTIAL_MPT_SEND;
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTSend transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit ConfidentialMPTSend(std::shared_ptr<STTx const> tx)
|
||||
: TransactionBase(std::move(tx))
|
||||
{
|
||||
// Verify transaction type
|
||||
if (tx_->getTxnType() != txType)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTSend");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT192::type::value_type
|
||||
getMPTokenIssuanceID() const
|
||||
{
|
||||
return this->tx_->at(sfMPTokenIssuanceID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestination (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getDestination() const
|
||||
{
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestinationTag (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_UINT32::type::value_type>
|
||||
getDestinationTag() const
|
||||
{
|
||||
if (hasDestinationTag())
|
||||
{
|
||||
return this->tx_->at(sfDestinationTag);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfDestinationTag is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasDestinationTag() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDestinationTag);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSenderEncryptedAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getSenderEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->at(sfSenderEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestinationEncryptedAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getDestinationEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->at(sfDestinationEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfIssuerEncryptedAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getIssuerEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->at(sfIssuerEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAuditorEncryptedAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getAuditorEncryptedAmount() const
|
||||
{
|
||||
if (hasAuditorEncryptedAmount())
|
||||
{
|
||||
return this->tx_->at(sfAuditorEncryptedAmount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfAuditorEncryptedAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasAuditorEncryptedAmount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfAuditorEncryptedAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfZKProof (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getZKProof() const
|
||||
{
|
||||
return this->tx_->at(sfZKProof);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmountCommitment (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getAmountCommitment() const
|
||||
{
|
||||
return this->tx_->at(sfAmountCommitment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfBalanceCommitment (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getBalanceCommitment() const
|
||||
{
|
||||
return this->tx_->at(sfBalanceCommitment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfCredentialIDs (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VECTOR256::type::value_type>
|
||||
getCredentialIDs() const
|
||||
{
|
||||
if (hasCredentialIDs())
|
||||
{
|
||||
return this->tx_->at(sfCredentialIDs);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfCredentialIDs is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasCredentialIDs() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfCredentialIDs);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for ConfidentialMPTSend transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ConfidentialMPTSendBuilder : public TransactionBuilderBase<ConfidentialMPTSendBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new ConfidentialMPTSendBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param mPTokenIssuanceID The sfMPTokenIssuanceID field value.
|
||||
* @param destination The sfDestination field value.
|
||||
* @param senderEncryptedAmount The sfSenderEncryptedAmount field value.
|
||||
* @param destinationEncryptedAmount The sfDestinationEncryptedAmount field value.
|
||||
* @param issuerEncryptedAmount The sfIssuerEncryptedAmount field value.
|
||||
* @param zKProof The sfZKProof field value.
|
||||
* @param amountCommitment The sfAmountCommitment field value.
|
||||
* @param balanceCommitment The sfBalanceCommitment field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_UINT192::type::value_type> const& mPTokenIssuanceID, std::decay_t<typename SF_ACCOUNT::type::value_type> const& destination, std::decay_t<typename SF_VL::type::value_type> const& senderEncryptedAmount, std::decay_t<typename SF_VL::type::value_type> const& destinationEncryptedAmount, std::decay_t<typename SF_VL::type::value_type> const& issuerEncryptedAmount, std::decay_t<typename SF_VL::type::value_type> const& zKProof, std::decay_t<typename SF_VL::type::value_type> const& amountCommitment, std::decay_t<typename SF_VL::type::value_type> const& balanceCommitment, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<ConfidentialMPTSendBuilder>(ttCONFIDENTIAL_MPT_SEND, account, sequence, fee)
|
||||
{
|
||||
setMPTokenIssuanceID(mPTokenIssuanceID);
|
||||
setDestination(destination);
|
||||
setSenderEncryptedAmount(senderEncryptedAmount);
|
||||
setDestinationEncryptedAmount(destinationEncryptedAmount);
|
||||
setIssuerEncryptedAmount(issuerEncryptedAmount);
|
||||
setZKProof(zKProof);
|
||||
setAmountCommitment(amountCommitment);
|
||||
setBalanceCommitment(balanceCommitment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a ConfidentialMPTSendBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttCONFIDENTIAL_MPT_SEND)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for ConfidentialMPTSendBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/** @brief Transaction-specific field setters */
|
||||
|
||||
/**
|
||||
* @brief Set sfMPTokenIssuanceID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setMPTokenIssuanceID(std::decay_t<typename SF_UINT192::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMPTokenIssuanceID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestinationTag (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setDestinationTag(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestinationTag] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSenderEncryptedAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setSenderEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSenderEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestinationEncryptedAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setDestinationEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestinationEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfIssuerEncryptedAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setIssuerEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfIssuerEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAuditorEncryptedAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setAuditorEncryptedAmount(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAuditorEncryptedAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfZKProof (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setZKProof(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfZKProof] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmountCommitment (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setAmountCommitment(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmountCommitment] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfBalanceCommitment (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setBalanceCommitment(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfBalanceCommitment] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfCredentialIDs (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
ConfidentialMPTSendBuilder&
|
||||
setCredentialIDs(std::decay_t<typename SF_VECTOR256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfCredentialIDs] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the ConfidentialMPTSend wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
ConfidentialMPTSend
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return ConfidentialMPTSend{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -187,58 +187,6 @@ public:
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMutableFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfIssuerEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getIssuerEncryptionKey() const
|
||||
{
|
||||
if (hasIssuerEncryptionKey())
|
||||
{
|
||||
return this->tx_->at(sfIssuerEncryptionKey);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfIssuerEncryptionKey is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasIssuerEncryptionKey() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfIssuerEncryptionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAuditorEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getAuditorEncryptionKey() const
|
||||
{
|
||||
if (hasAuditorEncryptionKey())
|
||||
{
|
||||
return this->tx_->at(sfAuditorEncryptionKey);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfAuditorEncryptionKey is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasAuditorEncryptionKey() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfAuditorEncryptionKey);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -349,28 +297,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfIssuerEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceSetBuilder&
|
||||
setIssuerEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfIssuerEncryptionKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAuditorEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceSetBuilder&
|
||||
setAuditorEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAuditorEncryptionKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the MPTokenIssuanceSet wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
|
||||
@@ -57,32 +57,6 @@ public:
|
||||
{
|
||||
return this->tx_->at(sfVaultID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMemoData (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getMemoData() const
|
||||
{
|
||||
if (hasMemoData())
|
||||
{
|
||||
return this->tx_->at(sfMemoData);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMemoData is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMemoData() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMemoData);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -138,17 +112,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMemoData (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
VaultDeleteBuilder&
|
||||
setMemoData(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMemoData] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the VaultDelete wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
|
||||
@@ -24,10 +24,6 @@ public:
|
||||
ApplyFlags flags,
|
||||
beast::Journal journal = beast::Journal{beast::Journal::getNullSink()});
|
||||
|
||||
// Convenience constructor used only by tests that build an ApplyContext
|
||||
// directly (e.g. invariant checks). Production always uses the parentBatchId
|
||||
// constructor above; this one fixes parentBatchId to std::nullopt and so is
|
||||
// never valid for a batch inner (hence the TapBatch assert).
|
||||
explicit ApplyContext(
|
||||
ServiceRegistry& registry,
|
||||
OpenView& base,
|
||||
@@ -128,7 +124,7 @@ private:
|
||||
ApplyFlags flags_;
|
||||
std::optional<ApplyViewImpl> view_;
|
||||
|
||||
// The ID of the batch transaction we are executing under, if set.
|
||||
// The ID of the batch transaction we are executing under, if seated.
|
||||
std::optional<uint256 const> parentBatchId_;
|
||||
};
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/applySteps.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
@@ -180,14 +179,13 @@ public:
|
||||
static NotTEC
|
||||
checkSign(PreclaimContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
checkBatchSign(PreclaimContext const& ctx);
|
||||
|
||||
// Returns the fee in fee units, not scaled for load.
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
// Returns the base fee plus extra base fee units, not scaled for load.
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx, std::uint32_t extraBaseFeeMultiplier);
|
||||
|
||||
/* Do NOT define an invokePreflight function in a derived class.
|
||||
Instead, define:
|
||||
|
||||
@@ -370,12 +368,7 @@ protected:
|
||||
std::optional<uint256 const> const& parentBatchId,
|
||||
AccountID const& idAccount,
|
||||
STObject const& sigObject,
|
||||
beast::Journal const j,
|
||||
// A batch may carry an inner from an account that an earlier inner
|
||||
// creates, so the signer account need not exist yet; when it does not,
|
||||
// only its own master key may authorize it. Normal transactions require
|
||||
// the account to already exist.
|
||||
bool permitUncreatedAccount = false);
|
||||
beast::Journal const j);
|
||||
|
||||
// Base class always returns true
|
||||
static bool
|
||||
@@ -415,8 +408,25 @@ protected:
|
||||
std::optional<T> value,
|
||||
unit::ValueUnit<Unit, T> min = unit::ValueUnit<Unit, T>{});
|
||||
|
||||
// Signature-authorization helpers. protected so the Batch transactor can
|
||||
// reuse them when validating each BatchSigner in Batch::checkBatchSign.
|
||||
private:
|
||||
static NotTEC
|
||||
checkPermission(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
std::unordered_set<GranularPermissionType>& heldGranularPermissions);
|
||||
|
||||
std::pair<TER, XRPAmount>
|
||||
reset(XRPAmount fee);
|
||||
|
||||
TER
|
||||
consumeSeqProxy(SLE::pointer const& sleAccount);
|
||||
|
||||
TER
|
||||
payFee();
|
||||
|
||||
std::tuple<TER, XRPAmount, bool>
|
||||
processPersistentChanges(TER result, XRPAmount fee);
|
||||
|
||||
static NotTEC
|
||||
checkSingleSign(
|
||||
ReadView const& view,
|
||||
@@ -433,24 +443,6 @@ protected:
|
||||
STObject const& sigObject,
|
||||
beast::Journal const j);
|
||||
|
||||
private:
|
||||
static NotTEC
|
||||
checkPermission(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
std::unordered_set<GranularPermissionType>& heldGranularPermissions);
|
||||
|
||||
std::pair<TER, XRPAmount>
|
||||
reset(XRPAmount fee);
|
||||
|
||||
TER
|
||||
consumeSeqProxy(SLE::pointer const& sleAccount);
|
||||
TER
|
||||
payFee();
|
||||
|
||||
std::tuple<TER, XRPAmount, bool>
|
||||
processPersistentChanges(TER result, XRPAmount fee);
|
||||
|
||||
void trapTransaction(uint256) const;
|
||||
|
||||
/** Performs early sanity checks on the account and fee fields.
|
||||
|
||||
@@ -375,35 +375,16 @@ public:
|
||||
*/
|
||||
class ValidAmounts
|
||||
{
|
||||
std::vector<SLE::const_pointer> afterEntries_;
|
||||
std::vector<std::shared_ptr<SLE const>> afterEntries_;
|
||||
|
||||
public:
|
||||
void
|
||||
visitEntry(bool, SLE::const_ref, SLE::const_ref);
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Verify that when an object with an associated pseudo-account is deleted,
|
||||
* its pseudo-account is also deleted.
|
||||
*
|
||||
* The reverse (pseudo-account deleted → object deleted) is enforced by
|
||||
* AccountRootsDeletedClean via getPseudoAccountFields().
|
||||
*/
|
||||
class ObjectHasPseudoAccount
|
||||
{
|
||||
public:
|
||||
void
|
||||
visitEntry(bool, SLE::const_ref, SLE::const_ref);
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
|
||||
private:
|
||||
std::vector<SLE::const_pointer> deletedObjSles_;
|
||||
};
|
||||
// additional invariant checks can be declared above and then added to this
|
||||
// tuple
|
||||
using InvariantChecks = std::tuple<
|
||||
@@ -432,11 +413,9 @@ using InvariantChecks = std::tuple<
|
||||
ValidLoanBroker,
|
||||
ValidLoan,
|
||||
ValidVault,
|
||||
ValidConfidentialMPToken,
|
||||
ValidMPTPayment,
|
||||
ValidAmounts,
|
||||
ValidMPTTransfer,
|
||||
ObjectHasPseudoAccount>;
|
||||
ValidMPTTransfer>;
|
||||
|
||||
/**
|
||||
* @brief get a tuple of all invariant checks
|
||||
|
||||
@@ -36,42 +36,17 @@ class ValidMPTIssuance
|
||||
std::vector<std::shared_ptr<SLE const>> deletedHoldings_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Track MPT issuance and holding creations, deletions, and
|
||||
* mutations.
|
||||
*
|
||||
* @param isDelete Whether the ledger entry is being deleted.
|
||||
* @param before The ledger entry before transaction application.
|
||||
* @param after The ledger entry after transaction application.
|
||||
*/
|
||||
void
|
||||
visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after);
|
||||
visitEntry(bool, SLE::const_ref, SLE::const_ref);
|
||||
|
||||
/**
|
||||
* @brief Verify MPT issuance invariants after transaction application.
|
||||
*
|
||||
* @param tx The transaction being checked.
|
||||
* @param result The transaction result code.
|
||||
* @param fee The fee charged by the transaction.
|
||||
* @param view The ledger view after transaction application.
|
||||
* @param j Journal used for diagnostics.
|
||||
* @return true if the invariant checks pass, otherwise false.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
finalize(
|
||||
STTx const& tx,
|
||||
TER const result,
|
||||
XRPAmount const fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) const;
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Verify public MPT amount and outstanding amount accounting.
|
||||
*
|
||||
* Checks that OutstandingAmount does not exceed MaximumAmount and that
|
||||
* OutstandingAmount after application equals OutstandingAmount before
|
||||
* application plus the net holder balance delta.
|
||||
/** Verify:
|
||||
* - OutstandingAmount <= MaximumAmount for any MPT
|
||||
* - OutstandingAmount after = OutstandingAmount before +
|
||||
* sum (MPT after - MPT before) - this is total MPT credit/debit
|
||||
*/
|
||||
class ValidMPTPayment
|
||||
{
|
||||
@@ -89,104 +64,11 @@ class ValidMPTPayment
|
||||
hash_map<uint192, MPTData> data_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Track MPT amount and outstanding amount changes.
|
||||
*
|
||||
* @param isDelete Whether the ledger entry is being deleted.
|
||||
* @param before The ledger entry before transaction application.
|
||||
* @param after The ledger entry after transaction application.
|
||||
*/
|
||||
void
|
||||
visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after);
|
||||
visitEntry(bool, SLE::const_ref, SLE::const_ref);
|
||||
|
||||
/**
|
||||
* @brief Verify public MPT payment accounting invariants.
|
||||
*
|
||||
* @param tx The transaction being checked.
|
||||
* @param result The transaction result code.
|
||||
* @param fee The fee charged by the transaction.
|
||||
* @param view The ledger view after transaction application.
|
||||
* @param j Journal used for diagnostics.
|
||||
* @return true if the invariant checks pass, otherwise false.
|
||||
*/
|
||||
bool
|
||||
finalize(
|
||||
STTx const& tx,
|
||||
TER const result,
|
||||
XRPAmount const fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Invariants: Confidential MPToken consistency
|
||||
*
|
||||
* - Convert/ConvertBack symmetry:
|
||||
* Regular MPToken balance change (±X) == COA (Confidential Outstanding Amount) change (∓X)
|
||||
* - Cannot delete MPToken with non-zero confidential state:
|
||||
* Cannot delete if sfIssuerEncryptedBalance exists
|
||||
* Cannot delete if sfConfidentialBalanceInbox and sfConfidentialBalanceSpending exist
|
||||
* - Privacy flag consistency:
|
||||
* MPToken confidential balance fields can only be created or changed if
|
||||
* lsfMPTCanHoldConfidentialBalance is set on the issuance.
|
||||
* - Encrypted field existence consistency:
|
||||
* If sfConfidentialBalanceSpending/sfConfidentialBalanceInbox exists, then
|
||||
* sfIssuerEncryptedBalance must also exist (and vice versa). If
|
||||
* sfAuditorEncryptedBalance exists, then those core encrypted balance fields
|
||||
* must also exist.
|
||||
* - COA <= OutstandingAmount:
|
||||
* Confidential outstanding balance cannot exceed total outstanding.
|
||||
* - Verifies sfConfidentialBalanceVersion is changed whenever sfConfidentialBalanceSpending is
|
||||
* modified on an MPToken.
|
||||
*/
|
||||
class ValidConfidentialMPToken
|
||||
{
|
||||
struct Changes
|
||||
{
|
||||
std::int64_t mptAmountDelta = 0;
|
||||
std::int64_t coaDelta = 0;
|
||||
std::int64_t outstandingDelta = 0;
|
||||
SLE::const_pointer issuance;
|
||||
bool deletedWithEncrypted = false;
|
||||
bool badConsistency = false;
|
||||
bool badCOA = false;
|
||||
bool changesConfidentialFields = false;
|
||||
bool badVersion = false;
|
||||
};
|
||||
std::map<uint192, Changes> changes_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Track confidential MPT balance, issuance, and version changes.
|
||||
*
|
||||
* @param isDelete Whether the ledger entry is being deleted.
|
||||
* @param before The ledger entry before transaction application.
|
||||
* @param after The ledger entry after transaction application.
|
||||
*/
|
||||
void
|
||||
visitEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after);
|
||||
|
||||
/**
|
||||
* @brief Verify confidential MPT accounting and encrypted-field
|
||||
* invariants.
|
||||
*
|
||||
* @param tx The transaction being checked.
|
||||
* @param result The transaction result code.
|
||||
* @param fee The fee charged by the transaction.
|
||||
* @param view The ledger view after transaction application.
|
||||
* @param j Journal used for diagnostics.
|
||||
* @return true if the invariant checks pass, otherwise false.
|
||||
*/
|
||||
bool
|
||||
finalize(
|
||||
STTx const& tx,
|
||||
TER const result,
|
||||
XRPAmount const fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
};
|
||||
|
||||
class ValidMPTTransfer
|
||||
@@ -203,36 +85,11 @@ class ValidMPTTransfer
|
||||
hash_map<uint256, bool> deletedAuthorized_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Track MPT balance changes and deleted authorization state.
|
||||
*
|
||||
* @param isDelete Whether the ledger entry is being deleted.
|
||||
* @param before The ledger entry before transaction application.
|
||||
* @param after The ledger entry after transaction application.
|
||||
*/
|
||||
void
|
||||
visitEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after);
|
||||
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
|
||||
|
||||
/**
|
||||
* @brief Verify MPT transfer authorization invariants.
|
||||
*
|
||||
* @param tx The transaction being checked.
|
||||
* @param result The transaction result code.
|
||||
* @param fee The fee charged by the transaction.
|
||||
* @param view The ledger view after transaction application.
|
||||
* @param j Journal used for diagnostics.
|
||||
* @return true if the invariant checks pass, otherwise false.
|
||||
*/
|
||||
bool
|
||||
finalize(
|
||||
STTx const& tx,
|
||||
TER const result,
|
||||
XRPAmount const fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j);
|
||||
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -242,13 +99,7 @@ private:
|
||||
* finalize() runs, so their authorization state is captured during
|
||||
* visitEntry() and stored in deletedAuthorized_. For deleted MPTokens,
|
||||
* returns true if reqAuth is false or lsfMPTAuthorized was set at deletion.
|
||||
* For existing MPTokens, returns the result of requireAuth().
|
||||
*
|
||||
* @param view The ledger view after transaction application.
|
||||
* @param mptid The MPToken issuance ID.
|
||||
* @param holder The holder account being checked.
|
||||
* @param requireAuth Whether the issuance requires explicit authorization.
|
||||
* @return true if the holder is authorized, otherwise false.
|
||||
* For existing MPTokens, returns the result of requireAuth()
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isAuthorized(
|
||||
|
||||
@@ -27,7 +27,7 @@ checkFreeze(
|
||||
}
|
||||
}
|
||||
|
||||
if (auto sle = view.read(keylet::trustLine(src, dst, currency)))
|
||||
if (auto sle = view.read(keylet::line(src, dst, currency)))
|
||||
{
|
||||
if (sle->isFlag((dst > src) ? lsfHighFreeze : lsfLowFreeze))
|
||||
{
|
||||
@@ -71,8 +71,8 @@ checkNoRipple(
|
||||
beast::Journal j)
|
||||
{
|
||||
// fetch the ripple lines into and out of this node
|
||||
auto sleIn = view.read(keylet::trustLine(prev, cur, currency));
|
||||
auto sleOut = view.read(keylet::trustLine(cur, next, currency));
|
||||
auto sleIn = view.read(keylet::line(prev, cur, currency));
|
||||
auto sleOut = view.read(keylet::line(cur, next, currency));
|
||||
|
||||
if (!sleIn || !sleOut)
|
||||
return terNO_LINE;
|
||||
|
||||
@@ -159,11 +159,6 @@ public:
|
||||
beast::Journal const& journal);
|
||||
|
||||
private:
|
||||
/** Returns IgnoreFreeze when the withdrawer is the issuer of a pool
|
||||
* asset (post-fixCleanup3_3_0), ZeroIfFrozen otherwise. */
|
||||
[[nodiscard]] FreezeHandling
|
||||
issuerFreezeHandling() const;
|
||||
|
||||
std::pair<TER, bool>
|
||||
applyGuts(Sandbox& view);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -59,12 +61,6 @@ public:
|
||||
ttLOAN_MANAGE,
|
||||
ttLOAN_PAY,
|
||||
});
|
||||
|
||||
private:
|
||||
// Skips signature verification for inner txns, so keep it private: it must
|
||||
// only be reached through Batch::checkSign.
|
||||
static NotTEC
|
||||
checkBatchSign(PreclaimContext const& ctx);
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Allows an MPT issuer to clawback confidential balances from a holder.
|
||||
*
|
||||
* This transaction enables the issuer of an MPToken Issuance (with clawback
|
||||
* enabled) to reclaim confidential tokens from a holder's account. Unlike
|
||||
* regular clawback, the issuer cannot see the holder's balance directly.
|
||||
* Instead, the issuer must provide a zero-knowledge proof that demonstrates
|
||||
* they know the exact encrypted balance amount.
|
||||
*
|
||||
* @par Cryptographic Operations:
|
||||
* - **Equality Proof Verification**: Verifies that the issuer's revealed
|
||||
* amount matches the holder's encrypted balance using the issuer's
|
||||
* ElGamal private key.
|
||||
*
|
||||
* @see ConfidentialMPTSend, ConfidentialMPTConvert
|
||||
*/
|
||||
class ConfidentialMPTClawback : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ConfidentialMPTClawback(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Converts public (plaintext) MPT balance to confidential (encrypted)
|
||||
* balance.
|
||||
*
|
||||
* This transaction allows a token holder to convert their publicly visible
|
||||
* MPToken balance into an encrypted confidential balance. Once converted,
|
||||
* the balance can only be spent using ConfidentialMPTSend transactions and
|
||||
* remains hidden from public view on the ledger.
|
||||
*
|
||||
* @par Cryptographic Operations:
|
||||
* - **Schnorr Proof Verification**: When registering a new ElGamal public key,
|
||||
* verifies proof of knowledge of the corresponding private key.
|
||||
* - **Revealed Amount Verification**: Verifies that the provided encrypted
|
||||
* amounts (for holder, issuer, and optionally auditor) all encrypt the
|
||||
* same plaintext amount using the provided blinding factor.
|
||||
*
|
||||
* @see ConfidentialMPTConvertBack, ConfidentialMPTSend
|
||||
*/
|
||||
class ConfidentialMPTConvert : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ConfidentialMPTConvert(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,62 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Converts confidential (encrypted) MPT balance back to public
|
||||
* (plaintext) balance.
|
||||
*
|
||||
* This transaction allows a token holder to convert their encrypted
|
||||
* confidential balance back into a publicly visible MPToken balance. The
|
||||
* holder must prove they have sufficient confidential balance without
|
||||
* revealing the actual balance amount.
|
||||
*
|
||||
* @par Cryptographic Operations:
|
||||
* - **Revealed Amount Verification**: Verifies that the provided encrypted
|
||||
* amounts correctly encrypt the conversion amount.
|
||||
* - **Pedersen Linkage Proof**: Verifies that the provided balance commitment
|
||||
* correctly links to the holder's encrypted spending balance.
|
||||
* - **Bulletproof Range Proof**: Verifies that the remaining balance (after
|
||||
* conversion) is non-negative, ensuring the holder has sufficient funds.
|
||||
*
|
||||
* @see ConfidentialMPTConvert, ConfidentialMPTSend
|
||||
*/
|
||||
class ConfidentialMPTConvertBack : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ConfidentialMPTConvertBack(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,63 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Merges the confidential inbox balance into the spending balance.
|
||||
*
|
||||
* In the confidential transfer system, incoming funds are deposited into an
|
||||
* "inbox" balance that the recipient cannot immediately spend. This prevents
|
||||
* front-running attacks where an attacker could invalidate a pending
|
||||
* transaction by sending funds to the sender. This transaction merges the
|
||||
* inbox into the spending balance, making those funds available for spending.
|
||||
*
|
||||
* @par Cryptographic Operations:
|
||||
* - **Homomorphic Addition**: Adds the encrypted inbox balance to the
|
||||
* encrypted spending balance using ElGamal homomorphic properties.
|
||||
* - **Zero Encryption**: Resets the inbox to an encryption of zero.
|
||||
*
|
||||
* @note This transaction requires no zero-knowledge proofs because it only
|
||||
* combines encrypted values that the holder already owns. The
|
||||
* homomorphic properties of ElGamal encryption ensure correctness.
|
||||
*
|
||||
* @see ConfidentialMPTSend, ConfidentialMPTConvert
|
||||
*/
|
||||
class ConfidentialMPTMergeInbox : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ConfidentialMPTMergeInbox(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,72 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
* @brief Transfers confidential MPT tokens between holders privately.
|
||||
*
|
||||
* This transaction enables private token transfers where the transfer amount
|
||||
* is hidden from public view. Both sender and recipient must have initialized
|
||||
* confidential balances. The transaction provides encrypted amounts for all
|
||||
* parties (sender, destination, issuer, and optionally auditor) along with
|
||||
* zero-knowledge proofs that verify correctness without revealing the amount.
|
||||
*
|
||||
* @par Cryptographic Operations:
|
||||
* - **Multi-Ciphertext Equality Proof**: Verifies that all encrypted amounts
|
||||
* (sender, destination, issuer, auditor) encrypt the same plaintext value.
|
||||
* - **Amount Pedersen Linkage Proof**: Verifies that the amount commitment
|
||||
* correctly links to the sender's encrypted amount.
|
||||
* - **Balance Pedersen Linkage Proof**: Verifies that the balance commitment
|
||||
* correctly links to the sender's encrypted spending balance.
|
||||
* - **Bulletproof Range Proof**: Verifies remaining balance and
|
||||
* transfer amount are non-negative.
|
||||
*
|
||||
* @note Funds are deposited into the destination's inbox, not spending
|
||||
* balance. The recipient must call ConfidentialMPTMergeInbox to make
|
||||
* received funds spendable.
|
||||
*
|
||||
* @see ConfidentialMPTMergeInbox, ConfidentialMPTConvert,
|
||||
* ConfidentialMPTConvertBack
|
||||
*/
|
||||
class ConfidentialMPTSend : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit ConfidentialMPTSend(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -190,8 +190,17 @@ Condition::deserialize(Slice s, std::error_code& ec)
|
||||
break;
|
||||
|
||||
case 1: // PrefixSha256
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
case 2: // ThresholdSha256
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
case 3: // RsaSha256
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
case 4: // Ed25519Sha256
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
@@ -101,8 +101,20 @@ Fulfillment::deserialize(Slice s, std::error_code& ec)
|
||||
break;
|
||||
|
||||
case safeCast<TagType>(Type::PrefixSha256):
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
break;
|
||||
|
||||
case safeCast<TagType>(Type::ThresholdSha256):
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
break;
|
||||
|
||||
case safeCast<TagType>(Type::RsaSha256):
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
break;
|
||||
|
||||
case safeCast<TagType>(Type::Ed25519Sha256):
|
||||
ec = Error::UnsupportedType;
|
||||
return {};
|
||||
|
||||
@@ -42,8 +42,7 @@ CanonicalTXSet::accountKey(AccountID const& account)
|
||||
void
|
||||
CanonicalTXSet::insert(std::shared_ptr<STTx const> txn)
|
||||
{
|
||||
Key const key(
|
||||
accountKey(txn->getAccountID(sfAccount)), txn->getSeqProxy(), txn->getTransactionID());
|
||||
Key key(accountKey(txn->getAccountID(sfAccount)), txn->getSeqProxy(), txn->getTransactionID());
|
||||
map_.emplace(key, std::move(txn));
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ Ledger::Ledger(
|
||||
}
|
||||
|
||||
{
|
||||
auto sle = std::make_shared<SLE>(keylet::feeSettings());
|
||||
auto sle = std::make_shared<SLE>(keylet::fees());
|
||||
// Whether featureXRPFees is supported will depend on startup options.
|
||||
if (std::ranges::find(amendments, featureXRPFees) != amendments.end())
|
||||
{
|
||||
@@ -560,7 +560,7 @@ Ledger::setup()
|
||||
|
||||
try
|
||||
{
|
||||
if (auto const sle = read(keylet::feeSettings()))
|
||||
if (auto const sle = read(keylet::fees()))
|
||||
{
|
||||
bool oldFees = false;
|
||||
bool newFees = false;
|
||||
|
||||
@@ -70,7 +70,7 @@ isVaultPseudoAccountFrozen(
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
auto const mptIssuance = view.read(keylet::mptokenIssuance(mptShare.getMptID()));
|
||||
auto const mptIssuance = view.read(keylet::mptIssuance(mptShare.getMptID()));
|
||||
if (mptIssuance == nullptr)
|
||||
return false; // zero MPToken won't block deletion of MPTokenIssuance
|
||||
|
||||
|
||||
@@ -555,7 +555,7 @@ ammLPHolds(
|
||||
auto const currency = ammLPTCurrency(asset1, asset2);
|
||||
STAmount amount;
|
||||
|
||||
auto const sle = view.read(keylet::trustLine(lpAccount, ammAccount, currency));
|
||||
auto const sle = view.read(keylet::line(lpAccount, ammAccount, currency));
|
||||
if (!sle)
|
||||
{
|
||||
amount.clear(Issue{currency, ammAccount});
|
||||
@@ -647,7 +647,7 @@ ammAccountHolds(ReadView const& view, AccountID const& ammAccountID, Asset const
|
||||
}
|
||||
else if (
|
||||
auto const sle =
|
||||
view.read(keylet::trustLine(ammAccountID, issue.account, issue.currency));
|
||||
view.read(keylet::line(ammAccountID, issue.account, issue.currency));
|
||||
sle && !isFrozen(view, ammAccountID, issue.currency, issue.account))
|
||||
{
|
||||
STAmount amount = (*sle)[sfBalance];
|
||||
|
||||
@@ -346,9 +346,9 @@ verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, b
|
||||
}
|
||||
|
||||
TER
|
||||
checkDepositPreauth(
|
||||
verifyDepositPreauth(
|
||||
STTx const& tx,
|
||||
ReadView const& view,
|
||||
ApplyView& view,
|
||||
AccountID const& src,
|
||||
AccountID const& dst,
|
||||
SLE::const_ref sleDst,
|
||||
@@ -360,27 +360,9 @@ checkDepositPreauth(
|
||||
// 2. If src is deposit preauthorized by dst (either by account or by
|
||||
// credentials).
|
||||
|
||||
if (sleDst && ((sleDst->getFlags() & lsfDepositAuth) != 0u))
|
||||
{
|
||||
if (src != dst)
|
||||
{
|
||||
if (!view.exists(keylet::depositPreauth(dst, src)))
|
||||
{
|
||||
return !tx.isFieldPresent(sfCredentialIDs)
|
||||
? tecNO_PERMISSION
|
||||
: credentials::authorizedDepositPreauth(
|
||||
view, tx.getFieldV256(sfCredentialIDs), dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool const credentialsPresent = tx.isFieldPresent(sfCredentialIDs);
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
cleanupExpiredCredentials(STTx const& tx, ApplyView& view, beast::Journal j)
|
||||
{
|
||||
if (tx.isFieldPresent(sfCredentialIDs))
|
||||
if (credentialsPresent)
|
||||
{
|
||||
auto const foundExpired =
|
||||
credentials::removeExpired(view, tx.getFieldV256(sfCredentialIDs), j);
|
||||
@@ -390,22 +372,20 @@ cleanupExpiredCredentials(STTx const& tx, ApplyView& view, beast::Journal j)
|
||||
return tecEXPIRED;
|
||||
}
|
||||
|
||||
if (sleDst && sleDst->isFlag(lsfDepositAuth))
|
||||
{
|
||||
if (src != dst)
|
||||
{
|
||||
if (!view.exists(keylet::depositPreauth(dst, src)))
|
||||
{
|
||||
return !credentialsPresent ? tecNO_PERMISSION
|
||||
: credentials::authorizedDepositPreauth(
|
||||
view, tx.getFieldV256(sfCredentialIDs), dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
verifyDepositPreauth(
|
||||
STTx const& tx,
|
||||
ApplyView& view,
|
||||
AccountID const& src,
|
||||
AccountID const& dst,
|
||||
SLE::const_ref sleDst,
|
||||
beast::Journal j)
|
||||
{
|
||||
if (auto const err = cleanupExpiredCredentials(tx, view, j); !isTesSuccess(err))
|
||||
return err;
|
||||
|
||||
return checkDepositPreauth(tx, view, src, dst, sleDst, j);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace xrpl {
|
||||
bool
|
||||
isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue)
|
||||
{
|
||||
if (auto const sle = view.read(keylet::mptokenIssuance(mptIssue.getMptID())))
|
||||
if (auto const sle = view.read(keylet::mptIssuance(mptIssue.getMptID())))
|
||||
return sle->isFlag(lsfMPTLocked);
|
||||
return false;
|
||||
}
|
||||
@@ -95,7 +95,7 @@ transferRate(ReadView const& view, MPTID const& issuanceID)
|
||||
// fee is 0-50,000 (0-50%), rate is 1,000,000,000-2,000,000,000
|
||||
// For example, if transfer fee is 50% then 10,000 * 50,000 = 500,000
|
||||
// which represents 50% of 1,000,000,000
|
||||
if (auto const sle = view.read(keylet::mptokenIssuance(issuanceID));
|
||||
if (auto const sle = view.read(keylet::mptIssuance(issuanceID));
|
||||
sle && sle->isFieldPresent(sfTransferFee))
|
||||
{
|
||||
auto const fee = sle->getFieldU16(sfTransferFee);
|
||||
@@ -110,7 +110,7 @@ transferRate(ReadView const& view, MPTID const& issuanceID)
|
||||
canAddHolding(ReadView const& view, MPTIssue const& mptIssue)
|
||||
{
|
||||
auto mptID = mptIssue.getMptID();
|
||||
auto issuance = view.read(keylet::mptokenIssuance(mptID));
|
||||
auto issuance = view.read(keylet::mptIssuance(mptID));
|
||||
if (!issuance)
|
||||
{
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
@@ -132,7 +132,7 @@ addEmptyHolding(
|
||||
beast::Journal journal)
|
||||
{
|
||||
auto const& mptID = mptIssue.getMptID();
|
||||
auto const mpt = view.peek(keylet::mptokenIssuance(mptID));
|
||||
auto const mpt = view.peek(keylet::mptIssuance(mptID));
|
||||
if (!mpt)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
if (mpt->isFlag(lsfMPTLocked))
|
||||
@@ -204,7 +204,7 @@ authorizeMPToken(
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
// Defensive check before we attempt to create MPToken for the issuer
|
||||
auto const mpt = view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
auto const mpt = view.read(keylet::mptIssuance(mptIssuanceID));
|
||||
if (!mpt || mpt->getAccountID(sfIssuer) == account)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
@@ -230,7 +230,7 @@ authorizeMPToken(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
auto const sleMptIssuance = view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
auto const sleMptIssuance = view.read(keylet::mptIssuance(mptIssuanceID));
|
||||
if (!sleMptIssuance)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -290,15 +290,6 @@ removeEmptyHolding(
|
||||
(view.rules().enabled(fixCleanup3_1_3) && (*mptoken)[~sfLockedAmount].valueOr(0) != 0))
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
// Don't delete if the token still has confidential balances
|
||||
if (mptoken->isFieldPresent(sfConfidentialBalanceInbox) ||
|
||||
mptoken->isFieldPresent(sfConfidentialBalanceSpending) ||
|
||||
mptoken->isFieldPresent(sfIssuerEncryptedBalance) ||
|
||||
mptoken->isFieldPresent(sfAuditorEncryptedBalance))
|
||||
{
|
||||
return tecHAS_OBLIGATIONS;
|
||||
}
|
||||
|
||||
return authorizeMPToken(
|
||||
view,
|
||||
{}, // priorBalance
|
||||
@@ -317,19 +308,7 @@ requireAuth(
|
||||
AuthType authType,
|
||||
std::uint8_t depth)
|
||||
{
|
||||
bool const fix330Enabled = view.rules().enabled(fixCleanup3_3_0);
|
||||
bool const featureSAVEnabled = view.rules().enabled(featureSingleAssetVault);
|
||||
bool const featureMPTV2Enabled = view.rules().enabled(featureMPTokensV2);
|
||||
|
||||
// Pseudo-accounts (Vault, LoanBroker, AMM) hold assets on behalf of their participants.
|
||||
// They are implicitly authorized for any MPT they hold, including vault shares whose
|
||||
// underlying asset would otherwise require auth.
|
||||
auto const isPseudoAccountExempt = [&] {
|
||||
return (featureSAVEnabled || featureMPTV2Enabled) &&
|
||||
isPseudoAccount(view, account, {&sfVaultID, &sfLoanBrokerID, &sfAMMID});
|
||||
};
|
||||
|
||||
auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID());
|
||||
auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
|
||||
auto const sleIssuance = view.read(mptID);
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
@@ -340,9 +319,7 @@ requireAuth(
|
||||
if (mptIssuer == account) // Issuer won't have MPToken
|
||||
return tesSUCCESS;
|
||||
|
||||
// Post-fix330: exempt before the recursive underlying-asset auth check.
|
||||
if (fix330Enabled && isPseudoAccountExempt())
|
||||
return tesSUCCESS;
|
||||
bool const featureSAVEnabled = view.rules().enabled(featureSingleAssetVault);
|
||||
|
||||
if (featureSAVEnabled)
|
||||
{
|
||||
@@ -405,9 +382,13 @@ requireAuth(
|
||||
// belong to someone who is explicitly authorized e.g. a vault owner.
|
||||
}
|
||||
|
||||
// Pre-fix330: exempt after domain/sleToken checks, preserving prior behavior.
|
||||
if (!fix330Enabled && isPseudoAccountExempt())
|
||||
return tesSUCCESS;
|
||||
bool const featureMPTV2Enabled = view.rules().enabled(featureMPTokensV2);
|
||||
if (featureSAVEnabled || featureMPTV2Enabled)
|
||||
{
|
||||
// Implicitly authorize Vault, LoanBroker, and AMM pseudo-accounts
|
||||
if (isPseudoAccount(view, account, {&sfVaultID, &sfLoanBrokerID, &sfAMMID}))
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
// mptoken must be authorized if issuance enabled requireAuth
|
||||
if (sleIssuance->isFlag(lsfMPTRequireAuth) &&
|
||||
@@ -425,7 +406,7 @@ enforceMPTokenAuthorization(
|
||||
XRPAmount const& priorBalance, // for MPToken authorization
|
||||
beast::Journal j)
|
||||
{
|
||||
auto const sleIssuance = view.read(keylet::mptokenIssuance(mptIssuanceID));
|
||||
auto const sleIssuance = view.read(keylet::mptIssuance(mptIssuanceID));
|
||||
if (!sleIssuance)
|
||||
return tefINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
@@ -549,7 +530,7 @@ canTransfer(
|
||||
WaiveMPTCanTransfer waive,
|
||||
std::uint8_t depth)
|
||||
{
|
||||
auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID());
|
||||
auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
|
||||
auto const sleIssuance = view.read(mptID);
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
@@ -603,7 +584,7 @@ canTrade(ReadView const& view, Asset const& asset, std::uint8_t depth)
|
||||
return asset.visit(
|
||||
[&](Issue const&) -> TER { return tesSUCCESS; },
|
||||
[&](MPTIssue const& mptIssue) -> TER {
|
||||
auto const sleIssuance = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
|
||||
auto const sleIssuance = view.read(keylet::mptIssuance(mptIssue.getMptID()));
|
||||
if (!sleIssuance)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
if (!sleIssuance->isFlag(lsfMPTCanTrade))
|
||||
@@ -657,7 +638,7 @@ TER
|
||||
lockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount, beast::Journal j)
|
||||
{
|
||||
auto const mptIssue = amount.get<MPTIssue>();
|
||||
auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID());
|
||||
auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
|
||||
auto sleIssuance = view.peek(mptID);
|
||||
if (!sleIssuance)
|
||||
{ // LCOV_EXCL_START
|
||||
@@ -762,7 +743,7 @@ unlockEscrowMPT(
|
||||
|
||||
auto const& issuer = netAmount.getIssuer();
|
||||
auto const& mptIssue = netAmount.get<MPTIssue>();
|
||||
auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID());
|
||||
auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
|
||||
auto sleIssuance = view.peek(mptID);
|
||||
if (!sleIssuance)
|
||||
{ // LCOV_EXCL_START
|
||||
@@ -946,7 +927,7 @@ checkCreateMPT(
|
||||
if (mptIssue.getIssuer() == holder)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const mptIssuanceID = keylet::mptokenIssuance(mptIssue.getMptID());
|
||||
auto const mptIssuanceID = keylet::mptIssuance(mptIssue.getMptID());
|
||||
auto const mptokenID = keylet::mptoken(mptIssuanceID.key, holder);
|
||||
if (!view.exists(mptokenID))
|
||||
{
|
||||
@@ -982,7 +963,7 @@ availableMPTAmount(SLE const& sleIssuance)
|
||||
std::int64_t
|
||||
availableMPTAmount(ReadView const& view, MPTID const& mptID)
|
||||
{
|
||||
auto const sle = view.read(keylet::mptokenIssuance(mptID));
|
||||
auto const sle = view.read(keylet::mptIssuance(mptID));
|
||||
if (!sle)
|
||||
Throw<std::runtime_error>(transHuman(tecINTERNAL));
|
||||
return availableMPTAmount(*sle);
|
||||
@@ -1006,7 +987,7 @@ issuerFundsToSelfIssue(ReadView const& view, MPTIssue const& issue)
|
||||
{
|
||||
STAmount amount{issue};
|
||||
|
||||
auto const sle = view.read(keylet::mptokenIssuance(issue));
|
||||
auto const sle = view.read(keylet::mptIssuance(issue));
|
||||
if (!sle)
|
||||
return amount;
|
||||
auto const available = availableMPTAmount(*sle);
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace xrpl::nft {
|
||||
static SLE::const_pointer
|
||||
locatePage(ReadView const& view, AccountID const& owner, uint256 const& id)
|
||||
{
|
||||
auto const first = keylet::nftokenPage(keylet::nftokenPageMin(owner), id);
|
||||
auto const last = keylet::nftokenPageMax(owner);
|
||||
auto const first = keylet::nftpage(keylet::nftpageMin(owner), id);
|
||||
auto const last = keylet::nftpageMax(owner);
|
||||
|
||||
// This NFT can only be found in the first page with a key that's strictly
|
||||
// greater than `first`, so look for that, up until the maximum possible
|
||||
@@ -57,8 +57,8 @@ locatePage(ReadView const& view, AccountID const& owner, uint256 const& id)
|
||||
static SLE::pointer
|
||||
locatePage(ApplyView& view, AccountID const& owner, uint256 const& id)
|
||||
{
|
||||
auto const first = keylet::nftokenPage(keylet::nftokenPageMin(owner), id);
|
||||
auto const last = keylet::nftokenPageMax(owner);
|
||||
auto const first = keylet::nftpage(keylet::nftpageMin(owner), id);
|
||||
auto const last = keylet::nftpageMax(owner);
|
||||
|
||||
// This NFT can only be found in the first page with a key that's strictly
|
||||
// greater than `first`, so look for that, up until the maximum possible
|
||||
@@ -74,9 +74,9 @@ getPageForToken(
|
||||
uint256 const& id,
|
||||
std::function<void(ApplyView&, AccountID const&)> const& createCallback)
|
||||
{
|
||||
auto const base = keylet::nftokenPageMin(owner);
|
||||
auto const first = keylet::nftokenPage(base, id);
|
||||
auto const last = keylet::nftokenPageMax(owner);
|
||||
auto const base = keylet::nftpageMin(owner);
|
||||
auto const first = keylet::nftpage(base, id);
|
||||
auto const last = keylet::nftpageMax(owner);
|
||||
|
||||
// This NFT can only be found in the first page with a key that's strictly
|
||||
// greater than `first`, so look for that, up until the maximum possible
|
||||
@@ -182,7 +182,7 @@ getPageForToken(
|
||||
? narr[kDirMaxTokensPerPage - 1].getFieldH256(sfNFTokenID).next()
|
||||
: carr[0].getFieldH256(sfNFTokenID);
|
||||
|
||||
auto np = std::make_shared<SLE>(keylet::nftokenPage(base, tokenIDForNewPage));
|
||||
auto np = std::make_shared<SLE>(keylet::nftpage(base, tokenIDForNewPage));
|
||||
XRPL_ASSERT(np->key() > base.key, "xrpl::nft::getPageForToken : valid NFT page index");
|
||||
np->setFieldArray(sfNFTokens, narr);
|
||||
np->setFieldH256(sfNextPageMin, cp->key());
|
||||
@@ -597,7 +597,7 @@ removeTokenOffersWithLimit(ApplyView& view, Keylet const& directory, std::size_t
|
||||
// deleting during iteration.
|
||||
for (int i = offerIndexes.size() - 1; i >= 0; --i)
|
||||
{
|
||||
if (auto const offer = view.peek(keylet::nftokenOffer(offerIndexes[i])))
|
||||
if (auto const offer = view.peek(keylet::nftoffer(offerIndexes[i])))
|
||||
{
|
||||
if (deleteTokenOffer(view, offer))
|
||||
{
|
||||
@@ -651,11 +651,11 @@ repairNFTokenDirectoryLinks(ApplyView& view, AccountID const& owner)
|
||||
{
|
||||
bool didRepair = false;
|
||||
|
||||
auto const last = keylet::nftokenPageMax(owner);
|
||||
auto const last = keylet::nftpageMax(owner);
|
||||
|
||||
SLE::pointer page = view.peek(Keylet(
|
||||
ltNFTOKEN_PAGE,
|
||||
view.succ(keylet::nftokenPageMin(owner).key, last.key.next()).value_or(last.key)));
|
||||
view.succ(keylet::nftpageMin(owner).key, last.key.next()).value_or(last.key)));
|
||||
|
||||
if (!page)
|
||||
return didRepair;
|
||||
@@ -839,10 +839,10 @@ tokenOfferCreatePreclaim(
|
||||
if (view.rules().enabled(featureNFTokenMintOffer))
|
||||
{
|
||||
if (nftIssuer != amount.getIssuer() &&
|
||||
!view.read(keylet::trustLine(nftIssuer, amount.get<Issue>())))
|
||||
!view.read(keylet::line(nftIssuer, amount.get<Issue>())))
|
||||
return tecNO_LINE;
|
||||
}
|
||||
else if (!view.exists(keylet::trustLine(nftIssuer, amount.get<Issue>())))
|
||||
else if (!view.exists(keylet::line(nftIssuer, amount.get<Issue>())))
|
||||
{
|
||||
return tecNO_LINE;
|
||||
}
|
||||
@@ -934,7 +934,7 @@ tokenOfferCreateApply(
|
||||
priorBalance < view.fees().accountReserve((*acct)[sfOwnerCount] + 1))
|
||||
return tecINSUFFICIENT_RESERVE;
|
||||
|
||||
auto const offerID = keylet::nftokenOffer(acctID, seqProxy.value());
|
||||
auto const offerID = keylet::nftoffer(acctID, seqProxy.value());
|
||||
|
||||
// Create the offer:
|
||||
{
|
||||
@@ -1020,7 +1020,7 @@ checkTrustlineAuthorized(
|
||||
|
||||
if (issuerAccount->isFlag(lsfRequireAuth))
|
||||
{
|
||||
auto const trustLine = view.read(keylet::trustLine(id, issue.account, issue.currency));
|
||||
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
|
||||
|
||||
if (!trustLine)
|
||||
{
|
||||
@@ -1070,7 +1070,7 @@ checkTrustlineDeepFrozen(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
auto const trustLine = view.read(keylet::trustLine(id, issue.account, issue.currency));
|
||||
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
|
||||
|
||||
if (!trustLine)
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ creditLimit(
|
||||
{
|
||||
STAmount result(Issue{currency, account});
|
||||
|
||||
auto sleRippleState = view.read(keylet::trustLine(account, issuer, currency));
|
||||
auto sleRippleState = view.read(keylet::line(account, issuer, currency));
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
@@ -78,7 +78,7 @@ creditBalance(
|
||||
{
|
||||
STAmount result(Issue{currency, account});
|
||||
|
||||
auto sleRippleState = view.read(keylet::trustLine(account, issuer, currency));
|
||||
auto sleRippleState = view.read(keylet::line(account, issuer, currency));
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
@@ -114,7 +114,7 @@ isIndividualFrozen(
|
||||
if (issuer != account)
|
||||
{
|
||||
// Check if the issuer froze the line
|
||||
auto const sle = view.read(keylet::trustLine(account, issuer, currency));
|
||||
auto const sle = view.read(keylet::line(account, issuer, currency));
|
||||
if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
|
||||
return true;
|
||||
}
|
||||
@@ -138,7 +138,7 @@ isFrozen(
|
||||
if (issuer != account)
|
||||
{
|
||||
// Check if the issuer froze the line
|
||||
sle = view.read(keylet::trustLine(account, issuer, currency));
|
||||
sle = view.read(keylet::line(account, issuer, currency));
|
||||
if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
|
||||
return true;
|
||||
}
|
||||
@@ -162,7 +162,7 @@ isDeepFrozen(
|
||||
return false;
|
||||
}
|
||||
|
||||
auto const sle = view.read(keylet::trustLine(account, issuer, currency));
|
||||
auto const sle = view.read(keylet::line(account, issuer, currency));
|
||||
if (!sle)
|
||||
{
|
||||
return false;
|
||||
@@ -403,7 +403,7 @@ issueIOU(
|
||||
|
||||
bool const bSenderHigh = issue.account > account;
|
||||
|
||||
auto const index = keylet::trustLine(issue.account, account, issue.currency);
|
||||
auto const index = keylet::line(issue.account, account, issue.currency);
|
||||
|
||||
if (auto state = view.peek(index))
|
||||
{
|
||||
@@ -497,7 +497,7 @@ redeemIOU(
|
||||
|
||||
bool const bSenderHigh = account > issue.account;
|
||||
|
||||
if (auto state = view.peek(keylet::trustLine(account, issue.account, issue.currency)))
|
||||
if (auto state = view.peek(keylet::line(account, issue.account, issue.currency)))
|
||||
{
|
||||
STAmount finalBalance = state->getFieldAmount(sfBalance);
|
||||
|
||||
@@ -558,7 +558,7 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account,
|
||||
if (isXRP(issue) || issue.account == account)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const trustLine = view.read(keylet::trustLine(account, issue.account, issue.currency));
|
||||
auto const trustLine = view.read(keylet::line(account, issue.account, issue.currency));
|
||||
// If account has no line, and this is a strong check, fail
|
||||
if (!trustLine && authType == AuthType::StrongAuth)
|
||||
return tecNO_LINE;
|
||||
@@ -596,7 +596,7 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc
|
||||
auto const isRippleDisabled = [&](AccountID account) -> bool {
|
||||
// Line might not exist, but some transfers can create it. If this
|
||||
// is the case, just check the default ripple on the issuer account.
|
||||
auto const line = view.read(keylet::trustLine(account, issue));
|
||||
auto const line = view.read(keylet::line(account, issue));
|
||||
if (line)
|
||||
{
|
||||
bool const issuerHigh = issuerId > account;
|
||||
@@ -638,7 +638,7 @@ addEmptyHolding(
|
||||
auto const& srcId = issuerId;
|
||||
auto const& dstId = accountID;
|
||||
auto const high = srcId > dstId;
|
||||
auto const index = keylet::trustLine(srcId, dstId, currency);
|
||||
auto const index = keylet::line(srcId, dstId, currency);
|
||||
auto const sleSrc = view.peek(keylet::account(srcId));
|
||||
auto const sleDst = view.peek(keylet::account(dstId));
|
||||
if (!sleDst || !sleSrc)
|
||||
@@ -696,7 +696,7 @@ removeEmptyHolding(
|
||||
// If the account is the issuer, then no line should exist. Check anyway.
|
||||
// If a line does exist, it will get deleted. If not, return success.
|
||||
bool const accountIsIssuer = accountID == issue.account;
|
||||
auto const line = view.peek(keylet::trustLine(accountID, issue));
|
||||
auto const line = view.peek(keylet::line(accountID, issue));
|
||||
if (!line)
|
||||
return accountIsIssuer ? (TER)tesSUCCESS : (TER)tecOBJECT_NOT_FOUND;
|
||||
if (!accountIsIssuer && line->at(sfBalance)->iou() != beast::kZero)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
|
||||
@@ -35,6 +34,14 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Forward declaration for function that remains in View.h/cpp
|
||||
bool
|
||||
isLPTokenFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
Asset const& asset,
|
||||
Asset const& asset2);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Freeze checking (Asset-based)
|
||||
@@ -157,90 +164,6 @@ checkDeepFrozen(ReadView const& view, AccountID const& account, Asset const& ass
|
||||
[&](auto const& issue) { return checkDeepFrozen(view, account, issue); }, asset.value());
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkWithdrawFreeze(
|
||||
ReadView const& view,
|
||||
AccountID const& srcAcct,
|
||||
AccountID const& submitterAcct,
|
||||
AccountID const& dstAcct,
|
||||
Asset const& asset)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
isPseudoAccount(view, srcAcct), "xrpl::checkWithdrawFreeze : source is a pseudo-account");
|
||||
XRPL_ASSERT(
|
||||
!isPseudoAccount(view, submitterAcct),
|
||||
"xrpl::checkWithdrawFreeze : submitter is not a pseudo-account");
|
||||
XRPL_ASSERT(
|
||||
!isPseudoAccount(view, dstAcct),
|
||||
"xrpl::checkWithdrawFreeze : destination is not a pseudo-account");
|
||||
|
||||
// Funds can always be sent to the issuer
|
||||
if (dstAcct == asset.getIssuer())
|
||||
return tesSUCCESS;
|
||||
|
||||
// If the asset is globally frozen, other checks are redundant
|
||||
if (auto const ret = checkGlobalFrozen(view, asset); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Special case for shares - check if the shares (and the transitive asset) is not frozen
|
||||
if (asset.holds<MPTIssue>() &&
|
||||
isVaultPseudoAccountFrozen(view, srcAcct, asset.get<MPTIssue>(), 0))
|
||||
{
|
||||
return tecLOCKED;
|
||||
}
|
||||
|
||||
// The transfer is from Submitter to Destination via Source (pseudo-account)
|
||||
// Both Source and Submitter must not be frozen to allow sending funds
|
||||
if (auto const ret = checkIndividualFrozen(view, srcAcct, asset); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Check submitter's individual freeze only when Submitter != Destination (a regular freeze
|
||||
// should not block self-withdrawal).
|
||||
if (submitterAcct != dstAcct)
|
||||
{
|
||||
if (auto const ret = checkIndividualFrozen(view, submitterAcct, asset); !isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
// The destination account must not be deep frozen to receive the funds
|
||||
return checkDeepFrozen(view, dstAcct, asset);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkDepositFreeze(
|
||||
ReadView const& view,
|
||||
AccountID const& srcAcct,
|
||||
AccountID const& dstAcct,
|
||||
Asset const& asset)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
isPseudoAccount(view, dstAcct),
|
||||
"xrpl::checkDepositFreeze : destination is a pseudo-account");
|
||||
XRPL_ASSERT(
|
||||
!isPseudoAccount(view, srcAcct),
|
||||
"xrpl::checkDepositFreeze : source is not a pseudo-account");
|
||||
|
||||
if (auto const ret = checkGlobalFrozen(view, asset); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
// Special case for shares - check if the shares and the transitive asset is not frozen
|
||||
if (asset.holds<MPTIssue>() &&
|
||||
isVaultPseudoAccountFrozen(view, dstAcct, asset.get<MPTIssue>(), 0))
|
||||
{
|
||||
return tecLOCKED;
|
||||
}
|
||||
|
||||
if (srcAcct != asset.getIssuer())
|
||||
{
|
||||
if (auto const ret = checkIndividualFrozen(view, srcAcct, asset); !isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Unlike regular accounts, pseudo-accounts cannot receive deposits under a regular freeze
|
||||
// because those funds cannot be later withdrawn
|
||||
return checkIndividualFrozen(view, dstAcct, asset);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Account balance functions
|
||||
@@ -256,7 +179,7 @@ getLineIfUsable(
|
||||
FreezeHandling zeroIfFrozen,
|
||||
beast::Journal j)
|
||||
{
|
||||
auto sle = view.read(keylet::trustLine(account, issuer, currency));
|
||||
auto sle = view.read(keylet::line(account, issuer, currency));
|
||||
|
||||
if (!sle)
|
||||
{
|
||||
@@ -397,7 +320,7 @@ accountHolds(
|
||||
{
|
||||
// if the account is the issuer, and the issuance exists, their limit is
|
||||
// the issuance limit minus the outstanding value
|
||||
auto const issuance = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
|
||||
auto const issuance = view.read(keylet::mptIssuance(mptIssue.getMptID()));
|
||||
|
||||
if (!issuance)
|
||||
{
|
||||
@@ -411,8 +334,11 @@ accountHolds(
|
||||
|
||||
auto const sleMpt = view.read(keylet::mptoken(mptIssue.getMptID(), account));
|
||||
|
||||
if (!sleMpt ||
|
||||
(zeroIfFrozen == FreezeHandling::ZeroIfFrozen && isFrozen(view, account, mptIssue)))
|
||||
if (!sleMpt)
|
||||
{
|
||||
amount.clear(mptIssue);
|
||||
}
|
||||
else if (zeroIfFrozen == FreezeHandling::ZeroIfFrozen && isFrozen(view, account, mptIssue))
|
||||
{
|
||||
amount.clear(mptIssue);
|
||||
}
|
||||
@@ -423,8 +349,7 @@ accountHolds(
|
||||
// Only if auth check is needed, as it needs to do an additional read
|
||||
// operation. Note featureSingleAssetVault will affect error codes.
|
||||
if (zeroIfUnauthorized == AuthHandling::ZeroIfUnauthorized &&
|
||||
(view.rules().enabled(featureSingleAssetVault) ||
|
||||
view.rules().enabled(featureConfidentialTransfer)))
|
||||
view.rules().enabled(featureSingleAssetVault))
|
||||
{
|
||||
if (auto const err = requireAuth(view, mptIssue, account, AuthType::StrongAuth);
|
||||
!isTesSuccess(err))
|
||||
@@ -432,7 +357,7 @@ accountHolds(
|
||||
}
|
||||
else if (zeroIfUnauthorized == AuthHandling::ZeroIfUnauthorized)
|
||||
{
|
||||
auto const sleIssuance = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
|
||||
auto const sleIssuance = view.read(keylet::mptIssuance(mptIssue.getMptID()));
|
||||
|
||||
// if auth is enabled on the issuance and mpt is not authorized,
|
||||
// clear amount
|
||||
@@ -643,7 +568,7 @@ directSendNoFeeIOU(
|
||||
XRPL_ASSERT(uSenderID != uReceiverID, "xrpl::directSendNoFeeIOU : sender is not receiver");
|
||||
|
||||
bool const bSenderHigh = uSenderID > uReceiverID;
|
||||
auto const index = keylet::trustLine(uSenderID, uReceiverID, currency);
|
||||
auto const index = keylet::line(uSenderID, uReceiverID, currency);
|
||||
|
||||
XRPL_ASSERT(
|
||||
!isXRP(uSenderID) && uSenderID != noAccount(),
|
||||
@@ -851,8 +776,7 @@ directSendNoLimitMultiIOU(
|
||||
if (senderID == issuer || receiverID == issuer || issuer == noAccount())
|
||||
{
|
||||
// Direct send: redeeming IOUs and/or sending own IOUs.
|
||||
if (auto const ter = directSendNoFeeIOU(view, senderID, receiverID, amount, false, j);
|
||||
!isTesSuccess(ter))
|
||||
if (auto const ter = directSendNoFeeIOU(view, senderID, receiverID, amount, false, j))
|
||||
return ter;
|
||||
actual += amount;
|
||||
// Do not add amount to takeFromSender, because directSendNoFeeIOU took
|
||||
@@ -1142,7 +1066,7 @@ directSendNoFeeMPT(
|
||||
beast::Journal j)
|
||||
{
|
||||
// Do not check MPT authorization here - it must have been checked earlier
|
||||
auto const mptID = keylet::mptokenIssuance(saAmount.get<MPTIssue>().getMptID());
|
||||
auto const mptID = keylet::mptIssuance(saAmount.get<MPTIssue>().getMptID());
|
||||
auto const& issuer = saAmount.getIssuer();
|
||||
auto sleIssuance = view.peek(mptID);
|
||||
if (!sleIssuance)
|
||||
@@ -1234,7 +1158,7 @@ directSendNoLimitMPT(
|
||||
// Safe to get MPT since directSendNoLimitMPT is only called by accountSendMPT
|
||||
auto const& issuer = saAmount.getIssuer();
|
||||
|
||||
auto const sle = view.read(keylet::mptokenIssuance(saAmount.get<MPTIssue>().getMptID()));
|
||||
auto const sle = view.read(keylet::mptIssuance(saAmount.get<MPTIssue>().getMptID()));
|
||||
if (!sle)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
@@ -1291,7 +1215,7 @@ directSendNoLimitMultiMPT(
|
||||
{
|
||||
auto const& issuer = mptIssue.getIssuer();
|
||||
|
||||
auto const sle = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
|
||||
auto const sle = view.read(keylet::mptIssuance(mptIssue.getMptID()));
|
||||
if (!sle)
|
||||
return tecOBJECT_NOT_FOUND;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <rocksdb/write_batch.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -285,7 +286,7 @@ public:
|
||||
Status status = Status::Ok;
|
||||
|
||||
rocksdb::ReadOptions const options;
|
||||
rocksdb::Slice const slice(reinterpret_cast<char const*>(hash.data()), keyBytes);
|
||||
rocksdb::Slice const slice(std::bit_cast<char const*>(hash.data()), keyBytes);
|
||||
|
||||
std::string string;
|
||||
|
||||
@@ -348,9 +349,8 @@ public:
|
||||
EncodedBlob const encoded(e);
|
||||
|
||||
wb.Put(
|
||||
rocksdb::Slice(reinterpret_cast<char const*>(encoded.getKey()), keyBytes),
|
||||
rocksdb::Slice(
|
||||
reinterpret_cast<char const*>(encoded.getData()), encoded.getSize()));
|
||||
rocksdb::Slice(std::bit_cast<char const*>(encoded.getKey()), keyBytes),
|
||||
rocksdb::Slice(std::bit_cast<char const*>(encoded.getData()), encoded.getSize()));
|
||||
}
|
||||
|
||||
rocksdb::WriteOptions const options;
|
||||
|
||||
@@ -1,487 +0,0 @@
|
||||
#include <xrpl/protocol/ConfidentialTransfer.h>
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <openssl/rand.h>
|
||||
#include <utility/mpt_utility.h>
|
||||
|
||||
#include <mpt_protocol.h>
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_mpt.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
namespace {
|
||||
|
||||
account_id
|
||||
toAccountId(AccountID const& account)
|
||||
{
|
||||
account_id res;
|
||||
std::memcpy(res.bytes, account.data(), kMPT_ACCOUNT_ID_SIZE);
|
||||
return res;
|
||||
}
|
||||
|
||||
mpt_issuance_id
|
||||
toIssuanceId(uint192 const& issuance)
|
||||
{
|
||||
mpt_issuance_id res;
|
||||
std::memcpy(res.bytes, issuance.data(), kMPT_ISSUANCE_ID_SIZE);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pack a ConfidentialRecipient (public key + ElGamal ciphertext) into the
|
||||
* secp256k1-mpt participant struct. Callers MUST have already validated that
|
||||
* r.publicKey.size() == kEcPubKeyLength and
|
||||
* r.encryptedAmount.size() == kEcGamalEncryptedTotalLength;
|
||||
*/
|
||||
mpt_confidential_participant
|
||||
toParticipant(ConfidentialRecipient const& r)
|
||||
{
|
||||
mpt_confidential_participant p{};
|
||||
std::memcpy(p.pubkey, r.publicKey.data(), kEcPubKeyLength);
|
||||
std::memcpy(p.ciphertext, r.encryptedAmount.data(), kEcGamalEncryptedTotalLength);
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
uint256
|
||||
getSendContextHash(
|
||||
AccountID const& account,
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence,
|
||||
AccountID const& destination,
|
||||
std::uint32_t version)
|
||||
{
|
||||
uint256 result;
|
||||
mpt_get_send_context_hash(
|
||||
toAccountId(account),
|
||||
toIssuanceId(issuanceID),
|
||||
sequence,
|
||||
toAccountId(destination),
|
||||
version,
|
||||
result.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
uint256
|
||||
getClawbackContextHash(
|
||||
AccountID const& account,
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence,
|
||||
AccountID const& holder)
|
||||
{
|
||||
uint256 result;
|
||||
mpt_get_clawback_context_hash(
|
||||
toAccountId(account),
|
||||
toIssuanceId(issuanceID),
|
||||
sequence,
|
||||
toAccountId(holder),
|
||||
result.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
uint256
|
||||
getConvertContextHash(AccountID const& account, uint192 const& issuanceID, std::uint32_t sequence)
|
||||
{
|
||||
uint256 result;
|
||||
mpt_get_convert_context_hash(
|
||||
toAccountId(account), toIssuanceId(issuanceID), sequence, result.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
uint256
|
||||
getConvertBackContextHash(
|
||||
AccountID const& account,
|
||||
uint192 const& issuanceID,
|
||||
std::uint32_t sequence,
|
||||
std::uint32_t version)
|
||||
{
|
||||
uint256 result;
|
||||
mpt_get_convert_back_context_hash(
|
||||
toAccountId(account), toIssuanceId(issuanceID), sequence, version, result.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<EcPair>
|
||||
makeEcPair(Slice const& buffer)
|
||||
{
|
||||
if (buffer.length() != 2 * kEcCiphertextComponentLength)
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
|
||||
auto parsePubKey = [](Slice const& slice, secp256k1_pubkey& out) {
|
||||
return secp256k1_ec_pubkey_parse(secp256k1Context(), &out, slice.data(), slice.length());
|
||||
};
|
||||
|
||||
Slice const s1{buffer.data(), kEcCiphertextComponentLength};
|
||||
Slice const s2{buffer.data() + kEcCiphertextComponentLength, kEcCiphertextComponentLength};
|
||||
|
||||
EcPair pair{};
|
||||
if (parsePubKey(s1, pair.c1) != 1 || parsePubKey(s2, pair.c2) != 1)
|
||||
return std::nullopt;
|
||||
|
||||
return pair;
|
||||
}
|
||||
|
||||
std::optional<Buffer>
|
||||
serializeEcPair(EcPair const& pair)
|
||||
{
|
||||
auto serializePubKey = [](secp256k1_pubkey const& pub, unsigned char* out) {
|
||||
size_t outLen = kEcCiphertextComponentLength; // 33 bytes
|
||||
auto const ret = secp256k1_ec_pubkey_serialize(
|
||||
secp256k1Context(), out, &outLen, &pub, SECP256K1_EC_COMPRESSED);
|
||||
return ret == 1 && outLen == kEcCiphertextComponentLength;
|
||||
};
|
||||
|
||||
Buffer buffer(kEcGamalEncryptedTotalLength);
|
||||
auto const ptr = buffer.data();
|
||||
bool const res1 = serializePubKey(pair.c1, ptr);
|
||||
bool const res2 = serializePubKey(pair.c2, ptr + kEcCiphertextComponentLength);
|
||||
|
||||
if (!res1 || !res2)
|
||||
return std::nullopt;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool
|
||||
isValidCiphertext(Slice const& buffer)
|
||||
{
|
||||
return makeEcPair(buffer).has_value();
|
||||
}
|
||||
|
||||
bool
|
||||
isValidCompressedECPoint(Slice const& buffer)
|
||||
{
|
||||
if (buffer.size() != kCompressedEcPointLength)
|
||||
return false;
|
||||
|
||||
// Compressed EC points must start with 0x02 or 0x03
|
||||
if (buffer[0] != kEcCompressedPrefixEvenY && buffer[0] != kEcCompressedPrefixOddY)
|
||||
return false;
|
||||
|
||||
secp256k1_pubkey point;
|
||||
return secp256k1_ec_pubkey_parse(secp256k1Context(), &point, buffer.data(), buffer.size()) == 1;
|
||||
}
|
||||
|
||||
std::optional<Buffer>
|
||||
homomorphicAdd(Slice const& a, Slice const& b)
|
||||
{
|
||||
if (a.length() != kEcGamalEncryptedTotalLength || b.length() != kEcGamalEncryptedTotalLength)
|
||||
return std::nullopt;
|
||||
|
||||
auto const pairA = makeEcPair(a);
|
||||
auto const pairB = makeEcPair(b);
|
||||
|
||||
if (!pairA || !pairB)
|
||||
return std::nullopt;
|
||||
|
||||
EcPair sum{};
|
||||
if (auto res = secp256k1_elgamal_add(
|
||||
secp256k1Context(), &sum.c1, &sum.c2, &pairA->c1, &pairA->c2, &pairB->c1, &pairB->c2);
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return serializeEcPair(sum);
|
||||
}
|
||||
|
||||
std::optional<Buffer>
|
||||
homomorphicSubtract(Slice const& a, Slice const& b)
|
||||
{
|
||||
if (a.length() != kEcGamalEncryptedTotalLength || b.length() != kEcGamalEncryptedTotalLength)
|
||||
return std::nullopt;
|
||||
|
||||
auto const pairA = makeEcPair(a);
|
||||
auto const pairB = makeEcPair(b);
|
||||
|
||||
if (!pairA || !pairB)
|
||||
return std::nullopt;
|
||||
|
||||
EcPair diff{};
|
||||
if (auto const res = secp256k1_elgamal_subtract(
|
||||
secp256k1Context(), &diff.c1, &diff.c2, &pairA->c1, &pairA->c2, &pairB->c1, &pairB->c2);
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return serializeEcPair(diff);
|
||||
}
|
||||
|
||||
std::optional<Buffer>
|
||||
rerandomizeCiphertext(Slice const& ciphertext, Slice const& pubKeySlice, Slice const& randomness)
|
||||
{
|
||||
auto zero = encryptAmount(0, pubKeySlice, randomness);
|
||||
if (!zero)
|
||||
return std::nullopt;
|
||||
|
||||
return homomorphicAdd(ciphertext, *zero);
|
||||
}
|
||||
|
||||
Buffer
|
||||
generateBlindingFactor()
|
||||
{
|
||||
unsigned char blindingFactor[kEcBlindingFactorLength];
|
||||
|
||||
// todo: might need to be updated using another RNG
|
||||
if (RAND_bytes(blindingFactor, kEcBlindingFactorLength) != 1)
|
||||
Throw<std::runtime_error>("Failed to generate random number");
|
||||
|
||||
return Buffer(blindingFactor, kEcBlindingFactorLength);
|
||||
}
|
||||
|
||||
std::optional<Buffer>
|
||||
encryptAmount(uint64_t const amt, Slice const& pubKeySlice, Slice const& blindingFactor)
|
||||
{
|
||||
if (blindingFactor.size() != kEcBlindingFactorLength || pubKeySlice.size() != kEcPubKeyLength)
|
||||
return std::nullopt;
|
||||
|
||||
Buffer out(kEcGamalEncryptedTotalLength);
|
||||
if (mpt_encrypt_amount(amt, pubKeySlice.data(), blindingFactor.data(), out.data()) != 0)
|
||||
return std::nullopt;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::optional<Buffer>
|
||||
encryptCanonicalZeroAmount(Slice const& pubKeySlice, AccountID const& account, MPTID const& mptId)
|
||||
{
|
||||
if (pubKeySlice.size() != kEcPubKeyLength)
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
|
||||
EcPair pair{};
|
||||
secp256k1_pubkey pubKey;
|
||||
if (auto res = secp256k1_ec_pubkey_parse(
|
||||
secp256k1Context(), &pubKey, pubKeySlice.data(), kEcPubKeyLength);
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (auto res = generate_canonical_encrypted_zero(
|
||||
secp256k1Context(), &pair.c1, &pair.c2, &pubKey, account.data(), mptId.data());
|
||||
res != 1)
|
||||
{
|
||||
return std::nullopt; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
return serializeEcPair(pair);
|
||||
}
|
||||
|
||||
TER
|
||||
verifyRevealedAmount(
|
||||
uint64_t const amount,
|
||||
Slice const& blindingFactor,
|
||||
ConfidentialRecipient const& holder,
|
||||
ConfidentialRecipient const& issuer,
|
||||
std::optional<ConfidentialRecipient> const& auditor)
|
||||
{
|
||||
if (blindingFactor.size() != kEcBlindingFactorLength ||
|
||||
holder.publicKey.size() != kEcPubKeyLength ||
|
||||
holder.encryptedAmount.size() != kEcGamalEncryptedTotalLength ||
|
||||
issuer.publicKey.size() != kEcPubKeyLength ||
|
||||
issuer.encryptedAmount.size() != kEcGamalEncryptedTotalLength)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
auto const holderP = toParticipant(holder);
|
||||
auto const issuerP = toParticipant(issuer);
|
||||
mpt_confidential_participant auditorP{};
|
||||
mpt_confidential_participant const* auditorPtr = nullptr;
|
||||
if (auditor)
|
||||
{
|
||||
if (auditor->publicKey.size() != kEcPubKeyLength ||
|
||||
auditor->encryptedAmount.size() != kEcGamalEncryptedTotalLength)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
auditorP = toParticipant(*auditor);
|
||||
auditorPtr = &auditorP;
|
||||
}
|
||||
|
||||
if (mpt_verify_revealed_amount(amount, blindingFactor.data(), &holderP, &issuerP, auditorPtr) !=
|
||||
0)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
checkEncryptedAmountFormat(STObject const& object)
|
||||
{
|
||||
// Current usage of this function is only for ConfidentialMPTConvert and
|
||||
// ConfidentialMPTConvertBack transactions, which already enforce that these fields
|
||||
// are present.
|
||||
if (!object.isFieldPresent(sfHolderEncryptedAmount) ||
|
||||
!object.isFieldPresent(sfIssuerEncryptedAmount))
|
||||
{
|
||||
return temMALFORMED; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (object[sfHolderEncryptedAmount].length() != kEcGamalEncryptedTotalLength ||
|
||||
object[sfIssuerEncryptedAmount].length() != kEcGamalEncryptedTotalLength)
|
||||
{
|
||||
return temBAD_CIPHERTEXT;
|
||||
}
|
||||
|
||||
bool const hasAuditor = object.isFieldPresent(sfAuditorEncryptedAmount);
|
||||
if (hasAuditor && object[sfAuditorEncryptedAmount].length() != kEcGamalEncryptedTotalLength)
|
||||
return temBAD_CIPHERTEXT;
|
||||
|
||||
if (!isValidCiphertext(object[sfHolderEncryptedAmount]) ||
|
||||
!isValidCiphertext(object[sfIssuerEncryptedAmount]))
|
||||
{
|
||||
return temBAD_CIPHERTEXT;
|
||||
}
|
||||
|
||||
if (hasAuditor && !isValidCiphertext(object[sfAuditorEncryptedAmount]))
|
||||
return temBAD_CIPHERTEXT;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 const& contextHash)
|
||||
{
|
||||
if (proofSlice.size() != kEcSchnorrProofLength || pubKeySlice.size() != kEcPubKeyLength)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (mpt_verify_convert_proof(proofSlice.data(), pubKeySlice.data(), contextHash.data()) != 0)
|
||||
return tecBAD_PROOF;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
verifyClawbackProof(
|
||||
uint64_t const amount,
|
||||
Slice const& proof,
|
||||
Slice const& pubKeySlice,
|
||||
Slice const& ciphertext,
|
||||
uint256 const& contextHash)
|
||||
{
|
||||
if (ciphertext.size() != kEcGamalEncryptedTotalLength ||
|
||||
pubKeySlice.size() != kEcPubKeyLength || proof.size() != kEcClawbackProofLength)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (mpt_verify_clawback_proof(
|
||||
proof.data(), amount, pubKeySlice.data(), ciphertext.data(), contextHash.data()) != 0)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
verifySendProof(
|
||||
Slice const& proof,
|
||||
ConfidentialRecipient const& sender,
|
||||
ConfidentialRecipient const& destination,
|
||||
ConfidentialRecipient const& issuer,
|
||||
std::optional<ConfidentialRecipient> const& auditor,
|
||||
Slice const& spendingBalance,
|
||||
Slice const& amountCommitment,
|
||||
Slice const& balanceCommitment,
|
||||
uint256 const& contextHash)
|
||||
{
|
||||
auto const recipientCount = getConfidentialRecipientCount(auditor.has_value());
|
||||
if (proof.size() != kEcSendProofLength || sender.publicKey.size() != kEcPubKeyLength ||
|
||||
sender.encryptedAmount.size() != kEcGamalEncryptedTotalLength ||
|
||||
destination.publicKey.size() != kEcPubKeyLength ||
|
||||
destination.encryptedAmount.size() != kEcGamalEncryptedTotalLength ||
|
||||
issuer.publicKey.size() != kEcPubKeyLength ||
|
||||
issuer.encryptedAmount.size() != kEcGamalEncryptedTotalLength ||
|
||||
spendingBalance.size() != kEcGamalEncryptedTotalLength ||
|
||||
amountCommitment.size() != kEcPedersenCommitmentLength ||
|
||||
balanceCommitment.size() != kEcPedersenCommitmentLength)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
std::vector<mpt_confidential_participant> participants;
|
||||
participants.reserve(recipientCount);
|
||||
participants.push_back(toParticipant(sender));
|
||||
participants.push_back(toParticipant(destination));
|
||||
participants.push_back(toParticipant(issuer));
|
||||
if (auditor)
|
||||
{
|
||||
if (auditor->publicKey.size() != kEcPubKeyLength ||
|
||||
auditor->encryptedAmount.size() != kEcGamalEncryptedTotalLength)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
participants.push_back(toParticipant(*auditor));
|
||||
}
|
||||
if (participants.size() != recipientCount)
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
|
||||
if (mpt_verify_send_proof(
|
||||
proof.data(),
|
||||
participants.data(),
|
||||
recipientCount,
|
||||
spendingBalance.data(),
|
||||
amountCommitment.data(),
|
||||
balanceCommitment.data(),
|
||||
contextHash.data()) != 0)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
verifyConvertBackProof(
|
||||
Slice const& proof,
|
||||
Slice const& pubKeySlice,
|
||||
Slice const& spendingBalance,
|
||||
Slice const& balanceCommitment,
|
||||
uint64_t amount,
|
||||
uint256 const& contextHash)
|
||||
{
|
||||
if (proof.size() != kEcConvertBackProofLength || pubKeySlice.size() != kEcPubKeyLength ||
|
||||
spendingBalance.size() != kEcGamalEncryptedTotalLength ||
|
||||
balanceCommitment.size() != kEcPedersenCommitmentLength)
|
||||
{
|
||||
return tecINTERNAL; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (mpt_verify_convert_back_proof(
|
||||
proof.data(),
|
||||
pubKeySlice.data(),
|
||||
spendingBalance.data(),
|
||||
balanceCommitment.data(),
|
||||
amount,
|
||||
contextHash.data()) != 0)
|
||||
{
|
||||
return tecBAD_PROOF;
|
||||
}
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -218,7 +218,7 @@ amendments() noexcept
|
||||
}
|
||||
|
||||
Keylet const&
|
||||
feeSettings() noexcept
|
||||
fees() noexcept
|
||||
{
|
||||
static Keylet const kRet{ltFEE_SETTINGS, indexHash(LedgerNameSpace::FeeSettings)};
|
||||
return kRet;
|
||||
@@ -232,18 +232,18 @@ negativeUNL() noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
book(Book const& b)
|
||||
BookT::operator()(Book const& b) const
|
||||
{
|
||||
return {ltDIR_NODE, getBookBase(b)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
trustLine(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept
|
||||
line(AccountID const& id0, AccountID const& id1, Currency const& currency) noexcept
|
||||
{
|
||||
// There is code in TrustSet that calls us with id0 == id1, to allow users
|
||||
// to locate and delete such "weird" trustlines. If we remove that code, we
|
||||
// could enable this assert:
|
||||
// XRPL_ASSERT(id0 != id1, "xrpl::keylet::trustLine : accounts must be
|
||||
// XRPL_ASSERT(id0 != id1, "xrpl::keylet::line : accounts must be
|
||||
// different");
|
||||
|
||||
// A trust line is shared between two accounts; while we typically think
|
||||
@@ -285,20 +285,20 @@ quality(Keylet const& k, std::uint64_t q) noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
next(Keylet const& k)
|
||||
NextT::operator()(Keylet const& k) const
|
||||
{
|
||||
XRPL_ASSERT(k.type == ltDIR_NODE, "xrpl::keylet::next : valid input type");
|
||||
XRPL_ASSERT(k.type == ltDIR_NODE, "xrpl::keylet::NextT::operator() : valid input type");
|
||||
return {ltDIR_NODE, getQualityNext(k.key)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
ticket(AccountID const& id, std::uint32_t ticketSeq)
|
||||
TicketT::operator()(AccountID const& id, std::uint32_t ticketSeq) const
|
||||
{
|
||||
return {ltTICKET, getTicketIndex(id, ticketSeq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
ticket(AccountID const& id, SeqProxy ticketSeq)
|
||||
TicketT::operator()(AccountID const& id, SeqProxy ticketSeq) const
|
||||
{
|
||||
return {ltTICKET, getTicketIndex(id, ticketSeq)};
|
||||
}
|
||||
@@ -307,15 +307,15 @@ ticket(AccountID const& id, SeqProxy ticketSeq)
|
||||
// else. If we ever support multiple pages of signer lists, this would be the
|
||||
// keylet used to locate them.
|
||||
static Keylet
|
||||
signerList(AccountID const& account, std::uint32_t page) noexcept
|
||||
signers(AccountID const& account, std::uint32_t page) noexcept
|
||||
{
|
||||
return {ltSIGNER_LIST, indexHash(LedgerNameSpace::SignerList, account, page)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
signerList(AccountID const& account) noexcept
|
||||
signers(AccountID const& account) noexcept
|
||||
{
|
||||
return signerList(account, 0);
|
||||
return signers(account, 0);
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -375,13 +375,13 @@ escrow(AccountID const& src, std::uint32_t seq) noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
payChannel(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept
|
||||
payChan(AccountID const& src, AccountID const& dst, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltPAYCHAN, indexHash(LedgerNameSpace::XRPPaymentChannel, src, dst, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
nftokenPageMin(AccountID const& owner)
|
||||
nftpageMin(AccountID const& owner)
|
||||
{
|
||||
std::array<std::uint8_t, 32> buf{};
|
||||
std::memcpy(buf.data(), owner.data(), owner.size());
|
||||
@@ -389,7 +389,7 @@ nftokenPageMin(AccountID const& owner)
|
||||
}
|
||||
|
||||
Keylet
|
||||
nftokenPageMax(AccountID const& owner)
|
||||
nftpageMax(AccountID const& owner)
|
||||
{
|
||||
uint256 id = nft::kPageMask;
|
||||
std::memcpy(id.data(), owner.data(), owner.size());
|
||||
@@ -397,14 +397,14 @@ nftokenPageMax(AccountID const& owner)
|
||||
}
|
||||
|
||||
Keylet
|
||||
nftokenPage(Keylet const& k, uint256 const& token)
|
||||
nftpage(Keylet const& k, uint256 const& token)
|
||||
{
|
||||
XRPL_ASSERT(k.type == ltNFTOKEN_PAGE, "xrpl::keylet::nftokenPage : valid input type");
|
||||
XRPL_ASSERT(k.type == ltNFTOKEN_PAGE, "xrpl::keylet::nftpage : valid input type");
|
||||
return {ltNFTOKEN_PAGE, (k.key & ~nft::kPageMask) + (token & nft::kPageMask)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
nftokenOffer(AccountID const& owner, std::uint32_t seq)
|
||||
nftoffer(AccountID const& owner, std::uint32_t seq)
|
||||
{
|
||||
return {ltNFTOKEN_OFFER, indexHash(LedgerNameSpace::NftokenOffer, owner, seq)};
|
||||
}
|
||||
@@ -518,13 +518,13 @@ oracle(AccountID const& account, std::uint32_t const& documentID) noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
mptokenIssuance(std::uint32_t seq, AccountID const& issuer) noexcept
|
||||
mptIssuance(std::uint32_t seq, AccountID const& issuer) noexcept
|
||||
{
|
||||
return mptokenIssuance(makeMptID(seq, issuer));
|
||||
return mptIssuance(makeMptID(seq, issuer));
|
||||
}
|
||||
|
||||
Keylet
|
||||
mptokenIssuance(MPTID const& issuanceID) noexcept
|
||||
mptIssuance(MPTID const& issuanceID) noexcept
|
||||
{
|
||||
return {ltMPTOKEN_ISSUANCE, indexHash(LedgerNameSpace::MPTokenIssuance, issuanceID)};
|
||||
}
|
||||
@@ -532,7 +532,7 @@ mptokenIssuance(MPTID const& issuanceID) noexcept
|
||||
Keylet
|
||||
mptoken(MPTID const& issuanceID, AccountID const& holder) noexcept
|
||||
{
|
||||
return mptoken(mptokenIssuance(issuanceID).key, holder);
|
||||
return mptoken(mptIssuance(issuanceID).key, holder);
|
||||
}
|
||||
|
||||
Keylet
|
||||
@@ -554,9 +554,9 @@ vault(AccountID const& owner, std::uint32_t seq) noexcept
|
||||
}
|
||||
|
||||
Keylet
|
||||
loanBroker(AccountID const& owner, std::uint32_t seq) noexcept
|
||||
loanbroker(AccountID const& owner, std::uint32_t seq) noexcept
|
||||
{
|
||||
return loanBroker(indexHash(LedgerNameSpace::LoanBroker, owner, seq));
|
||||
return loanbroker(indexHash(LedgerNameSpace::LoanBroker, owner, seq));
|
||||
}
|
||||
|
||||
Keylet
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -153,11 +152,9 @@ Permission::getPermissionName(std::uint32_t value) const
|
||||
return granular;
|
||||
|
||||
// not a granular permission, check if it maps to a transaction type
|
||||
if (auto const txType = permissionToTxType(value))
|
||||
{
|
||||
if (auto const* item = TxFormats::getInstance().findByType(*txType); item != nullptr)
|
||||
return item->getName();
|
||||
}
|
||||
auto const txType = permissionToTxType(value);
|
||||
if (auto const* item = TxFormats::getInstance().findByType(txType); item != nullptr)
|
||||
return item->getName();
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -234,10 +231,7 @@ Permission::isDelegable(std::uint32_t permissionValue, Rules const& rules) const
|
||||
}
|
||||
|
||||
auto const txType = permissionToTxType(permissionValue);
|
||||
if (!txType)
|
||||
return false;
|
||||
|
||||
auto const txIt = txDelegationMap_.find(*txType);
|
||||
auto const txIt = txDelegationMap_.find(txType);
|
||||
|
||||
// Tx-level permissions require the transaction type itself to be delegable, and
|
||||
// the corresponding amendment enabled.
|
||||
@@ -251,14 +245,10 @@ Permission::txToPermissionType(TxType const type)
|
||||
return static_cast<uint32_t>(type) + 1;
|
||||
}
|
||||
|
||||
std::optional<TxType>
|
||||
TxType
|
||||
Permission::permissionToTxType(uint32_t value)
|
||||
{
|
||||
// Values outside this range [1, 65536] would silently truncate when cast to
|
||||
// uint16_t, for example, 65537 would become 1, mapping to the Payment transaction.
|
||||
if (value == 0 || value > std::numeric_limits<std::uint16_t>::max() + 1u)
|
||||
return std::nullopt;
|
||||
|
||||
XRPL_ASSERT(value > 0, "xrpl::Permission::permissionToTxType : value is greater than 0");
|
||||
return static_cast<TxType>(value - 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/basics/strHex.h>
|
||||
#include <xrpl/protocol/KeyType.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/detail/secp256k1.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
@@ -212,7 +211,7 @@ publicKeyType(Slice const& slice)
|
||||
if (slice[0] == 0xED)
|
||||
return KeyType::Ed25519;
|
||||
|
||||
if (slice[0] == kEcCompressedPrefixEvenY || slice[0] == kEcCompressedPrefixOddY)
|
||||
if (slice[0] == 0x02 || slice[0] == 0x03)
|
||||
return KeyType::Secp256k1;
|
||||
}
|
||||
|
||||
|
||||
@@ -635,20 +635,6 @@ STObject::getAccountID(SField const& field) const
|
||||
return getFieldByValue<STAccount>(field);
|
||||
}
|
||||
|
||||
AccountID
|
||||
STObject::getFeePayer() const
|
||||
{
|
||||
// If sfDelegate is present, the delegate account is the payer
|
||||
// note: if a delegate is specified, its authorization to act on behalf of the account is
|
||||
// enforced in `Transactor::invokeCheckPermission`
|
||||
// cryptographic signature validity is checked separately (e.g., in `Transactor::checkSign`)
|
||||
if (isFieldPresent(sfDelegate))
|
||||
return getAccountID(sfDelegate);
|
||||
|
||||
// Default payer
|
||||
return getAccountID(sfAccount);
|
||||
}
|
||||
|
||||
Blob
|
||||
STObject::getFieldVL(SField const& field) const
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/StringUtilities.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
@@ -71,7 +72,6 @@ STTx::STTx(STObject&& object) : STObject(std::move(object))
|
||||
txType_ = safeCast<TxType>(getFieldU16(sfTransactionType));
|
||||
applyTemplate(getTxFormat(txType_)->getSOTemplate()); // may throw
|
||||
tid_ = getHash(HashPrefix::TransactionId);
|
||||
buildBatchTxnIds();
|
||||
}
|
||||
|
||||
STTx::STTx(SerialIter& sit) : STObject(sfTransaction)
|
||||
@@ -88,7 +88,6 @@ STTx::STTx(SerialIter& sit) : STObject(sfTransaction)
|
||||
|
||||
applyTemplate(getTxFormat(txType_)->getSOTemplate()); // May throw
|
||||
tid_ = getHash(HashPrefix::TransactionId);
|
||||
buildBatchTxnIds();
|
||||
}
|
||||
|
||||
STTx::STTx(TxType type, std::function<void(STObject&)> assembler) : STObject(sfTransaction)
|
||||
@@ -106,7 +105,6 @@ STTx::STTx(TxType type, std::function<void(STObject&)> assembler) : STObject(sfT
|
||||
logicError("Transaction type was mutated during assembly");
|
||||
|
||||
tid_ = getHash(HashPrefix::TransactionId);
|
||||
buildBatchTxnIds();
|
||||
}
|
||||
|
||||
STBase*
|
||||
@@ -214,6 +212,20 @@ STTx::getSeqValue() const
|
||||
return getSeqProxy().value();
|
||||
}
|
||||
|
||||
AccountID
|
||||
STTx::getFeePayer() const
|
||||
{
|
||||
// If sfDelegate is present, the delegate account is the payer
|
||||
// note: if a delegate is specified, its authorization to act on behalf of the account is
|
||||
// enforced in `Transactor::invokeCheckPermission`
|
||||
// cryptographic signature validity is checked separately (e.g., in `Transactor::checkSign`)
|
||||
if (isFieldPresent(sfDelegate))
|
||||
return getAccountID(sfDelegate);
|
||||
|
||||
// Default payer
|
||||
return getAccountID(sfAccount);
|
||||
}
|
||||
|
||||
void
|
||||
STTx::sign(
|
||||
PublicKey const& publicKey,
|
||||
@@ -267,17 +279,6 @@ STTx::checkSign(Rules const& rules) const
|
||||
if (auto const ret = checkSign(rules, counterSig); !ret)
|
||||
return std::unexpected("Counterparty: " + ret.error());
|
||||
}
|
||||
|
||||
// Verify the batch signer signatures here too, so they are cached with the
|
||||
// rest of signature checking (checkValidity / SF_SIGGOOD) and stay out of
|
||||
// the transaction engine. Gated on a batch (batchTxnIds_ seated) that
|
||||
// actually carries signers; a batch whose inners are all from the outer
|
||||
// account has no sfBatchSigners and needs no signer crypto.
|
||||
if (batchTxnIds_ && isFieldPresent(sfBatchSigners))
|
||||
{
|
||||
if (auto const ret = checkBatchSign(rules); !ret)
|
||||
return ret;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -286,24 +287,13 @@ STTx::checkBatchSign(Rules const& rules) const
|
||||
{
|
||||
try
|
||||
{
|
||||
XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::checkBatchSign : not a batch transaction");
|
||||
if (getTxnType() != ttBATCH)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("STTx::checkBatchSign : not a batch transaction");
|
||||
JLOG(debugLog().fatal()) << "not a batch transaction";
|
||||
return std::unexpected("Not a batch transaction.");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
if (!isFieldPresent(sfBatchSigners))
|
||||
return std::unexpected("Missing BatchSigners field."); // LCOV_EXCL_LINE
|
||||
STArray const& signers{getFieldArray(sfBatchSigners)};
|
||||
// Bound signature verification to the protocol cap. This runs in
|
||||
// checkValidity (via checkSign) at relay / submit time, BEFORE preflight
|
||||
// and passesLocalChecks enforce the cap. Without this guard a malicious
|
||||
// peer could put an oversized sfBatchSigners array in a 1 MB blob and
|
||||
// force one signature verification per entry before any of those checks
|
||||
// (or the fee charge) runs.
|
||||
if (signers.size() > kMaxBatchSigners)
|
||||
return std::unexpected("BatchSigners array exceeds max entries.");
|
||||
for (auto const& signer : signers)
|
||||
{
|
||||
Blob const& signingPubKey = signer.getFieldVL(sfSigningPubKey);
|
||||
@@ -317,10 +307,9 @@ STTx::checkBatchSign(Rules const& rules) const
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
return std::unexpected(std::string("Internal batch signature check failure: ") + e.what());
|
||||
// LCOV_EXCL_STOP
|
||||
JLOG(debugLog().error()) << "Batch signature check failed: " << e.what();
|
||||
}
|
||||
return std::unexpected("Internal batch signature check failure.");
|
||||
}
|
||||
|
||||
json::Value
|
||||
@@ -440,11 +429,8 @@ STTx::checkSingleSign(STObject const& sigObject) const
|
||||
std::expected<void, std::string>
|
||||
STTx::checkBatchSingleSign(STObject const& batchSigner) const
|
||||
{
|
||||
XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::checkBatchSingleSign : batch transaction");
|
||||
Serializer msg;
|
||||
serializeBatch(
|
||||
msg, getAccountID(sfAccount), getSeqValue(), getFlags(), getBatchTransactionIDs());
|
||||
finishMultiSigningData(batchSigner.getAccountID(sfAccount), msg);
|
||||
serializeBatch(msg, getFlags(), getBatchTransactionIDs());
|
||||
return singleSignHelper(batchSigner, msg.slice());
|
||||
}
|
||||
|
||||
@@ -518,7 +504,7 @@ multiSignHelper(
|
||||
{
|
||||
return std::unexpected(
|
||||
std::string("Invalid signature on account ") + toBase58(accountID) +
|
||||
(errorWhat ? ": " + *errorWhat : "") + ".");
|
||||
errorWhat.value_or("") + ".");
|
||||
}
|
||||
}
|
||||
// All signatures verified.
|
||||
@@ -528,18 +514,14 @@ multiSignHelper(
|
||||
std::expected<void, std::string>
|
||||
STTx::checkBatchMultiSign(STObject const& batchSigner, Rules const& rules) const
|
||||
{
|
||||
XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::checkBatchMultiSign : batch transaction");
|
||||
// We can ease the computational load inside the loop a bit by
|
||||
// pre-constructing part of the data that we hash. Fill a Serializer
|
||||
// with the stuff that stays constant from signature to signature.
|
||||
auto const batchSignerAccount = batchSigner.getAccountID(sfAccount);
|
||||
Serializer dataStart;
|
||||
serializeBatch(
|
||||
dataStart, getAccountID(sfAccount), getSeqValue(), getFlags(), getBatchTransactionIDs());
|
||||
dataStart.addBitString(batchSignerAccount);
|
||||
serializeBatch(dataStart, getFlags(), getBatchTransactionIDs());
|
||||
return multiSignHelper(
|
||||
batchSigner,
|
||||
batchSignerAccount,
|
||||
std::nullopt,
|
||||
[&dataStart](AccountID const& accountID) -> Serializer {
|
||||
Serializer s = dataStart;
|
||||
finishMultiSigningData(accountID, s);
|
||||
@@ -573,48 +555,42 @@ STTx::checkMultiSign(Rules const& rules, STObject const& sigObject) const
|
||||
rules);
|
||||
}
|
||||
|
||||
void
|
||||
STTx::buildBatchTxnIds()
|
||||
{
|
||||
// Precondition: the template must have been applied first, so the fields
|
||||
// (including sfRawTransactions) are canonical before the inner txns are
|
||||
// hashed. The constructors call this immediately after applying the
|
||||
// template; isFree() being false confirms a template is set.
|
||||
XRPL_ASSERT(!isFree(), "STTx::buildBatchTxnIds : template applied");
|
||||
if (getTxnType() != ttBATCH || !isFieldPresent(sfRawTransactions))
|
||||
return;
|
||||
|
||||
auto const& raw = getFieldArray(sfRawTransactions);
|
||||
|
||||
// Bound the eager hashing to the protocol cap. This runs in the STTx
|
||||
// constructor, i.e. at parse time, BEFORE preflight / passesLocalChecks
|
||||
// enforce the cap and BEFORE checkValidity's signature check. Without this
|
||||
// guard a malicious peer could put an oversized sfRawTransactions array in
|
||||
// a 1 MB blob and force hashing of every inner id at deserialization.
|
||||
// Leaving batchTxnIds_ unseated (nullopt) makes checkSign skip batch-signer
|
||||
// verification for the oversized batch, which is then dropped by the count
|
||||
// checks in preflight / passesLocalChecks downstream.
|
||||
if (raw.size() > kMaxBatchTxCount)
|
||||
return;
|
||||
|
||||
// For an in-cap batch the ids are always fully built, preserving the
|
||||
// invariant batchTxnIds_->size() == rawTransactions.size().
|
||||
auto& ids = batchTxnIds_.emplace();
|
||||
ids.reserve(raw.size());
|
||||
for (STObject const& rb : raw)
|
||||
ids.push_back(rb.getHash(HashPrefix::TransactionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Retrieves a batch of transaction IDs from the STTx.
|
||||
*
|
||||
* This function returns a vector of transaction IDs by extracting them from
|
||||
* the field array `sfRawTransactions` within the STTx. If the batch
|
||||
* transaction IDs have already been computed and cached in `batchTxnIds_`,
|
||||
* it returns the cached vector. Otherwise, it computes the transaction IDs,
|
||||
* caches them, and then returns the vector.
|
||||
*
|
||||
* @return A vector of `uint256` containing the batch transaction IDs.
|
||||
*
|
||||
* @note The function asserts that the `sfRawTransactions` field array is not
|
||||
* empty and that the size of the computed batch transaction IDs matches the
|
||||
* size of the `sfRawTransactions` field array.
|
||||
*/
|
||||
std::vector<uint256> const&
|
||||
STTx::getBatchTransactionIDs() const
|
||||
{
|
||||
XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::getBatchTransactionIDs : batch transaction");
|
||||
XRPL_ASSERT(getTxnType() == ttBATCH, "STTx::getBatchTransactionIDs : not a batch transaction");
|
||||
XRPL_ASSERT(
|
||||
batchTxnIds_.has_value(), "STTx::getBatchTransactionIDs : batch transaction IDs built");
|
||||
!getFieldArray(sfRawTransactions).empty(),
|
||||
"STTx::getBatchTransactionIDs : empty raw transactions");
|
||||
|
||||
// The list of inner ids is built once, then reused on subsequent calls.
|
||||
// After the list is built, it must always have the same size as the array
|
||||
// `sfRawTransactions`. The assert below verifies that.
|
||||
if (batchTxnIds_.empty())
|
||||
{
|
||||
for (STObject const& rb : getFieldArray(sfRawTransactions))
|
||||
batchTxnIds_.push_back(rb.getHash(HashPrefix::TransactionId));
|
||||
}
|
||||
|
||||
XRPL_ASSERT(
|
||||
batchTxnIds_->size() == getFieldArray(sfRawTransactions).size(),
|
||||
batchTxnIds_.size() == getFieldArray(sfRawTransactions).size(),
|
||||
"STTx::getBatchTransactionIDs : batch transaction IDs size mismatch");
|
||||
return *batchTxnIds_;
|
||||
return batchTxnIds_;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -751,22 +727,13 @@ invalidMPTAmountInTx(STObject const& tx)
|
||||
}
|
||||
|
||||
static bool
|
||||
isBatchRawTransactionOkay(STObject const& st, std::string& reason)
|
||||
isRawTransactionOkay(STObject const& st, std::string& reason)
|
||||
{
|
||||
if (!st.isFieldPresent(sfRawTransactions))
|
||||
return true;
|
||||
|
||||
// sfRawTransactions only appears on a Batch. passesLocalChecks runs on
|
||||
// unverified user and peer input, so reject (rather than assert) a non-batch
|
||||
// transaction that carries it.
|
||||
if (st.getFieldU16(sfTransactionType) != ttBATCH)
|
||||
{
|
||||
reason = "Only Batch transactions may contain raw transactions.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st.isFieldPresent(sfBatchSigners) &&
|
||||
st.getFieldArray(sfBatchSigners).size() > kMaxBatchSigners)
|
||||
st.getFieldArray(sfBatchSigners).size() > kMaxBatchTxCount)
|
||||
{
|
||||
reason = "Batch Signers array exceeds max entries.";
|
||||
return false;
|
||||
@@ -790,12 +757,6 @@ isBatchRawTransactionOkay(STObject const& st, std::string& reason)
|
||||
}
|
||||
|
||||
raw.applyTemplate(getTxFormat(tt)->getSOTemplate());
|
||||
|
||||
// passesLocalChecks recurses back into isBatchRawTransactionOkay,
|
||||
// but an inner can never be a batch (rejected above), so the
|
||||
// recursion terminates at depth 1.
|
||||
if (!passesLocalChecks(raw, reason))
|
||||
return false;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
@@ -830,7 +791,7 @@ passesLocalChecks(STObject const& st, std::string& reason)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isBatchRawTransactionOkay(st, reason))
|
||||
if (!isRawTransactionOkay(st, reason))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -106,7 +106,6 @@ transResults()
|
||||
MAKE_ERROR(tecLIMIT_EXCEEDED, "Limit exceeded."),
|
||||
MAKE_ERROR(tecPSEUDO_ACCOUNT, "This operation is not allowed against a pseudo-account."),
|
||||
MAKE_ERROR(tecPRECISION_LOSS, "The amounts used by the transaction cannot interact."),
|
||||
MAKE_ERROR(tecBAD_PROOF, "Proof cannot be verified"),
|
||||
|
||||
MAKE_ERROR(tefALREADY, "The exact transaction was already in this ledger."),
|
||||
MAKE_ERROR(tefBAD_ADD_AUTH, "Not authorized to add account."),
|
||||
@@ -130,8 +129,6 @@ transResults()
|
||||
MAKE_ERROR(tefNO_TICKET, "Ticket is not in ledger."),
|
||||
MAKE_ERROR(tefNFTOKEN_IS_NOT_TRANSFERABLE, "The specified NFToken is not transferable."),
|
||||
MAKE_ERROR(tefINVALID_LEDGER_FIX_TYPE, "The LedgerFixType field has an invalid value."),
|
||||
MAKE_ERROR(tefNO_DST_PARTIAL, "Partial payment to create account not allowed."),
|
||||
MAKE_ERROR(tefBAD_PATH_COUNT, "Malformed: Too many paths."),
|
||||
|
||||
MAKE_ERROR(telLOCAL_ERROR, "Local failure."),
|
||||
MAKE_ERROR(telBAD_DOMAIN, "Domain too long."),
|
||||
@@ -202,7 +199,6 @@ transResults()
|
||||
MAKE_ERROR(temARRAY_TOO_LARGE, "Malformed: Array is too large."),
|
||||
MAKE_ERROR(temBAD_TRANSFER_FEE, "Malformed: Transfer fee is outside valid range."),
|
||||
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
|
||||
MAKE_ERROR(temBAD_CIPHERTEXT, "Malformed: Invalid ciphertext."),
|
||||
|
||||
MAKE_ERROR(terRETRY, "Retry transaction."),
|
||||
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/invariants/InvariantCheck.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
@@ -115,7 +114,7 @@ ApplyContext::checkInvariantsHelper(
|
||||
tx, result, fee, *view_, journal)...}}; // NOLINT(bugprone-unchecked-optional-access)
|
||||
|
||||
// call each check's finalizer to see that it passes
|
||||
if (!std::ranges::all_of(finalizers, [](auto const& b) { return b; }))
|
||||
if (!std::all_of(finalizers.cbegin(), finalizers.cend(), [](auto const& b) { return b; }))
|
||||
{
|
||||
JLOG(journal.fatal()) << "Transaction has failed one or more global invariants: "
|
||||
<< to_string(tx.getJson(JsonOptions::Values::None));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
@@ -220,15 +221,13 @@ Transactor::preflight1(PreflightContext const& ctx, std::uint32_t flagMask)
|
||||
if (ctx.tx.getSeqProxy().isTicket() && ctx.tx.isFieldPresent(sfAccountTxnID))
|
||||
return temINVALID;
|
||||
|
||||
if (ctx.tx.isFlag(tfInnerBatchTxn) && !ctx.rules.enabled(featureBatchV1_1))
|
||||
if (ctx.tx.isFlag(tfInnerBatchTxn) && !ctx.rules.enabled(featureBatch))
|
||||
return temINVALID_FLAG;
|
||||
|
||||
// Reject if the inner batch flag and parentBatchId are inconsistent.
|
||||
// A standalone tx with tfInnerBatchTxn but no parentBatchId is an
|
||||
// attack attempt. A tx with parentBatchId but without tfInnerBatchTxn
|
||||
// is a programming error.
|
||||
if (ctx.tx.isFlag(tfInnerBatchTxn) != ctx.parentBatchId.has_value())
|
||||
return temINVALID_INNER_BATCH;
|
||||
XRPL_ASSERT(
|
||||
ctx.tx.isFlag(tfInnerBatchTxn) == ctx.parentBatchId.has_value() ||
|
||||
!ctx.rules.enabled(featureBatch),
|
||||
"Inner batch transaction must have a parent batch ID.");
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
@@ -244,19 +243,15 @@ Transactor::preflight2(PreflightContext const& ctx)
|
||||
return *ret;
|
||||
}
|
||||
|
||||
// Skip the signature check on batch inner transactions. preflight1 already
|
||||
// enforces both conditions; re-checking them as defense in depth guarantees
|
||||
// we never return success (and so skip signature validation) for an inner
|
||||
// transaction unless the amendment is enabled and it really sits inside a
|
||||
// batch.
|
||||
if (ctx.tx.isFlag(tfInnerBatchTxn))
|
||||
{
|
||||
if (!ctx.rules.enabled(featureBatchV1_1))
|
||||
return temINVALID_FLAG;
|
||||
if (!ctx.parentBatchId.has_value())
|
||||
return temINVALID_INNER_BATCH;
|
||||
// It should be impossible for the InnerBatchTxn flag to be set without
|
||||
// featureBatch being enabled
|
||||
XRPL_ASSERT_PARTS(
|
||||
!ctx.tx.isFlag(tfInnerBatchTxn) || ctx.rules.enabled(featureBatch),
|
||||
"xrpl::Transactor::preflight2",
|
||||
"InnerBatch flag only set if feature enabled");
|
||||
// Skip signature check on batch inner transactions
|
||||
if (ctx.tx.isFlag(tfInnerBatchTxn) && ctx.rules.enabled(featureBatch))
|
||||
return tesSUCCESS;
|
||||
}
|
||||
// Do not add any checks after this point that are relevant for
|
||||
// batch inner transactions. They will be skipped.
|
||||
|
||||
@@ -361,15 +356,6 @@ Transactor::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
return baseFee + (signerCount * baseFee);
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
Transactor::calculateBaseFee(
|
||||
ReadView const& view,
|
||||
STTx const& tx,
|
||||
std::uint32_t extraBaseFeeMultiplier)
|
||||
{
|
||||
return calculateBaseFee(view, tx) + view.fees().base * extraBaseFeeMultiplier;
|
||||
}
|
||||
|
||||
// Returns the fee in fee units, not scaled for load.
|
||||
XRPAmount
|
||||
Transactor::calculateOwnerReserveFee(ReadView const& view, STTx const& tx)
|
||||
@@ -542,7 +528,7 @@ Transactor::checkSeqProxy(ReadView const& view, STTx const& tx, beast::Journal j
|
||||
}
|
||||
|
||||
// Transaction can never succeed if the Ticket is not in the ledger.
|
||||
if (!view.exists(keylet::ticket(id, tSeqProx)))
|
||||
if (!view.exists(keylet::kTicket(id, tSeqProx)))
|
||||
{
|
||||
JLOG(j.trace()) << "applyTransaction: ticket already used or never created "
|
||||
<< "a_seq=" << aSeq << " t_seq=" << tSeqProx;
|
||||
@@ -607,7 +593,7 @@ Transactor::ticketDelete(
|
||||
{
|
||||
// Delete the Ticket, adjust the account root ticket count, and
|
||||
// reduce the owner count.
|
||||
SLE::pointer const sleTicket = view.peek(keylet::ticket(ticketIndex));
|
||||
SLE::pointer const sleTicket = view.peek(keylet::kTicket(ticketIndex));
|
||||
if (!sleTicket)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
@@ -713,26 +699,23 @@ Transactor::checkSign(
|
||||
std::optional<uint256 const> const& parentBatchId,
|
||||
AccountID const& idAccount,
|
||||
STObject const& sigObject,
|
||||
beast::Journal const j,
|
||||
bool permitUncreatedAccount)
|
||||
beast::Journal const j)
|
||||
{
|
||||
{
|
||||
auto const sle = view.read(keylet::account(idAccount));
|
||||
|
||||
if ((view.rules().enabled(featureLendingProtocol) ||
|
||||
view.rules().enabled(featureBatchV1_1) || view.rules().enabled(fixCleanup3_3_0)) &&
|
||||
isPseudoAccount(sle))
|
||||
if (view.rules().enabled(featureLendingProtocol) && isPseudoAccount(sle))
|
||||
{
|
||||
// Pseudo-accounts can't sign transactions. This check is gated on a
|
||||
// few different amendments so that it takes effect as soon as any of
|
||||
// them is activated.
|
||||
// Pseudo-accounts can't sign transactions. This check is gated on
|
||||
// the Lending Protocol amendment because that's the project it was
|
||||
// added under, and it doesn't justify another amendment
|
||||
return tefBAD_AUTH;
|
||||
}
|
||||
}
|
||||
|
||||
auto const pkSigner = sigObject.getFieldVL(sfSigningPubKey);
|
||||
// Ignore signature check on batch inner transactions
|
||||
if (parentBatchId && view.rules().enabled(featureBatchV1_1))
|
||||
if (parentBatchId && view.rules().enabled(featureBatch))
|
||||
{
|
||||
// Defensive Check: These values are also checked in Batch::preflight
|
||||
if (sigObject.isFieldPresent(sfTxnSignature) || !pkSigner.empty() ||
|
||||
@@ -770,16 +753,7 @@ Transactor::checkSign(
|
||||
auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
|
||||
auto const sleAccount = view.read(keylet::account(idAccount));
|
||||
if (!sleAccount)
|
||||
{
|
||||
// An account that does not exist yet can only be authorized by its own
|
||||
// master key, and only where an un-created signer is permitted (a batch
|
||||
// whose earlier inner creates the account). Otherwise it cannot sign.
|
||||
if (!permitUncreatedAccount)
|
||||
return terNO_ACCOUNT;
|
||||
if (idAccount != idSigner)
|
||||
return tefBAD_AUTH;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
return checkSingleSign(view, idSigner, idAccount, sleAccount, j);
|
||||
}
|
||||
@@ -792,6 +766,50 @@ Transactor::checkSign(PreclaimContext const& ctx)
|
||||
return checkSign(ctx.view, ctx.flags, ctx.parentBatchId, idAccount, ctx.tx, ctx.j);
|
||||
}
|
||||
|
||||
NotTEC
|
||||
Transactor::checkBatchSign(PreclaimContext const& ctx)
|
||||
{
|
||||
NotTEC ret = tesSUCCESS;
|
||||
STArray const& signers{ctx.tx.getFieldArray(sfBatchSigners)};
|
||||
for (auto const& signer : signers)
|
||||
{
|
||||
auto const idAccount = signer.getAccountID(sfAccount);
|
||||
|
||||
Blob const& pkSigner = signer.getFieldVL(sfSigningPubKey);
|
||||
if (pkSigner.empty())
|
||||
{
|
||||
if (ret = checkMultiSign(ctx.view, ctx.flags, idAccount, signer, ctx.j);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
if (!publicKeyType(makeSlice(pkSigner)))
|
||||
return tefBAD_AUTH;
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
|
||||
auto const sleAccount = ctx.view.read(keylet::account(idAccount));
|
||||
|
||||
// A batch can include transactions from an un-created account ONLY
|
||||
// when the account master key is the signer
|
||||
if (!sleAccount)
|
||||
{
|
||||
if (idAccount != idSigner)
|
||||
return tefBAD_AUTH;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
if (ret = checkSingleSign(ctx.view, idSigner, idAccount, sleAccount, ctx.j);
|
||||
!isTesSuccess(ret))
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
NotTEC
|
||||
Transactor::checkSingleSign(
|
||||
ReadView const& view,
|
||||
@@ -833,7 +851,7 @@ Transactor::checkMultiSign(
|
||||
beast::Journal const j)
|
||||
{
|
||||
// Get id's SignerList and Quorum.
|
||||
STLedgerEntry::const_pointer const sleAccountSigners = view.read(keylet::signerList(id));
|
||||
STLedgerEntry::const_pointer const sleAccountSigners = view.read(keylet::signers(id));
|
||||
// If the signer list doesn't exist the account is not multi-signing.
|
||||
if (!sleAccountSigners)
|
||||
{
|
||||
@@ -1013,7 +1031,7 @@ removeExpiredNFTokenOffers(
|
||||
|
||||
for (auto const& index : offers)
|
||||
{
|
||||
if (auto const offer = view.peek(keylet::nftokenOffer(index)))
|
||||
if (auto const offer = view.peek(keylet::nftoffer(index)))
|
||||
{
|
||||
nft::deleteTokenOffer(view, offer);
|
||||
if (++removed == kExpiredOfferRemoveLimit)
|
||||
@@ -1087,7 +1105,7 @@ Transactor::reset(XRPAmount fee)
|
||||
|
||||
// balance should have already been checked in checkFee / preFlight.
|
||||
XRPL_ASSERT(
|
||||
(fee == beast::kZero || balance != beast::kZero) && (!view().open() || balance >= fee),
|
||||
balance != beast::kZero && (!view().open() || balance >= fee),
|
||||
"xrpl::Transactor::reset : valid balance");
|
||||
|
||||
// We retry/reject the transaction if the account balance is zero or
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/OpenView.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
@@ -38,14 +39,30 @@ checkValidity(HashRouter& router, STTx const& tx, Rules const& rules)
|
||||
auto const id = tx.getTransactionID();
|
||||
auto const flags = router.getFlags(id);
|
||||
|
||||
// Batch inner transactions are never independently valid: they are applied
|
||||
// within their batch, not through checkValidity. Reaching here means one was
|
||||
// relayed or submitted on its own, so mark it bad regardless of the
|
||||
// amendment (like PeerImp and NetworkOPs).
|
||||
if (tx.isFlag(tfInnerBatchTxn))
|
||||
// Ignore signature check on batch inner transactions
|
||||
if (tx.isFlag(tfInnerBatchTxn) && rules.enabled(featureBatch))
|
||||
{
|
||||
router.setFlags(id, kSfSigbad);
|
||||
return {Validity::SigBad, "Batch inner transactions are never considered validly signed."};
|
||||
// Defensive Check: These values are also checked in Batch::preflight
|
||||
if (tx.isFieldPresent(sfTxnSignature) || !tx.getSigningPubKey().empty() ||
|
||||
tx.isFieldPresent(sfSigners))
|
||||
return {Validity::SigBad, "Malformed: Invalid inner batch transaction."};
|
||||
|
||||
// This block should probably have never been included in the
|
||||
// original `Batch` implementation. An inner transaction never
|
||||
// has a valid signature.
|
||||
bool const neverValid = rules.enabled(fixBatchInnerSigs);
|
||||
if (!neverValid)
|
||||
{
|
||||
std::string reason;
|
||||
if (!passesLocalChecks(tx, reason))
|
||||
{
|
||||
router.setFlags(id, kSfLocalbad);
|
||||
return {Validity::SigGoodOnly, reason};
|
||||
}
|
||||
|
||||
router.setFlags(id, kSfSiggood);
|
||||
return {Validity::Valid, ""};
|
||||
}
|
||||
}
|
||||
|
||||
if (any(flags & kSfSigbad))
|
||||
@@ -166,9 +183,6 @@ applyBatchTransactions(
|
||||
|
||||
// If the transaction should be applied push its changes to the
|
||||
// whole-batch view.
|
||||
// NOTE: each inner tx is individually capped at kOversizeMetaDataCap;
|
||||
// there is no aggregate cap here. Bounded by kMaxBatchTxCount * cap,
|
||||
// which standalone txns can already produce in one ledger.
|
||||
if (ret.applied && (isTesSuccess(ret.ter) || isTecClaim(ret.ter)))
|
||||
perTxBatchView.apply(batchView);
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -64,23 +63,6 @@ hasPrivilege(STTx const& tx, Privilege priv)
|
||||
#undef TRANSACTION
|
||||
#pragma pop_macro("TRANSACTION")
|
||||
|
||||
// Returns the human-readable name of a ledger entry's type, falling back to
|
||||
// the numeric type if the format is somehow unknown.
|
||||
static std::string
|
||||
ledgerEntryTypeName(SLE const& sle)
|
||||
{
|
||||
auto const item = LedgerFormats::getInstance().findByType(sle.getType());
|
||||
|
||||
if (item == nullptr)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::ledgerEntryTypeName : ledger entry has no known ledger format");
|
||||
return std::to_string(sle.getType());
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
return item->getName();
|
||||
}
|
||||
|
||||
void
|
||||
TransactionFeeCheck::visitEntry(bool, SLE::const_ref, SLE::const_ref)
|
||||
{
|
||||
@@ -475,8 +457,16 @@ AccountRootsDeletedClean::finalize(
|
||||
if (auto const sle = view.read(keylet))
|
||||
{
|
||||
// Finding the object is bad
|
||||
JLOG(j.fatal()) << "Invariant failed: account deletion left behind a "
|
||||
<< ledgerEntryTypeName(*sle) << " object";
|
||||
auto const typeName = [&sle]() {
|
||||
auto item = LedgerFormats::getInstance().findByType(sle->getType());
|
||||
|
||||
if (item != nullptr)
|
||||
return item->getName();
|
||||
return std::to_string(sle->getType());
|
||||
}();
|
||||
|
||||
JLOG(j.fatal()) << "Invariant failed: account deletion left behind a " << typeName
|
||||
<< " object";
|
||||
// The comment above starting with "assert(enforce)" explains this
|
||||
// assert.
|
||||
XRPL_ASSERT(
|
||||
@@ -528,8 +518,8 @@ AccountRootsDeletedClean::finalize(
|
||||
// checked above as entries in directAccountKeylets. This uses
|
||||
// view.succ() to check for any NFT pages in between the two
|
||||
// endpoints.
|
||||
Keylet const first = keylet::nftokenPageMin(accountID);
|
||||
Keylet const last = keylet::nftokenPageMax(accountID);
|
||||
Keylet const first = keylet::nftpageMin(accountID);
|
||||
Keylet const last = keylet::nftpageMax(accountID);
|
||||
|
||||
std::optional<uint256> key = view.succ(first.key, last.key.next());
|
||||
|
||||
@@ -886,9 +876,10 @@ ValidPseudoAccounts::visitEntry(bool isDelete, SLE::const_ref before, SLE::const
|
||||
{
|
||||
std::vector<SField const*> const& fields = getPseudoAccountFields();
|
||||
|
||||
auto const numFields = std::ranges::count_if(
|
||||
fields,
|
||||
[&after](SField const* sf) -> bool { return after->isFieldPresent(*sf); });
|
||||
auto const numFields =
|
||||
std::count_if(fields.begin(), fields.end(), [&after](SField const* sf) -> bool {
|
||||
return after->isFieldPresent(*sf);
|
||||
});
|
||||
if (numFields != 1)
|
||||
{
|
||||
std::stringstream error;
|
||||
@@ -1080,69 +1071,4 @@ ValidAmounts::finalize(
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ObjectHasPseudoAccount::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after)
|
||||
{
|
||||
if (!isDelete)
|
||||
return;
|
||||
|
||||
// Before should never be null when isDelete = true
|
||||
if (!before)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
"xrpl::ObjectHasPseudoAccount::visitEntry : deleted ledger entry missing before state");
|
||||
return;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
switch (before->getType())
|
||||
{
|
||||
case ltAMM:
|
||||
case ltVAULT:
|
||||
case ltLOAN_BROKER:
|
||||
deletedObjSles_.push_back(before);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
ObjectHasPseudoAccount::finalize(
|
||||
STTx const&,
|
||||
TER const,
|
||||
XRPAmount const,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) const
|
||||
{
|
||||
if (!view.rules().enabled(fixCleanup3_3_0))
|
||||
return true;
|
||||
|
||||
if (deletedObjSles_.empty())
|
||||
return true;
|
||||
|
||||
bool failed = false;
|
||||
for (auto const& sle : deletedObjSles_)
|
||||
{
|
||||
if (!sle->isFieldPresent(sfAccount))
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted " << ledgerEntryTypeName(*sle)
|
||||
<< " is missing pseudo-account field";
|
||||
failed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The pseudo-account must NOT exist on the ledger after the object is deleted.
|
||||
if (view.exists(keylet::account(sle->getAccountID(sfAccount))))
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: deleted " << ledgerEntryTypeName(*sle)
|
||||
<< " without deleting its pseudo-account";
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !failed;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -130,7 +130,7 @@ ValidLoanBroker::finalize(
|
||||
for (auto const& [brokerID, broker] : brokers_)
|
||||
{
|
||||
auto const& after =
|
||||
broker.brokerAfter ? broker.brokerAfter : view.read(keylet::loanBroker(brokerID));
|
||||
broker.brokerAfter ? broker.brokerAfter : view.read(keylet::loanbroker(brokerID));
|
||||
|
||||
if (!after)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#include <xrpl/tx/invariants/MPTInvariant.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
@@ -25,46 +21,11 @@
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/invariants/InvariantCheckPrivilege.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace {
|
||||
constexpr auto kConfidentialMptTxTypes = std::to_array<TxType>({
|
||||
ttCONFIDENTIAL_MPT_SEND,
|
||||
ttCONFIDENTIAL_MPT_CONVERT,
|
||||
ttCONFIDENTIAL_MPT_CONVERT_BACK,
|
||||
ttCONFIDENTIAL_MPT_MERGE_INBOX,
|
||||
ttCONFIDENTIAL_MPT_CLAWBACK,
|
||||
});
|
||||
|
||||
// Clamp to the cap (== INT64_MAX) before the signed conversion. Invariant
|
||||
// tests can inject INT64_MAX + 1, which would result in undefined behavior
|
||||
// under UBSan if converted directly.
|
||||
std::int64_t
|
||||
toSignedMPTAmount(std::uint64_t amount)
|
||||
{
|
||||
return static_cast<std::int64_t>(std::min(amount, kMaxMpTokenAmount));
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
addMPTAmountDelta(std::int64_t delta, std::uint64_t amount)
|
||||
{
|
||||
return delta + toSignedMPTAmount(amount);
|
||||
}
|
||||
|
||||
std::int64_t
|
||||
subtractMPTAmountDelta(std::int64_t delta, std::uint64_t amount)
|
||||
{
|
||||
return delta - toSignedMPTAmount(amount);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void
|
||||
ValidMPTIssuance::visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after)
|
||||
{
|
||||
@@ -475,16 +436,6 @@ ValidMPTPayment::finalize(
|
||||
{
|
||||
if (isTesSuccess(result))
|
||||
{
|
||||
// Confidential transactions are validated by ValidConfidentialMPToken.
|
||||
// They modify encrypted fields and sfConfidentialOutstandingAmount
|
||||
// rather than sfMPTAmount/sfOutstandingAmount in the standard way,
|
||||
// so ValidMPTPayment's accounting does not apply to them.
|
||||
if (std::ranges::find(kConfidentialMptTxTypes, tx.getTxnType()) !=
|
||||
kConfidentialMptTxTypes.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool const invariantPasses = !view.rules().enabled(featureMPTokensV2);
|
||||
if (overflow_)
|
||||
{
|
||||
@@ -515,261 +466,6 @@ ValidMPTPayment::finalize(
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ValidConfidentialMPToken::visitEntry(
|
||||
bool isDelete,
|
||||
std::shared_ptr<SLE const> const& before,
|
||||
std::shared_ptr<SLE const> const& after)
|
||||
{
|
||||
// Helper to get MPToken Issuance ID safely
|
||||
auto const getMptID = [](std::shared_ptr<SLE const> const& sle) -> uint192 {
|
||||
if (!sle)
|
||||
return beast::kZero;
|
||||
if (sle->getType() == ltMPTOKEN)
|
||||
return sle->getFieldH192(sfMPTokenIssuanceID);
|
||||
if (sle->getType() == ltMPTOKEN_ISSUANCE)
|
||||
return makeMptID(sle->getFieldU32(sfSequence), sle->getAccountID(sfIssuer));
|
||||
return beast::kZero;
|
||||
};
|
||||
|
||||
if (before && before->getType() == ltMPTOKEN)
|
||||
{
|
||||
uint192 const id = getMptID(before);
|
||||
auto& change = changes_[id];
|
||||
change.mptAmountDelta =
|
||||
subtractMPTAmountDelta(change.mptAmountDelta, before->getFieldU64(sfMPTAmount));
|
||||
|
||||
// Cannot delete MPToken with non-zero confidential state or non-zero public amount
|
||||
if (isDelete)
|
||||
{
|
||||
bool const hasPublicBalance = before->getFieldU64(sfMPTAmount) > 0;
|
||||
bool const hasEncryptedFields = before->isFieldPresent(sfConfidentialBalanceSpending) ||
|
||||
before->isFieldPresent(sfConfidentialBalanceInbox) ||
|
||||
before->isFieldPresent(sfIssuerEncryptedBalance) ||
|
||||
before->isFieldPresent(sfAuditorEncryptedBalance);
|
||||
|
||||
if (hasPublicBalance || hasEncryptedFields)
|
||||
changes_[id].deletedWithEncrypted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (after && after->getType() == ltMPTOKEN)
|
||||
{
|
||||
uint192 const id = getMptID(after);
|
||||
auto& change = changes_[id];
|
||||
change.mptAmountDelta =
|
||||
addMPTAmountDelta(change.mptAmountDelta, after->getFieldU64(sfMPTAmount));
|
||||
|
||||
// Encrypted field existence consistency
|
||||
bool const hasIssuerBalance = after->isFieldPresent(sfIssuerEncryptedBalance);
|
||||
bool const hasHolderInbox = after->isFieldPresent(sfConfidentialBalanceInbox);
|
||||
bool const hasHolderSpending = after->isFieldPresent(sfConfidentialBalanceSpending);
|
||||
bool const hasAuditorBalance = after->isFieldPresent(sfAuditorEncryptedBalance);
|
||||
|
||||
// The core encrypted balances must all exist or not exist at the same time. The auditor
|
||||
// balance is optional, but cannot exist without the core fields.
|
||||
if (hasHolderInbox != hasHolderSpending || hasHolderInbox != hasIssuerBalance ||
|
||||
(hasAuditorBalance && !hasIssuerBalance))
|
||||
changes_[id].badConsistency = true;
|
||||
|
||||
auto const confidentialBalanceFieldChanged = [&before, &after](auto const& field) {
|
||||
auto const afterValue = (*after)[~field];
|
||||
if (!afterValue)
|
||||
return false;
|
||||
|
||||
if (!before || before->getType() != ltMPTOKEN)
|
||||
return true; // LCOV_EXCL_LINE
|
||||
|
||||
return (*before)[~field] != afterValue;
|
||||
};
|
||||
|
||||
if (confidentialBalanceFieldChanged(sfConfidentialBalanceInbox) ||
|
||||
confidentialBalanceFieldChanged(sfConfidentialBalanceSpending) ||
|
||||
confidentialBalanceFieldChanged(sfIssuerEncryptedBalance) ||
|
||||
confidentialBalanceFieldChanged(sfAuditorEncryptedBalance))
|
||||
{
|
||||
changes_[id].changesConfidentialFields = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (before && before->getType() == ltMPTOKEN_ISSUANCE)
|
||||
{
|
||||
uint192 const id = getMptID(before);
|
||||
auto& change = changes_[id];
|
||||
if (before->isFieldPresent(sfConfidentialOutstandingAmount))
|
||||
{
|
||||
change.coaDelta = subtractMPTAmountDelta(
|
||||
change.coaDelta, before->getFieldU64(sfConfidentialOutstandingAmount));
|
||||
}
|
||||
change.outstandingDelta = subtractMPTAmountDelta(
|
||||
change.outstandingDelta, before->getFieldU64(sfOutstandingAmount));
|
||||
}
|
||||
|
||||
if (after && after->getType() == ltMPTOKEN_ISSUANCE)
|
||||
{
|
||||
uint192 const id = getMptID(after);
|
||||
auto& change = changes_[id];
|
||||
|
||||
bool const hasCOA = after->isFieldPresent(sfConfidentialOutstandingAmount);
|
||||
std::uint64_t const coa = (*after)[~sfConfidentialOutstandingAmount].value_or(0);
|
||||
std::uint64_t const oa = after->getFieldU64(sfOutstandingAmount);
|
||||
|
||||
if (hasCOA)
|
||||
change.coaDelta = addMPTAmountDelta(change.coaDelta, coa);
|
||||
|
||||
change.outstandingDelta = addMPTAmountDelta(change.outstandingDelta, oa);
|
||||
change.issuance = after;
|
||||
|
||||
// COA <= OutstandingAmount
|
||||
if (coa > oa)
|
||||
change.badCOA = true;
|
||||
}
|
||||
|
||||
if (before && after && before->getType() == ltMPTOKEN && after->getType() == ltMPTOKEN)
|
||||
{
|
||||
uint192 const id = getMptID(after);
|
||||
|
||||
// sfConfidentialBalanceVersion must change when spending changes
|
||||
auto const spendingBefore = (*before)[~sfConfidentialBalanceSpending];
|
||||
auto const spendingAfter = (*after)[~sfConfidentialBalanceSpending];
|
||||
auto const versionBefore = (*before)[~sfConfidentialBalanceVersion];
|
||||
auto const versionAfter = (*after)[~sfConfidentialBalanceVersion];
|
||||
|
||||
if (spendingBefore.has_value() && spendingBefore != spendingAfter)
|
||||
{
|
||||
if (versionBefore == versionAfter)
|
||||
changes_[id].badVersion = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ValidConfidentialMPToken::finalize(
|
||||
STTx const& tx,
|
||||
TER const result,
|
||||
XRPAmount const,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j)
|
||||
{
|
||||
if (result != tesSUCCESS)
|
||||
return true;
|
||||
|
||||
for (auto const& [id, checks] : changes_)
|
||||
{
|
||||
// Find the MPTokenIssuance
|
||||
auto const issuance = [&]() -> std::shared_ptr<SLE const> {
|
||||
if (checks.issuance)
|
||||
return checks.issuance;
|
||||
return view.read(keylet::mptokenIssuance(id));
|
||||
}();
|
||||
|
||||
// Skip all invariance checks if issuance doesn't exist because that means the MPT has been
|
||||
// deleted
|
||||
if (!issuance)
|
||||
continue;
|
||||
|
||||
// Cannot delete MPToken with non-zero confidential state
|
||||
if (checks.deletedWithEncrypted)
|
||||
{
|
||||
if ((*issuance)[~sfConfidentialOutstandingAmount].value_or(0) > 0)
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Invariant failed: MPToken deleted with encrypted fields while COA > 0";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Encrypted field existence consistency
|
||||
if (checks.badConsistency)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: MPToken encrypted field "
|
||||
"existence inconsistency";
|
||||
return false;
|
||||
}
|
||||
|
||||
// COA <= OutstandingAmount
|
||||
if (checks.badCOA)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: Confidential outstanding amount "
|
||||
"exceeds total outstanding amount";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confidential balance fields may remain on a holder MPToken after all
|
||||
// confidential balances have returned to zero. Only creating or
|
||||
// changing those fields requires the issuance privacy flag.
|
||||
if (checks.changesConfidentialFields)
|
||||
{
|
||||
if (!issuance->isFlag(lsfMPTCanHoldConfidentialBalance))
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: MPToken has encrypted "
|
||||
"fields but Issuance does not have "
|
||||
"lsfMPTCanHoldConfidentialBalance set";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We only enforce this when Confidential Outstanding Amount changes (Convert, ConvertBack,
|
||||
// ConfidentialClawback). This avoids falsely failing on Escrow or AMM operations that lock
|
||||
// public tokens outside of ltMPTOKEN. Convert / ConvertBack:
|
||||
// - COA and MPTAmount must have opposite deltas, which cancel each other out to zero.
|
||||
// - OA remains unchanged.
|
||||
// - Therefore, the net delta on both sides of the equation is zero.
|
||||
//
|
||||
// Clawback:
|
||||
// - MPTAmount remains unchanged.
|
||||
// - COA and OA must have identical deltas (mirrored on each side).
|
||||
// - The equation remains balanced as both sides have equal offsets.
|
||||
if (checks.coaDelta != 0)
|
||||
{
|
||||
if (checks.mptAmountDelta + checks.coaDelta != checks.outstandingDelta)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: Token conservation "
|
||||
"violation for MPT "
|
||||
<< to_string(id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (
|
||||
std::ranges::find(kConfidentialMptTxTypes, tx.getTxnType()) !=
|
||||
kConfidentialMptTxTypes.end())
|
||||
{
|
||||
// Confidential Txns should not modify public MPTAmount balance
|
||||
// if Confidential Amount Delta is 0
|
||||
if (checks.mptAmountDelta != 0)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: MPTAmount changed by confidential "
|
||||
"transaction that should not modify this field."
|
||||
<< to_string(id);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Among confidential MPT transactions, only ConfidentialMPTSend and
|
||||
// ConfidentialMPTMergeInbox leave coaDelta unmodified. Therefore, if a confidential MPT
|
||||
// transaction reaches here, it must be one of these two types, neither of which will
|
||||
// modify sfOutstandingAmount
|
||||
if (checks.outstandingDelta != 0)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: OutstandingAmount changed "
|
||||
"by confidential transaction that should not "
|
||||
"modify it for MPT "
|
||||
<< to_string(id);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (checks.badVersion)
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Invariant failed: MPToken sfConfidentialBalanceVersion not updated when "
|
||||
"sfConfidentialBalanceSpending changed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ValidMPTTransfer::visitEntry(
|
||||
bool isDelete,
|
||||
@@ -813,15 +509,6 @@ ValidMPTTransfer::isAuthorized(
|
||||
AccountID const& holder,
|
||||
bool reqAuth) const
|
||||
{
|
||||
// Pseudo-accounts (Vault, LoanBroker, AMM) hold assets on behalf of their
|
||||
// participants and are implicitly authorized for any MPT they hold,
|
||||
// including vault shares whose underlying asset would otherwise require
|
||||
// auth. Exempt them here rather than relying on requireAuth: the recursive
|
||||
// share -> underlying descent in requireAuth fails for a pseudo-account
|
||||
// that holds the share but not the underlying.
|
||||
if (isPseudoAccount(view, holder, {&sfVaultID, &sfLoanBrokerID, &sfAMMID}))
|
||||
return true;
|
||||
|
||||
auto const key = keylet::mptoken(mptid, holder);
|
||||
auto const it = deletedAuthorized_.find(key.key);
|
||||
if (it != deletedAuthorized_.end())
|
||||
@@ -837,8 +524,6 @@ ValidMPTTransfer::finalize(
|
||||
ReadView const& view,
|
||||
beast::Journal const& j)
|
||||
{
|
||||
auto const fix330Enabled = view.rules().enabled(fixCleanup3_3_0);
|
||||
|
||||
if (hasPrivilege(tx, OverrideFreeze))
|
||||
return true;
|
||||
|
||||
@@ -866,7 +551,7 @@ ValidMPTTransfer::finalize(
|
||||
std::uint16_t senders = 0;
|
||||
std::uint16_t receivers = 0;
|
||||
bool invalidTransfer = false;
|
||||
auto const sleIssuance = view.read(keylet::mptokenIssuance(mptID));
|
||||
auto const sleIssuance = view.read(keylet::mptIssuance(mptID));
|
||||
if (!sleIssuance)
|
||||
{
|
||||
continue;
|
||||
@@ -899,29 +584,12 @@ ValidMPTTransfer::finalize(
|
||||
++senders;
|
||||
}
|
||||
|
||||
// Check once: if any involved account is frozen, the whole issuance transfer is
|
||||
// considered frozen. Only need to check for frozen if there is a transfer of funds.
|
||||
//
|
||||
// Post-fix330: full isFrozen() applies — vault-share transitive freeze is part of
|
||||
// the freeze semantics for all changed holders.
|
||||
//
|
||||
// Pre-fix330: legacy AMM withdraw only checked individual freeze on the
|
||||
// destination, not the transitive vault freeze. All other paths (and the AMM
|
||||
// account itself as sender) did apply the full check.
|
||||
MPTIssue const issue{mptID};
|
||||
auto const legacyAccountFrozen = [&] {
|
||||
if (isGlobalFrozen(view, issue) || isIndividualFrozen(view, account, issue))
|
||||
return true;
|
||||
bool const isReceiver =
|
||||
!value.amtBefore.has_value() || *value.amtAfter > *value.amtBefore;
|
||||
if (txnType == ttAMM_WITHDRAW && isReceiver)
|
||||
return false;
|
||||
return isVaultPseudoAccountFrozen(view, account, issue, 0);
|
||||
};
|
||||
bool const accountFrozen =
|
||||
fix330Enabled ? isFrozen(view, account, issue) : legacyAccountFrozen();
|
||||
// Check once: if any involved account is frozen, the whole
|
||||
// issuance transfer is considered frozen. Only need to check for
|
||||
// frozen if there is a transfer of funds.
|
||||
if (!invalidTransfer &&
|
||||
(accountFrozen || !isAuthorized(view, mptID, account, reqAuth)))
|
||||
(isFrozen(view, account, MPTIssue{mptID}) ||
|
||||
!isAuthorized(view, mptID, account, reqAuth)))
|
||||
{
|
||||
invalidTransfer = true;
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ ValidVault::deltaAssets(AccountID const& id) const
|
||||
{
|
||||
if (isXRP(issue))
|
||||
return lookup(keylet::account(id).key);
|
||||
auto result = lookup(keylet::trustLine(id, issue).key);
|
||||
auto result = lookup(keylet::line(id, issue).key);
|
||||
// Trust-line balance is stored from the low-account's perspective;
|
||||
// negate if id is the high account so the delta is in id's terms.
|
||||
if (result && id > issue.getIssuer())
|
||||
@@ -238,7 +238,7 @@ ValidVault::deltaShares(AccountID const& id) const
|
||||
auto const& afterVault = afterVault_[0];
|
||||
auto const it = [&]() {
|
||||
if (id == afterVault.pseudoId)
|
||||
return deltas_.find(keylet::mptokenIssuance(afterVault.shareMPTID).key);
|
||||
return deltas_.find(keylet::mptIssuance(afterVault.shareMPTID).key);
|
||||
return deltas_.find(keylet::mptoken(afterVault.shareMPTID, id).key);
|
||||
}();
|
||||
|
||||
@@ -411,7 +411,7 @@ ValidVault::finalize(
|
||||
return e;
|
||||
}
|
||||
|
||||
auto const sleShares = view.read(keylet::mptokenIssuance(afterVault.shareMPTID));
|
||||
auto const sleShares = view.read(keylet::mptIssuance(afterVault.shareMPTID));
|
||||
|
||||
return sleShares ? std::optional<Shares>(Shares::make(*sleShares)) : std::nullopt;
|
||||
}();
|
||||
|
||||
@@ -1359,7 +1359,7 @@ BookStep<TIn, TOut, TDerived>::check(StrandContext const& ctx) const
|
||||
|
||||
auto const err = book_.in.visit(
|
||||
[&](Issue const& issue) -> std::optional<TER> {
|
||||
auto sle = view.read(keylet::trustLine(*prev, cur, issue.currency));
|
||||
auto sle = view.read(keylet::line(*prev, cur, issue.currency));
|
||||
if (!sle)
|
||||
return terNO_LINE;
|
||||
if (sle->isFlag((cur > *prev) ? lsfHighNoRipple : lsfLowNoRipple))
|
||||
|
||||
@@ -344,7 +344,7 @@ DirectIPaymentStep::quality(ReadView const& sb, QualityDirection qDir) const
|
||||
if (src_ == dst_)
|
||||
return QUALITY_ONE;
|
||||
|
||||
auto const sle = sb.read(keylet::trustLine(dst_, src_, currency_));
|
||||
auto const sle = sb.read(keylet::line(dst_, src_, currency_));
|
||||
|
||||
if (!sle)
|
||||
return QUALITY_ONE;
|
||||
@@ -420,7 +420,7 @@ DirectIPaymentStep::check(StrandContext const& ctx, SLE::const_ref sleSrc) const
|
||||
// Since this is a payment a trust line must be present. Perform all
|
||||
// trust line related checks.
|
||||
{
|
||||
auto const sleLine = ctx.view.read(keylet::trustLine(src_, dst_, currency_));
|
||||
auto const sleLine = ctx.view.read(keylet::line(src_, dst_, currency_));
|
||||
if (!sleLine)
|
||||
{
|
||||
JLOG(j_.trace()) << "DirectStepI: No credit line. " << *this;
|
||||
|
||||
@@ -434,7 +434,7 @@ MPTEndpointStep<TDerived>::maxPaymentFlow(ReadView const& sb) const
|
||||
return {toAmount<MPTAmount>(maxFlow), DebtDirection::Redeems};
|
||||
|
||||
// From an issuer to a holder
|
||||
if (auto const sle = sb.read(keylet::mptokenIssuance(mptIssue_)))
|
||||
if (auto const sle = sb.read(keylet::mptIssuance(mptIssue_)))
|
||||
{
|
||||
// If issuer is the source account, and it is direct payment then
|
||||
// MPTEndpointStep is the only step. Provide available maxFlow.
|
||||
|
||||
@@ -203,7 +203,7 @@ private:
|
||||
{
|
||||
return ctx.strandDeliver.visit(
|
||||
[&](Issue const& issue) {
|
||||
if (!ctx.view.exists(keylet::trustLine(acc, issue)))
|
||||
if (!ctx.view.exists(keylet::line(acc, issue)))
|
||||
return -1;
|
||||
return 0;
|
||||
},
|
||||
|
||||
@@ -260,8 +260,8 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
|
||||
return tecHAS_OBLIGATIONS;
|
||||
|
||||
// If the account owns any NFTs it cannot be deleted.
|
||||
Keylet const first = keylet::nftokenPageMin(account);
|
||||
Keylet const last = keylet::nftokenPageMax(account);
|
||||
Keylet const first = keylet::nftpageMin(account);
|
||||
Keylet const last = keylet::nftpageMax(account);
|
||||
|
||||
auto const cp = ctx.view.read(
|
||||
Keylet(ltNFTOKEN_PAGE, ctx.view.succ(first.key, last.key.next()).value_or(last.key)));
|
||||
|
||||
@@ -194,27 +194,30 @@ AccountSet::preclaim(PreclaimContext const& ctx)
|
||||
//
|
||||
// Clawback
|
||||
//
|
||||
if (uSetFlag == asfAllowTrustLineClawback)
|
||||
if (ctx.view.rules().enabled(featureClawback))
|
||||
{
|
||||
if (sle->isFlag(lsfNoFreeze))
|
||||
if (uSetFlag == asfAllowTrustLineClawback)
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "Can't set Clawback if NoFreeze is set";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
if (sle->isFlag(lsfNoFreeze))
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "Can't set Clawback if NoFreeze is set";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
|
||||
if (!dirIsEmpty(ctx.view, keylet::ownerDir(id)))
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "Owner directory not empty.";
|
||||
return tecOWNERS;
|
||||
if (!dirIsEmpty(ctx.view, keylet::ownerDir(id)))
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "Owner directory not empty.";
|
||||
return tecOWNERS;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (uSetFlag == asfNoFreeze)
|
||||
{
|
||||
// Cannot set NoFreeze if clawback is enabled
|
||||
if (sle->isFlag(lsfAllowTrustLineClawback))
|
||||
else if (uSetFlag == asfNoFreeze)
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "Can't set NoFreeze if clawback is enabled";
|
||||
return tecNO_PERMISSION;
|
||||
// Cannot set NoFreeze if clawback is enabled
|
||||
if (sle->isFlag(lsfAllowTrustLineClawback))
|
||||
{
|
||||
JLOG(ctx.j.trace()) << "Can't set NoFreeze if clawback is enabled";
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +315,7 @@ AccountSet::doApply()
|
||||
return tecNEED_MASTER_KEY;
|
||||
}
|
||||
|
||||
if ((!sle->isFieldPresent(sfRegularKey)) && (!view().peek(keylet::signerList(accountID_))))
|
||||
if ((!sle->isFieldPresent(sfRegularKey)) && (!view().peek(keylet::signers(accountID_))))
|
||||
{
|
||||
// Account has no regular key or multi-signer signer list.
|
||||
return tecNO_ALTERNATIVE_KEY;
|
||||
@@ -573,7 +576,7 @@ AccountSet::doApply()
|
||||
}
|
||||
|
||||
// Set flag for clawback
|
||||
if (uSetFlag == asfAllowTrustLineClawback)
|
||||
if (ctx_.view().rules().enabled(featureClawback) && uSetFlag == asfAllowTrustLineClawback)
|
||||
{
|
||||
JLOG(j_.trace()) << "set allow clawback";
|
||||
uFlagsOut |= lsfAllowTrustLineClawback;
|
||||
|
||||
@@ -67,7 +67,7 @@ SetRegularKey::doApply()
|
||||
else
|
||||
{
|
||||
// Account has disabled master key and no multi-signer signer list.
|
||||
if (sle->isFlag(lsfDisableMaster) && !view().peek(keylet::signerList(accountID_)))
|
||||
if (sle->isFlag(lsfDisableMaster) && !view().peek(keylet::signers(accountID_)))
|
||||
return tecNO_ALTERNATIVE_KEY;
|
||||
|
||||
sle->makeFieldAbsent(sfRegularKey);
|
||||
|
||||
@@ -232,7 +232,7 @@ SignerListSet::removeFromLedger(
|
||||
{
|
||||
auto const accountKeylet = keylet::account(account);
|
||||
auto const ownerDirKeylet = keylet::ownerDir(account);
|
||||
auto const signerListKeylet = keylet::signerList(account);
|
||||
auto const signerListKeylet = keylet::signers(account);
|
||||
|
||||
return removeSignersFromLedger(
|
||||
registry, view, accountKeylet, ownerDirKeylet, signerListKeylet, j);
|
||||
@@ -302,7 +302,7 @@ SignerListSet::replaceSignerList()
|
||||
{
|
||||
auto const accountKeylet = keylet::account(accountID_);
|
||||
auto const ownerDirKeylet = keylet::ownerDir(accountID_);
|
||||
auto const signerListKeylet = keylet::signerList(accountID_);
|
||||
auto const signerListKeylet = keylet::signers(accountID_);
|
||||
|
||||
// This may be either a create or a replace. Preemptively remove any
|
||||
// old signer list. May reduce the reserve, so this is done before
|
||||
@@ -367,7 +367,7 @@ SignerListSet::destroySignerList()
|
||||
return tecNO_ALTERNATIVE_KEY;
|
||||
|
||||
auto const ownerDirKeylet = keylet::ownerDir(accountID_);
|
||||
auto const signerListKeylet = keylet::signerList(accountID_);
|
||||
auto const signerListKeylet = keylet::signers(accountID_);
|
||||
return removeSignersFromLedger(
|
||||
ctx_.registry, view(), accountKeylet, ownerDirKeylet, signerListKeylet, j_);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user