mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-22 11:37:07 +00:00
Compare commits
40
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
025aa71930 | ||
|
|
ef5064eeb9 | ||
|
|
c2e739f670 | ||
|
|
15fac6250d | ||
|
|
3608433514 | ||
|
|
7939339a65 | ||
|
|
4ea2db2eda | ||
|
|
d4ffe32534 | ||
|
|
7354816f65 | ||
|
|
12cb3932f3 | ||
|
|
dc64a8daac | ||
|
|
dc524e9cc6 | ||
|
|
4060b1bcd4 | ||
|
|
bfbb440fc2 | ||
|
|
4087861411 | ||
|
|
dc43faafed | ||
|
|
6af97c07d9 | ||
|
|
4c7d920e66 | ||
|
|
8b59d9d307 | ||
|
|
b0fa295595 | ||
|
|
9af432cb0e | ||
|
|
4435ca4cbf | ||
|
|
cd72a11786 | ||
|
|
b398b88385 | ||
|
|
31f6f90206 | ||
|
|
1d8c2f9172 | ||
|
|
f105418bdb | ||
|
|
4a134eb883 | ||
|
|
ec3f251ad8 | ||
|
|
5faa861226 | ||
|
|
88fd1222d6 | ||
|
|
f1ce9449f2 | ||
|
|
7237b3321c | ||
|
|
84d980d883 | ||
|
|
791c96faad | ||
|
|
31473e7e6d | ||
|
|
aa70b368b5 | ||
|
|
d3db569b34 | ||
|
|
94d6b7daf8 | ||
|
|
e089abe982 |
No files matched your search
+2
-2
@@ -103,6 +103,7 @@ words:
|
||||
- dearmor
|
||||
- decryptor
|
||||
- dedented
|
||||
- dedup
|
||||
- deleteme
|
||||
- demultiplexer
|
||||
- deserializaton
|
||||
@@ -317,7 +318,6 @@ words:
|
||||
- sttx
|
||||
- stvar
|
||||
- stvector
|
||||
- stxchainattestations
|
||||
- summands
|
||||
- superpeer
|
||||
- superpeers
|
||||
@@ -344,6 +344,7 @@ words:
|
||||
- unambiguity
|
||||
- unauthorizes
|
||||
- unauthorizing
|
||||
- undeserializable
|
||||
- unergonomic
|
||||
- unfetched
|
||||
- unfindable
|
||||
@@ -375,7 +376,6 @@ words:
|
||||
- writeme
|
||||
- wsrch
|
||||
- wthread
|
||||
- xbridge
|
||||
- xchain
|
||||
- xcrun
|
||||
- ximinez
|
||||
|
||||
@@ -62,6 +62,7 @@ libxrpl.tx > xrpl.protocol
|
||||
libxrpl.tx > xrpl.server
|
||||
libxrpl.tx > xrpl.tx
|
||||
test.app > test.jtx
|
||||
test.app > tests.libxrpl
|
||||
test.app > test.unit_test
|
||||
test.app > xrpl.basics
|
||||
test.app > xrpl.config
|
||||
|
||||
@@ -8,6 +8,7 @@ on:
|
||||
branches:
|
||||
- "develop"
|
||||
- "release/*"
|
||||
- "staging/*"
|
||||
paths:
|
||||
- "crates/**/Cargo.toml"
|
||||
- "crates/Cargo.lock"
|
||||
|
||||
@@ -243,7 +243,7 @@ jobs:
|
||||
- should-run
|
||||
- build-test
|
||||
# Only run when committing to a PR that targets a release branch.
|
||||
if: ${{ github.repository == 'XRPLF/rippled' && needs.should-run.outputs.go == 'true' && github.event_name == 'pull_request' && startsWith(github.event.pull_request.base.ref, 'release') }}
|
||||
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 }}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
# This workflow runs all workflows to build and test the code on various Linux
|
||||
# flavors, as well as on MacOS and Windows, on a scheduled basis, on merge into
|
||||
# the 'develop' or 'release*' branches, or when requested manually. Upon pushes
|
||||
# to the develop branch it also uploads the libxrpl recipe to the Conan remote.
|
||||
# the 'develop', 'release/*' or 'staging/*' branches, or when requested
|
||||
# manually. Upon pushes to the develop branch, it also uploads the libxrpl
|
||||
# recipe to the Conan remote.
|
||||
name: Trigger
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "release*"
|
||||
- "release/*"
|
||||
- "staging/*"
|
||||
paths:
|
||||
# These paths are unique to `on-trigger.yml`.
|
||||
- ".github/workflows/on-trigger.yml"
|
||||
@@ -62,9 +64,9 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
# When a PR is merged into the develop branch it will be assigned a unique
|
||||
# When a PR is merged into the develop branch, it will be assigned a unique
|
||||
# group identifier, so execution will continue even if another PR is merged
|
||||
# while it is still running. In all other cases the group identifier is shared
|
||||
# while it is still running. In all other cases, the group identifier is shared
|
||||
# per branch, so that any in-progress runs are cancelled when a new commit is
|
||||
# pushed.
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' && github.sha || github.ref }}
|
||||
@@ -98,7 +100,7 @@ jobs:
|
||||
# However, we do not enable ccache for events targeting a release branch,
|
||||
# to protect against the rare case that the output produced by ccache is
|
||||
# not identical to a regular compilation.
|
||||
ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release') }}
|
||||
ccache_enabled: ${{ github.repository_owner == 'XRPLF' && !startsWith(github.ref, 'refs/heads/release/') }}
|
||||
os: ${{ matrix.os }}
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
@@ -8,7 +8,8 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- "develop"
|
||||
- "release*"
|
||||
- "release/*"
|
||||
- "staging/*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -123,13 +123,19 @@ jobs:
|
||||
|
||||
- name: Fix style
|
||||
if: ${{ steps.files_changed.outcome != 'success' }}
|
||||
# pre-commit installs every hook's environment, even for hooks that match
|
||||
# no files, and node-based hooks need libatomic, which this image lacks.
|
||||
# Exit code 1 just means hooks modified files or found issues.
|
||||
env:
|
||||
SKIP: prettier,cspell
|
||||
run: |
|
||||
pre-commit run --all-files || true
|
||||
git add --update
|
||||
pre-commit run || [ $? -eq 1 ]
|
||||
|
||||
- name: Generate git diff
|
||||
if: ${{ steps.files_changed.outcome != 'success' }}
|
||||
run: |
|
||||
git diff | tee "${DIFF_FILE}"
|
||||
git diff HEAD | tee "${DIFF_FILE}"
|
||||
|
||||
- name: Upload clang-tidy diff output
|
||||
if: ${{ github.event.repository.visibility == 'public' && steps.files_changed.outcome != 'success' }}
|
||||
|
||||
@@ -26,6 +26,10 @@ This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-R
|
||||
|
||||
Version 3.5.0 is not yet released.
|
||||
|
||||
### Breaking changes in 3.5.0
|
||||
|
||||
- The `XChainBridge` amendment and its ledger entries and transactions are removed. `XChainBridge` and `fixXChainRewardRounding` are now obsolete and can no longer be voted for; neither was ever enabled on Mainnet. `ledger_entry` no longer accepts `bridge`, `xchain_owned_claim_id`, or `xchain_owned_create_account_claim_id`; `account_objects` no longer accepts those values in `type`; and `server_definitions` no longer lists the removed ledger entry types, transaction types, fields, and the `XChainBridge` serialized type.
|
||||
|
||||
### Additions in 3.5.0
|
||||
|
||||
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive the same `transaction` message as the `transactions` stream for each validated transaction whose metadata affects a subscribed issuance. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
|
||||
@@ -36,6 +40,10 @@ Version 3.5.0 is not yet released.
|
||||
- `channel_authorize`: The `channel_id` field now returns an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
|
||||
- `channel_verify`: The `channel_id` and `signature` fields now return an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
|
||||
- `account_currencies`, `account_nfts`, `account_offers`: A request with more than one problem may now report a different one of them. An invalid `ledger_hash` or `ledger_index` is reported before an invalid or missing `account`. An invalid `limit` or `marker` is reported before `lgrNotFound` or `actNotFound`, and for `account_offers` also before `actMalformed`. A request with a single problem returns the same error as before. [#8561](https://github.com/XRPLF/rippled/pull/8561)
|
||||
- `deposit_authorized`: A `credentials` entry that is all zeros (for example `"0"` or 64 `0` characters) now returns a `badCredentials` error instead of looking up a credential that can never exist.
|
||||
- `account_info`, `account_lines`, `account_channels`: A request with more than one problem may now report a different one of them. An invalid `ledger_hash` or `ledger_index` is reported before a missing or invalid `account`, or `ident` for `account_info`. For `account_lines`, a `peer` that is not a string, or an invalid `limit` or `marker`, is reported before `lgrNotFound`, `actNotFound` or a malformed `account`, and an invalid `limit` or `marker` also before a malformed `peer`. For `account_channels`, a malformed `account` is reported before `lgrNotFound`, and an invalid `destination_account`, `limit` or `marker` before `lgrNotFound` or `actNotFound`. A request with a single problem returns the same error as before. [#8573](https://github.com/XRPLF/rippled/pull/8573)
|
||||
- `deposit_authorized`, `nft_buy_offers`, `nft_sell_offers`: A request with more than one problem may now report a different one of them. An invalid `ledger_hash` or `ledger_index` is reported before a missing or invalid `source_account`, `destination_account` or `nft_id`, and for `nft_buy_offers` / `nft_sell_offers` also before an invalid `limit`. For `deposit_authorized`, an invalid `credentials` array is reported before `lgrNotFound`, `srcActNotFound`, `dstActNotFound` or `badCredentials`. For `nft_buy_offers` and `nft_sell_offers`, an invalid `marker` is reported before `lgrNotFound` or `objectNotFound`. A request with a single problem returns the same error as before. [#8613](https://github.com/XRPLF/rippled/pull/8613)
|
||||
- `nft_buy_offers`, `nft_sell_offers`: An `nft_id` that is an array or an object now returns an `invalidParams` error instead of an `internal` error. [#8613](https://github.com/XRPLF/rippled/pull/8613)
|
||||
|
||||
### Bugfixes in 3.5.0
|
||||
|
||||
|
||||
@@ -2,33 +2,12 @@
|
||||
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| These instructions assume you have a C++ development environment ready with Git, Python, Conan, CMake, and a C++ compiler. For help setting one up on Linux, macOS, or Windows, [see this guide](./docs/build/environment.md).<br><br>These instructions also assume a basic familiarity with Conan and CMake. If you are unfamiliar with Conan, you can read our [crash course](./docs/build/conan.md) or the official [Getting Started][conan-getting-started] walkthrough. |
|
||||
|
||||
## Minimum Requirements
|
||||
## Supported platforms
|
||||
|
||||
For the hardware needed to run a node, see
|
||||
[System Requirements](https://xrpl.org/system-requirements.html).
|
||||
|
||||
For the software needed to build xrpld, see the
|
||||
[environment setup guide](./docs/build/environment.md).
|
||||
|
||||
## Operating Systems
|
||||
|
||||
### Linux
|
||||
|
||||
The Ubuntu Linux distribution has received the highest level of quality
|
||||
assurance, testing, and support. We also support Red Hat and use Debian
|
||||
internally.
|
||||
Our Linux CI tooling is distro-independent and uses a Nix-based environment, so it should be possible to build on other Linux distributions as well, although we have not tested them.
|
||||
|
||||
### macOS
|
||||
|
||||
Many `xrpld` engineers use macOS for development.
|
||||
The minimum supported version is macOS 15 (Sequoia).
|
||||
CI testing is done in macOS 26 (Tahoe), but the build defaults `CMAKE_OSX_DEPLOYMENT_TARGET` to 15.
|
||||
|
||||
### Windows
|
||||
|
||||
Windows is used by some engineers for development only, and is not recommended
|
||||
for production use.
|
||||
Building and testing are supported on Linux, macOS, and (best effort) Windows;
|
||||
see [Supported development platforms](./docs/build/environment.md#supported-development-platforms).
|
||||
Running `xrpld` is officially supported on Linux only;
|
||||
see [Requirements](./docs/install.md#requirements).
|
||||
|
||||
## Steps
|
||||
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ if(is_gcc)
|
||||
# GCC-specific fixes
|
||||
add_compile_options(-Wno-unknown-pragmas -Wno-subobject-linkage)
|
||||
# -Wno-subobject-linkage can be removed when we upgrade GCC version to at least 13.3
|
||||
elseif(is_clang)
|
||||
elseif(is_any_clang)
|
||||
# Clang-specific fixes
|
||||
add_compile_options(-Wno-unknown-warning-option) # Ignore unknown warning options
|
||||
elseif(is_msvc)
|
||||
|
||||
+1
-1
@@ -332,7 +332,7 @@ This ensures that configuration changes don't introduce new warnings across the
|
||||
|
||||
### Installing clang-tidy
|
||||
|
||||
See the [environment setup guide](./docs/build/environment.md#clang-tidy) for how to get clang-tidy.
|
||||
The [Nix development shell](./docs/build/nix.md) provides `clang-tidy` at the [tested version](./docs/build/environment.md#tested-compiler-versions).
|
||||
|
||||
### Running clang-tidy locally
|
||||
|
||||
|
||||
@@ -1360,6 +1360,39 @@
|
||||
# Example:
|
||||
# owner_reserve = 200000 # 0.2 XRP
|
||||
#
|
||||
# gas_limit = <gas>
|
||||
#
|
||||
# The gas limit is the maximum amount of gas that can be
|
||||
# consumed by a single transaction. The gas limit is used to prevent
|
||||
# transactions from consuming too many resources.
|
||||
#
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# gas_limit = 1000000 # 1 million gas
|
||||
#
|
||||
# bytecode_size_limit = <bytes>
|
||||
#
|
||||
# The bytecode size limit is the maximum size of a WASM extension in
|
||||
# bytes. The size limit is used to prevent extensions from consuming
|
||||
# too many resources.
|
||||
#
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# bytecode_size_limit = 100000 # 100 kb
|
||||
#
|
||||
# gas_price = <micro-drops>
|
||||
#
|
||||
# The gas price is the conversion between WASM gas and its price in drops.
|
||||
#
|
||||
# If this parameter is unspecified, xrpld will use an internal
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# gas_price = 1000000 # 1 drop per gas
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 9. Misc Settings
|
||||
|
||||
@@ -9,13 +9,21 @@ include_guard(GLOBAL)
|
||||
# --------------------------------------------------------------------
|
||||
# Compiler detection (C++)
|
||||
# --------------------------------------------------------------------
|
||||
set(is_clang FALSE)
|
||||
# is_any_clang is true for both LLVM Clang and AppleClang. Their version numbers
|
||||
# and feature sets differ, so use is_llvm_clang or is_apple_clang when it matters.
|
||||
set(is_any_clang FALSE)
|
||||
set(is_llvm_clang FALSE)
|
||||
set(is_apple_clang FALSE)
|
||||
set(is_gcc FALSE)
|
||||
set(is_msvc FALSE)
|
||||
set(is_xcode FALSE)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") # Clang or AppleClang
|
||||
set(is_clang TRUE)
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(is_any_clang TRUE)
|
||||
set(is_llvm_clang TRUE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(is_any_clang TRUE)
|
||||
set(is_apple_clang TRUE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(is_gcc TRUE)
|
||||
elseif(MSVC)
|
||||
|
||||
@@ -130,7 +130,7 @@ else()
|
||||
INTERFACE
|
||||
-Wall
|
||||
-Wdeprecated
|
||||
$<$<BOOL:${is_clang}>:-Wno-deprecated-declarations>
|
||||
$<$<BOOL:${is_any_clang}>:-Wno-deprecated-declarations>
|
||||
$<$<BOOL:${wextra}>:-Wextra
|
||||
-Wno-unused-parameter>
|
||||
$<$<BOOL:${werr}>:-Werror>
|
||||
@@ -177,7 +177,7 @@ else()
|
||||
if(
|
||||
is_nix_compiler
|
||||
AND is_linux
|
||||
AND is_clang
|
||||
AND is_any_clang
|
||||
AND CMAKE_CXX_FLAGS MATCHES "stdlib=libstdc"
|
||||
)
|
||||
string(
|
||||
@@ -204,7 +204,10 @@ if(voidstar)
|
||||
"Antithesis instrumentation requires Linux, aborting..."
|
||||
)
|
||||
elseif(
|
||||
NOT (is_clang AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
|
||||
NOT (
|
||||
is_llvm_clang
|
||||
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0
|
||||
)
|
||||
)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
|
||||
@@ -297,11 +297,16 @@ if(xrpld)
|
||||
VALUE_TYPE "::json::Value"
|
||||
VIEW_HEADER "xrpld/rpc/detail/JsonObjectView.hpp"
|
||||
HANDLERS
|
||||
account_channels
|
||||
account_currencies
|
||||
account_info
|
||||
account_lines
|
||||
account_nfts
|
||||
account_offers
|
||||
book_changes
|
||||
deposit_authorized
|
||||
ledger
|
||||
nft_offers_common
|
||||
transaction_entry
|
||||
)
|
||||
target_sources(xrpld PRIVATE ${rpcspec_instantiations})
|
||||
|
||||
@@ -58,7 +58,7 @@ target_link_options(common INTERFACE ${sanitizers_linker_flags})
|
||||
# This module appends -fsanitize-ignorelist=<path> for Clang builds.
|
||||
# The ignorelist path contains CMAKE_SOURCE_DIR, so it must be set here, rather than in the Conan profile.
|
||||
# GCC does not support -fsanitize-ignorelist.
|
||||
if(is_clang)
|
||||
if(is_any_clang)
|
||||
set(ignorelist_path
|
||||
"${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt"
|
||||
)
|
||||
|
||||
@@ -23,11 +23,8 @@ if(NOT is_multiconfig)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(is_clang) # both Clang and AppleClang
|
||||
if(
|
||||
"${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang"
|
||||
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0
|
||||
)
|
||||
if(is_llvm_clang)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16.0)
|
||||
message(FATAL_ERROR "This project requires clang 16 or later")
|
||||
endif()
|
||||
elseif(is_gcc)
|
||||
|
||||
@@ -62,11 +62,11 @@ if(unity)
|
||||
set(CMAKE_UNITY_BUILD ON CACHE BOOL "Do a unity build")
|
||||
endif()
|
||||
|
||||
if(is_clang AND is_linux)
|
||||
if(is_llvm_clang AND is_linux)
|
||||
option(voidstar "Enable Antithesis instrumentation." OFF)
|
||||
endif()
|
||||
|
||||
if(is_gcc OR is_clang)
|
||||
if(is_gcc OR is_any_clang)
|
||||
include(ProcessorCount)
|
||||
ProcessorCount(PROCESSOR_COUNT)
|
||||
|
||||
@@ -125,7 +125,7 @@ else()
|
||||
set(use_mold OFF CACHE BOOL "mold linker, linux only" FORCE)
|
||||
endif()
|
||||
|
||||
if(is_clang)
|
||||
if(is_any_clang)
|
||||
option(use_lld "enables detection of lld linker" ON)
|
||||
else()
|
||||
set(use_lld OFF CACHE BOOL "try lld linker, clang only" FORCE)
|
||||
|
||||
+2
-2
@@ -3,11 +3,11 @@
|
||||
"requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
|
||||
"xrpl-rpc-spec/0.1.23#56e8946f5b3fb949a3732e1a51135ca2%1790977482.197086",
|
||||
"xrpl-rpc-spec/0.1.29#852afc87cac32aca93cc50a985d73fe0%1792359643.19817",
|
||||
"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",
|
||||
"secp256k1/0.7.1#f4d16a4d907dd057598954476ca6f88c%1792234329.790275",
|
||||
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1782392413.075713",
|
||||
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1782392402.431897",
|
||||
"protobuf/6.33.5#ff253ead763bd8d9904a52979cd21e81%1782392410.233933",
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ class Xrpl(ConanFile):
|
||||
"nudb/2.0.9",
|
||||
"openssl/3.6.3",
|
||||
"soci/4.0.3",
|
||||
"xrpl-rpc-spec/0.1.23",
|
||||
"xrpl-rpc-spec/0.1.29",
|
||||
"zlib/1.3.2",
|
||||
]
|
||||
|
||||
|
||||
Vendored
+32
-77
@@ -4,6 +4,18 @@ This document explains how to set one up.
|
||||
|
||||
[BUILD.md]: ../../BUILD.md
|
||||
|
||||
## Supported development platforms
|
||||
|
||||
- **Linux**: the [Nix development shell](./nix.md),
|
||||
which provides the same toolchain CI uses on any distribution.
|
||||
- **macOS** 15 (Sequoia) or newer: the [Nix development shell](./nix.md),
|
||||
or the system [Apple Clang](#macos-apple-clang).
|
||||
CI runs on macOS 26 (Tahoe), but the build defaults `CMAKE_OSX_DEPLOYMENT_TARGET` to 15.
|
||||
- **Windows**: best effort, see [Windows](#windows).
|
||||
|
||||
For the platforms supported for running `xrpld`,
|
||||
see [Requirements](../install.md#requirements).
|
||||
|
||||
## Tested compiler versions
|
||||
|
||||
`xrpld` is built in the **C++23** dialect by default, so your toolchain has to
|
||||
@@ -35,20 +47,16 @@ compiler building. Treat support for anything outside the table as best-effort.
|
||||
|
||||
## Required tools
|
||||
|
||||
Besides a compiler, building `xrpld` requires:
|
||||
|
||||
| Tool | Minimum version |
|
||||
| ------------------------------------------- | --------------- |
|
||||
| [Git](https://git-scm.com/downloads) | any recent |
|
||||
| [Python](https://www.python.org/downloads/) | 3.11 |
|
||||
| [Conan](https://conan.io/downloads.html) | 2.17 |
|
||||
| [CMake](https://cmake.org/download/) | 3.16 |
|
||||
Besides a compiler, building `xrpld` requires
|
||||
[Git](https://git-scm.com/downloads),
|
||||
[Python](https://www.python.org/downloads/),
|
||||
[Conan](https://conan.io/downloads.html),
|
||||
and [CMake](https://cmake.org/download/).
|
||||
Building with `-Drust=ON` additionally requires a Rust toolchain,
|
||||
see [Rust](#rust).
|
||||
|
||||
On Linux and macOS, the [Nix development shell](./nix.md) provides all of them
|
||||
(see below). On Windows they have to be installed manually.
|
||||
|
||||
Building with `-Drust=ON` additionally requires a Rust toolchain, see
|
||||
[Rust](#rust). A default build does not, so it is not in the table above.
|
||||
at the versions CI uses, recorded in [`nix/check-tools/`](../../nix/check-tools).
|
||||
|
||||
Once they are in place, verify that everything is installed and runnable with:
|
||||
|
||||
@@ -58,60 +66,19 @@ Once they are in place, verify that everything is installed and runnable with:
|
||||
|
||||
## Linux and macOS
|
||||
|
||||
The **recommended way** to get a development environment on Linux and macOS is
|
||||
the Nix development shell. It provides the exact tooling used in CI — `git`,
|
||||
`python`, `conan`, `cmake`, `clang-tidy`, `clang-format`, and everything else —
|
||||
with a single command and without installing anything system-wide:
|
||||
Use the [Nix development shell](./nix.md):
|
||||
it provides the compiler and every tool CI uses,
|
||||
without installing anything system-wide.
|
||||
|
||||
```bash
|
||||
nix --experimental-features 'nix-command flakes' develop
|
||||
```
|
||||
### macOS: Apple Clang
|
||||
|
||||
On **Linux**, Nix also provides the compiler (GCC); on **macOS**, it provides
|
||||
Clang. If you instead opt to use your system-wide Apple Clang (via
|
||||
`nix develop .#apple-clang`), you need to manage its version yourself (see
|
||||
below).
|
||||
|
||||
See [Using the Nix development shell](./nix.md) for installation and usage
|
||||
details, including how to select a different compiler and why we recommend Nix
|
||||
over a hand-maintained environment.
|
||||
|
||||
### macOS: managing the Apple Clang version
|
||||
|
||||
If you use your system-wide Apple Clang on macOS (via `nix develop .#apple-clang`),
|
||||
the compiler version is whatever your installed Xcode (or Command Line Tools)
|
||||
provides. The following command should return a version greater than or equal to
|
||||
the [tested one](#tested-compiler-versions):
|
||||
|
||||
```bash
|
||||
clang --version
|
||||
```
|
||||
|
||||
If you develop other applications using Xcode, you might be consistently
|
||||
updating to the newest version of Apple Clang, which will likely cause issues
|
||||
building xrpld. You may want to install and pin a specific version of Xcode:
|
||||
|
||||
1. **Download Xcode**
|
||||
- Visit [Apple Developer Downloads](https://developer.apple.com/download/more/)
|
||||
- Sign in with your Apple Developer account
|
||||
- Search for an Xcode version that includes the expected Apple Clang version
|
||||
- Download the `.xip` file
|
||||
|
||||
2. **Install and configure Xcode**
|
||||
|
||||
```bash
|
||||
# Extract the .xip file and rename for version management
|
||||
# Example: Xcode_16.2.app
|
||||
|
||||
# Move to Applications directory
|
||||
sudo mv Xcode_16.2.app /Applications/
|
||||
|
||||
# Set as default toolchain (persistent)
|
||||
sudo xcode-select -s /Applications/Xcode_16.2.app/Contents/Developer
|
||||
|
||||
# Set as environment variable (temporary)
|
||||
export DEVELOPER_DIR=/Applications/Xcode_16.2.app/Contents/Developer
|
||||
```
|
||||
You can also build with the system Apple Clang,
|
||||
installing the other [required tools](#required-tools) any way you like
|
||||
(or getting them from `nix develop .#apple-clang`).
|
||||
Its version is whatever your installed Xcode (or Command Line Tools) provides,
|
||||
so check that `clang --version` is at least the [tested one](#tested-compiler-versions).
|
||||
If several Xcode versions are installed,
|
||||
select one with `sudo xcode-select -s <path>` or the `DEVELOPER_DIR` environment variable.
|
||||
|
||||
## Windows
|
||||
|
||||
@@ -123,8 +90,7 @@ manually:
|
||||
"x64 Native Tools Command Prompt". CI configures CMake with the
|
||||
`Visual Studio 18 2026` generator.
|
||||
- [Git for Windows](https://git-scm.com/download/win)
|
||||
- Python, Conan, and CMake, at the versions listed in
|
||||
[Required tools](#required-tools).
|
||||
- recent releases of Python, Conan, and CMake
|
||||
- a [Rust toolchain](https://rustup.rs) — only needed to build with
|
||||
`-Drust=ON`, see [Rust](#rust)
|
||||
|
||||
@@ -145,16 +111,5 @@ version.
|
||||
Everything else the Rust build needs on the CMake side comes from Conan along
|
||||
with the rest of the dependencies, so there is nothing further to install.
|
||||
|
||||
## Clang-tidy
|
||||
|
||||
`clang-tidy` is required to run static analysis checks locally (see
|
||||
[CONTRIBUTING.md](../../CONTRIBUTING.md)). It is not required to build the
|
||||
project. The version this project uses is listed in
|
||||
[Tested compiler versions](#tested-compiler-versions).
|
||||
|
||||
On Linux and macOS, the [Nix development shell](./nix.md) provides that exact
|
||||
version out of the box — run it via `run-clang-tidy`. No separate installation
|
||||
is needed.
|
||||
|
||||
[cpp23-support]: https://en.cppreference.com/w/cpp/compiler_support/23
|
||||
[packages.nix]: ../../nix/packages.nix
|
||||
Vendored
+2
-9
@@ -9,9 +9,7 @@ This guide explains how to use Nix to set up a reproducible development environm
|
||||
- **Reproducible environment**: Everyone gets the same versions of tools and compilers
|
||||
- **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment, and CI builds some macOS configurations in it as well
|
||||
- **No system pollution**: Dependencies are isolated and don't affect your system packages
|
||||
- **Consistent compilers**: The GCC and Clang shells use the same versions as CI
|
||||
- **Quick setup**: Get started with a single command
|
||||
- **Works on Linux and macOS**: Consistent experience across platforms
|
||||
|
||||
## Install Nix
|
||||
|
||||
@@ -27,13 +25,8 @@ From the root of the xrpld repository, enter the default development shell:
|
||||
nix --experimental-features 'nix-command flakes' develop
|
||||
```
|
||||
|
||||
This will:
|
||||
|
||||
- Download and set up all required development tools (CMake, Ninja, Conan, etc.)
|
||||
- Configure the appropriate compiler for your platform:
|
||||
- **Linux**: GCC (provided by Nix)
|
||||
- **macOS**: Clang (provided by Nix)
|
||||
|
||||
This downloads and sets up all required development tools (CMake, Ninja, Conan, etc.)
|
||||
and the compiler for your platform (see [Platform notes](#platform-notes)).
|
||||
The first time you run this command, it will take a few minutes to download and build the environment. Subsequent runs will be much faster.
|
||||
|
||||
### Platform notes
|
||||
|
||||
@@ -10,6 +10,19 @@ and DNF on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux,
|
||||
where `yum` is a symlink to `dnf`.
|
||||
To build from source instead, see [BUILD.md](../BUILD.md).
|
||||
|
||||
## Requirements
|
||||
|
||||
Linux is the only operating system officially supported for running `xrpld`;
|
||||
macOS and Windows builds are for development only.
|
||||
|
||||
Any x86-64 Linux distribution with APT or DNF and glibc 2.31 or newer should work
|
||||
(see [How libc is handled](../nix/docker/README.md#how-libc-is-handled)).
|
||||
CI tests the packages on Debian 11–13, Ubuntu 20.04–26.04,
|
||||
RHEL (UBI) 9–10, AlmaLinux 9–10, and Rocky Linux 9–10.
|
||||
|
||||
For the hardware needed to run a node,
|
||||
see [System Requirements](https://xrpl.org/system-requirements.html).
|
||||
|
||||
## Release channels
|
||||
|
||||
Packages are published to four channels:
|
||||
|
||||
@@ -352,9 +352,9 @@ class Number final
|
||||
using rep = std::int64_t;
|
||||
using InternalRep = MantissaRange::rep;
|
||||
|
||||
bool negative_{false};
|
||||
InternalRep mantissa_{0};
|
||||
int exponent_{std::numeric_limits<int>::lowest()};
|
||||
bool negative_{false};
|
||||
|
||||
public:
|
||||
// The range for the exponent when normalized
|
||||
@@ -650,8 +650,12 @@ private:
|
||||
shiftExponent(int exponentDelta) const;
|
||||
};
|
||||
|
||||
// The number class currently has 3 tail padding bytes. If you are adding new
|
||||
// members, try to fit them there before expanding the size of the class.
|
||||
static_assert(sizeof(Number) == 16);
|
||||
|
||||
constexpr Number::Number(bool negative, InternalRep mantissa, int exponent, Unchecked) noexcept
|
||||
: negative_(negative), mantissa_{mantissa}, exponent_{exponent}
|
||||
: mantissa_{mantissa}, exponent_{exponent}, negative_(negative)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ struct Keys
|
||||
static constexpr auto kBbtOptions = "bbt_options";
|
||||
static constexpr auto kBgThreads = "bg_threads";
|
||||
static constexpr auto kBlockSize = "block_size";
|
||||
static constexpr auto kBytecodeSizeLimit = "bytecode_size_limit";
|
||||
static constexpr auto kCacheAge = "cache_age";
|
||||
static constexpr auto kCacheMb = "cache_mb";
|
||||
static constexpr auto kCacheSize = "cache_size";
|
||||
@@ -108,6 +109,8 @@ struct Keys
|
||||
static constexpr auto kFileSizeMult = "file_size_mult";
|
||||
static constexpr auto kFilterBits = "filter_bits";
|
||||
static constexpr auto kFilterFull = "filter_full";
|
||||
static constexpr auto kGasLimit = "gas_limit";
|
||||
static constexpr auto kGasPrice = "gas_price";
|
||||
static constexpr auto kHardSet = "hard_set";
|
||||
static constexpr auto kHighThreads = "high_threads";
|
||||
static constexpr auto kHoldTime = "hold_time";
|
||||
|
||||
@@ -257,13 +257,42 @@ public:
|
||||
header_.validated = true;
|
||||
}
|
||||
|
||||
void
|
||||
/**
|
||||
* Mark this ledger as accepted and attempt to make it immutable.
|
||||
*
|
||||
* The close-time fields are recorded first, since the ledger hash covers
|
||||
* them.
|
||||
*
|
||||
* @param closeTime The consensus-agreed close time.
|
||||
* @param closeResolution The close time resolution.
|
||||
* @param correctCloseTime Whether consensus agreed on the close time. If
|
||||
* false, kSLcfNoConsensusTime is recorded in closeFlags instead.
|
||||
* @return What setImmutable() returned.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
setAccepted(
|
||||
NetClock::time_point closeTime,
|
||||
NetClock::duration closeResolution,
|
||||
bool correctCloseTime);
|
||||
|
||||
void
|
||||
/**
|
||||
* Mark this ledger as immutable, so it can no longer be modified.
|
||||
*
|
||||
* A ledger built or loaded locally cannot have an invalid map, since only
|
||||
* a map syncing against hashes from outside can be proven impossible (see
|
||||
* SHAMap::addKnownNode), so a caller on such a path may treat a false
|
||||
* return as a broken internal invariant. A caller assembling a ledger from
|
||||
* peer data may not: for it, false is an outcome a peer can produce.
|
||||
*
|
||||
* @param rehash Whether to recompute the ledger hash from the header
|
||||
* fields. The transaction and account hashes are recomputed from the
|
||||
* maps too, but only the first time.
|
||||
* @return false if either map is Invalid, leaving the immutable flag as it
|
||||
* was and the header untouched. A map invalidated partway through can
|
||||
* still leave the other one immutable, so a false return means the
|
||||
* ledger must be discarded rather than retried.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
setImmutable(bool rehash = true);
|
||||
|
||||
bool
|
||||
@@ -272,23 +301,28 @@ public:
|
||||
return immutable_;
|
||||
}
|
||||
|
||||
/* Mark this ledger as "should be full".
|
||||
/**
|
||||
* @return Whether both maps can still be the maps the header names. See
|
||||
* SHAMap::isValid().
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
mapsValid() const
|
||||
{
|
||||
return txMap_.isValid() && stateMap_.isValid();
|
||||
}
|
||||
|
||||
"Full" is metadata property of the ledger, it indicates
|
||||
that the local server wants all the corresponding nodes
|
||||
in durable storage.
|
||||
|
||||
This is marked `const` because it reflects metadata
|
||||
and not data that is in common with other nodes on the
|
||||
network.
|
||||
*/
|
||||
/**
|
||||
* Mark this ledger as "should be full", indicating that the local server
|
||||
* wants all the corresponding nodes in durable storage.
|
||||
*
|
||||
* Const because it reflects metadata, not data this ledger shares with
|
||||
* other nodes on the network.
|
||||
*/
|
||||
void
|
||||
setFull() const
|
||||
{
|
||||
txMap_.setFull();
|
||||
txMap_.setLedgerSeq(header_.seq);
|
||||
stateMap_.setFull();
|
||||
stateMap_.setLedgerSeq(header_.seq);
|
||||
txMap_.setFull(header_.seq);
|
||||
stateMap_.setFull(header_.seq);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -418,6 +452,22 @@ private:
|
||||
static std::pair<std::shared_ptr<STTx const>, std::shared_ptr<STObject const>>
|
||||
deserializeTxPlusMeta(SHAMapItem const& item);
|
||||
|
||||
/**
|
||||
* Make both maps immutable.
|
||||
*
|
||||
* Each map is settled on its own, so neither is left mid-sync because the
|
||||
* other refused.
|
||||
*
|
||||
* @return Whether both maps are immutable.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
setMapsImmutable()
|
||||
{
|
||||
bool const txImmutable = txMap_.setImmutable();
|
||||
bool const stateImmutable = stateMap_.setImmutable();
|
||||
return txImmutable && stateImmutable;
|
||||
}
|
||||
|
||||
bool immutable_;
|
||||
|
||||
// A SHAMap containing the transactions associated with this ledger.
|
||||
|
||||
@@ -265,6 +265,13 @@ canWithdraw(
|
||||
[[nodiscard]] TER
|
||||
canWithdraw(ReadView const& view, STTx const& tx);
|
||||
|
||||
/**
|
||||
* Pays out a withdrawal from a vault or loan broker pseudo-account.
|
||||
*
|
||||
* `sourceAmount` leaves `sourceAcct` and `destinationAmount` reaches `dstAcct`.
|
||||
* The two differ only when the withdrawal carries a transfer fee; the
|
||||
* difference is the fee and is settled through the issuer.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
doWithdraw(
|
||||
ApplyViewContext ctx,
|
||||
@@ -272,7 +279,8 @@ doWithdraw(
|
||||
AccountID const& dstAcct,
|
||||
AccountID const& sourceAcct,
|
||||
XRPAmount priorBalance,
|
||||
STAmount const& amount,
|
||||
STAmount const& destinationAmount,
|
||||
STAmount const& sourceAmount,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <typename ViewT>
|
||||
class BridgeEntry : public SLEBase<ViewT, ltBRIDGE>
|
||||
{
|
||||
public:
|
||||
using Base = SLEBase<ViewT, ltBRIDGE>;
|
||||
|
||||
// Inherit base constructors: adopt an existing SLE, or resolve one from a
|
||||
// Keylet against the view.
|
||||
using Base::Base;
|
||||
|
||||
explicit BridgeEntry(
|
||||
STXChainBridge const& bridge,
|
||||
STXChainBridge::ChainType chainType,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::bridge(bridge, chainType), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using BridgeEntryR = BridgeEntry<ReadView>;
|
||||
using BridgeEntryW = BridgeEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <typename ViewT>
|
||||
class XChainOwnedClaimIDEntry : public SLEBase<ViewT, ltXCHAIN_OWNED_CLAIM_ID>
|
||||
{
|
||||
public:
|
||||
using Base = SLEBase<ViewT, ltXCHAIN_OWNED_CLAIM_ID>;
|
||||
|
||||
// Inherit base constructors: adopt an existing SLE, or resolve one from a
|
||||
// Keylet against the view.
|
||||
using Base::Base;
|
||||
|
||||
explicit XChainOwnedClaimIDEntry(
|
||||
STXChainBridge const& bridge,
|
||||
std::uint64_t seq,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::xChainClaimID(bridge, seq), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using XChainOwnedClaimIDEntryR = XChainOwnedClaimIDEntry<ReadView>;
|
||||
using XChainOwnedClaimIDEntryW = XChainOwnedClaimIDEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/SLEBase.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <typename ViewT>
|
||||
class XChainOwnedCreateAccountClaimIDEntry
|
||||
: public SLEBase<ViewT, ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID>
|
||||
{
|
||||
public:
|
||||
using Base = SLEBase<ViewT, ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID>;
|
||||
|
||||
// Inherit base constructors: adopt an existing SLE, or resolve one from a
|
||||
// Keylet against the view.
|
||||
using Base::Base;
|
||||
|
||||
explicit XChainOwnedCreateAccountClaimIDEntry(
|
||||
STXChainBridge const& bridge,
|
||||
std::uint64_t seq,
|
||||
Base::ViewRefType view,
|
||||
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
|
||||
: Base(keylet::xChainCreateAccountClaimID(bridge, seq), view, j)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using XChainOwnedCreateAccountClaimIDEntryR = XChainOwnedCreateAccountClaimIDEntry<ReadView>;
|
||||
using XChainOwnedCreateAccountClaimIDEntryW = XChainOwnedCreateAccountClaimIDEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Concepts.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Fees.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
@@ -27,6 +28,8 @@
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
/**
|
||||
@@ -560,4 +563,54 @@ escrowUnlockApplyHelper<MPTIssue>(
|
||||
journal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smart escrow kill switches, driven by the voted FeeSettings.
|
||||
*
|
||||
* Zeroing `bytecodeSizeLimit` stops new uploads while leaving existing escrows
|
||||
* finishable without forcing holders to wait for `CancelAfter`.
|
||||
* Zeroing `gasLimit` stops both.
|
||||
*/
|
||||
/** @{ */
|
||||
inline bool
|
||||
isBytecodeUploadDisabled(Fees const& fees)
|
||||
{
|
||||
return fees.bytecodeSizeLimit == 0 || fees.gasLimit == 0;
|
||||
}
|
||||
|
||||
inline bool
|
||||
isBytecodeExecutionDisabled(Fees const& fees)
|
||||
{
|
||||
return fees.gasLimit == 0;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* Owner count an escrow costs.
|
||||
*
|
||||
* An escrow costs one increment per started 500 bytes of bytecode, and one
|
||||
* increment if it carries no bytecode.
|
||||
*/
|
||||
template <class T>
|
||||
int32_t
|
||||
calculateAdditionalReserve(T const& finishFunction)
|
||||
{
|
||||
static auto constexpr kBytecodeReserveIncrement = 500;
|
||||
|
||||
if (!finishFunction)
|
||||
return 1;
|
||||
|
||||
auto const size = finishFunction->size();
|
||||
if (size == 0)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
// Empty Bytecode is refused at create, so no escrow carries it. Ceiling
|
||||
// division would answer 0, which would subtract less than the create added.
|
||||
UNREACHABLE("xrpl::calculateAdditionalReserve : empty Bytecode");
|
||||
return 1;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return static_cast<int32_t>((size + kBytecodeReserveIncrement - 1) / kBytecodeReserveIncrement);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -7,10 +7,10 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/VaultHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
@@ -31,9 +31,9 @@ namespace xrpl {
|
||||
/**
|
||||
* Broker cover preclaim precision guard (fixCleanup3_2_0).
|
||||
*
|
||||
* Prevents a "silent sub-ULP no-op" where a deposit, withdrawal, or clawback
|
||||
* amount is so small that it rounds to zero at `sfCoverAvailable`'s scale.
|
||||
* Without this guard, both the pseudo trust-line and `sfCoverAvailable` would
|
||||
* Prevents a silent sub-ULP no-op where a deposit, withdrawal, or clawback
|
||||
* amount is so small that it rounds to zero at sfCoverAvailable's scale.
|
||||
* Without this guard, both the pseudo trust-line and sfCoverAvailable would
|
||||
* identically absorb the rounded zero, resulting in a successful transaction
|
||||
* (tesSUCCESS) where no funds actually moved.
|
||||
*
|
||||
@@ -44,8 +44,8 @@ namespace xrpl {
|
||||
* @param j Journal for logging.
|
||||
* @param logPrefix Transactor name for log diagnostics.
|
||||
*
|
||||
* @return `tecPRECISION_LOSS` if the request rounds to zero at cover scale.
|
||||
* `tesSUCCESS` if the amendment is disabled or the request is safely supra-ULP.
|
||||
* @return tecPRECISION_LOSS if the request rounds to zero at cover scale.
|
||||
* tesSUCCESS if the amendment is disabled or the request is safely supra-ULP.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
canApplyToBrokerCover(
|
||||
@@ -56,6 +56,82 @@ canApplyToBrokerCover(
|
||||
beast::Journal j,
|
||||
std::string_view logPrefix);
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Return a LoanBroker's posterior live cover exponent after applying an
|
||||
* unrounded delta.
|
||||
*/
|
||||
[[nodiscard]] int
|
||||
getPosteriorBrokerCoverScale(SLE::ConstRef vault, SLE::ConstRef broker, Number const& delta);
|
||||
|
||||
/**
|
||||
* Round a cover outflow delta (cover withdraw, cover clawback, the
|
||||
* broker-side decrease of a default's cover credit) at the LoanBroker's
|
||||
* posterior live exponent. Safe to round the delta directly for an outflow:
|
||||
* amount on the posterior grid of CoverAvailable always leaves CoverAvailable
|
||||
* minus amount representable, since the posterior grid is exactly the grid
|
||||
* CoverAvailable itself will canonicalize to after the subtraction.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
roundToPosteriorBrokerCoverScale(
|
||||
SLE::ConstRef vault,
|
||||
SLE::ConstRef broker,
|
||||
STAmount const& delta,
|
||||
Number::RoundingMode roundingMode);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* Round a cover debit (cover withdraw, cover clawback, the broker-side
|
||||
* decrease of a default's cover credit): amount is the non-negative
|
||||
* magnitude leaving CoverAvailable. Negates so the posterior is computed for
|
||||
* CoverAvailable minus amount, then negates the result back to a
|
||||
* non-negative magnitude, per roundToPosteriorBrokerCoverScale's outflow
|
||||
* rationale above. Magnitude in, magnitude out -- unlike the vault-side
|
||||
* outflow dispatcher (clampVaultOutflow), which takes and returns a negative
|
||||
* delta; callers on each side already hold the value in that side's native
|
||||
* form.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
debitToPosteriorBrokerCoverScale(
|
||||
SLE::ConstRef vault,
|
||||
SLE::ConstRef broker,
|
||||
STAmount const& amount,
|
||||
Number::RoundingMode roundingMode);
|
||||
|
||||
/**
|
||||
* Round a cover inflow (cover deposit, LoanPay's fee redirect into cover)
|
||||
* into CoverAvailable by flooring the sum rather than the delta:
|
||||
* credit = floor16(CoverAvailable + raw) - CoverAvailable, never finer
|
||||
* than the Vault's base exponent (-Scale). See
|
||||
* creditToPosteriorAvailableScale's doc for why the sum, not the delta,
|
||||
* must be floored; the same reasoning applies to CoverAvailable.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
creditToPosteriorBrokerCoverScale(
|
||||
SLE::ConstRef vault,
|
||||
SLE::ConstRef broker,
|
||||
Number const& raw,
|
||||
Number::RoundingMode roundingMode);
|
||||
|
||||
/**
|
||||
* Check whether amount is an admissible optional cover inflow.
|
||||
*
|
||||
* Legacy and CashBasis Vaults always succeed. A LoanBroker attached to a
|
||||
* FixedPrecision Vault must remain at the Vault's base scale after applying
|
||||
* the rounded amount, and its posterior CoverAvailable must stay within the
|
||||
* Open zone.
|
||||
*
|
||||
* LoanPay's fee redirect into cover is a mandatory inflow and does not call
|
||||
* this check, so it can push CoverAvailable past the Open zone limit this
|
||||
* check enforces. Once that happens, every subsequent LoanBrokerCoverDeposit
|
||||
* returns tecLIMIT_EXCEEDED until the owner withdraws cover back under the
|
||||
* limit; LoanBrokerCoverWithdraw and LoanBrokerCoverClawback are unaffected.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkOptionalBrokerCoverInflow(SLE::ConstRef vault, SLE::ConstRef broker, STAmount const& amount);
|
||||
|
||||
// Lending protocol has dependencies, so capture them here.
|
||||
bool
|
||||
checkLendingProtocolDependencies(Rules const& rules, STTx const& tx);
|
||||
@@ -64,13 +140,13 @@ checkLendingProtocolDependencies(Rules const& rules, STTx const& tx);
|
||||
* The accounts and asset that LoanManage::defaultLoan's fixCleanup3_4_0
|
||||
* freeze/lock exemption applies to.
|
||||
*
|
||||
* `defaultLoan` moves funds from the LoanBroker pseudo-account to the Vault
|
||||
* pseudo-account via `accountSend`. Since neither is the vault asset's
|
||||
* defaultLoan moves funds from the LoanBroker pseudo-account to the Vault
|
||||
* pseudo-account via accountSend. Since neither is the vault asset's
|
||||
* issuer, this is a third-party transfer that transits through the issuer in
|
||||
* two hops (broker -> issuer, issuer -> vault; see
|
||||
* `directSendNoLimitIOU`/`directSendNoLimitMPT`), so the exemption must cover
|
||||
* directSendNoLimitIOU/directSendNoLimitMPT), so the exemption must cover
|
||||
* both the issuer/broker and issuer/vault pairs, not a direct broker/vault
|
||||
* pair. `asset` scopes it further to the vault's own currency/MPT issuance,
|
||||
* pair. asset scopes it further to the vault's own currency/MPT issuance,
|
||||
* so an unrelated one the same accounts happen to hold is still protected.
|
||||
*/
|
||||
struct LoanDefaultFreezeExemptAccounts
|
||||
@@ -88,10 +164,10 @@ struct LoanDefaultFreezeExemptAccounts
|
||||
* @param view Ledger view used to resolve the Loan -> LoanBroker -> Vault
|
||||
* chain.
|
||||
* @param tx The transaction under invariant review.
|
||||
* @return The exempt accounts and asset if `tx` is a `ttLOAN_MANAGE`
|
||||
* transaction with the `tfLoanDefault` flag set, `fixCleanup3_4_0` is
|
||||
* @return The exempt accounts and asset if tx is a ttLOAN_MANAGE
|
||||
* transaction with the tfLoanDefault flag set, fixCleanup3_4_0 is
|
||||
* enabled, and the loan/broker/vault objects it references can all be
|
||||
* resolved; `std::nullopt` otherwise.
|
||||
* resolved; std::nullopt otherwise.
|
||||
*/
|
||||
[[nodiscard]] std::optional<LoanDefaultFreezeExemptAccounts>
|
||||
getLoanDefaultFreezeExemptAccounts(ReadView const& view, STTx const& tx);
|
||||
@@ -254,28 +330,38 @@ adjustImpreciseNumber(
|
||||
value = 0;
|
||||
}
|
||||
|
||||
inline int
|
||||
getAssetsTotalScale(SLE::ConstRef vaultSle)
|
||||
{
|
||||
if (!vaultSle)
|
||||
return Number::kMinExponent - 1; // LCOV_EXCL_LINE
|
||||
return scale(vaultSle->at(sfAssetsTotal), vaultSle->at(sfAsset));
|
||||
}
|
||||
/**
|
||||
* Apply a signed delta to a LoanBroker's DebtTotal: on FixedPrecision Vaults,
|
||||
* add the exact delta (DebtTotal moves by exactly the same amount as the
|
||||
* Vault's AssetsDeployed, never re-rounded); on Legacy/CashBasis Vaults,
|
||||
* round through adjustImpreciseNumber at vaultScale. Shared by LoanSet
|
||||
* (origination) and LoanPay (payment, where delta is negative).
|
||||
*
|
||||
* @param brokerSle The LoanBroker whose DebtTotal is adjusted.
|
||||
* @param vaultSle The LoanBroker's Vault.
|
||||
* @param delta The signed change to DebtTotal.
|
||||
* @param vaultScale The Vault scale the caller captured before changing
|
||||
* AssetsTotal. Legacy/CashBasis round DebtTotal at that scale, not at
|
||||
* the scale after this transaction's AssetsTotal change. Unused on
|
||||
* FixedPrecision Vaults.
|
||||
*/
|
||||
void
|
||||
adjustBrokerDebtTotal(
|
||||
SLE::Ref brokerSle,
|
||||
SLE::ConstRef vaultSle,
|
||||
Number const& delta,
|
||||
int vaultScale);
|
||||
|
||||
// Compute the minimum required broker cover, rounded consistently.
|
||||
// DebtTotal is a broker-level aggregate maintained at vault scale, so the
|
||||
// rounding must also use vault scale — never an individual loan's scale.
|
||||
inline Number
|
||||
minimumBrokerCover(Number const& debtTotal, TenthBips32 coverRateMinimum, SLE::ConstRef vaultSle)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
vaultSle && vaultSle->getType() == ltVAULT, "xrpl::minimumBrokerCover : valid Vault sle");
|
||||
NumberRoundModeGuard const mg(Number::RoundingMode::Upward);
|
||||
return roundToAsset(
|
||||
vaultSle->at(sfAsset),
|
||||
tenthBipsOfValue(debtTotal, coverRateMinimum),
|
||||
getAssetsTotalScale(vaultSle));
|
||||
}
|
||||
/**
|
||||
* Minimum required broker cover, rounded up.
|
||||
*
|
||||
* DebtTotal is a broker-level aggregate, never rounded at an individual
|
||||
* loan's scale. Legacy and CashBasis Vaults round at the live AssetsTotal
|
||||
* exponent. FixedPrecision Vaults round at the Vault's base exponent
|
||||
* (-Scale, or 0 for integral assets).
|
||||
*/
|
||||
Number
|
||||
minimumBrokerCover(Number const& debtTotal, TenthBips32 coverRateMinimum, SLE::ConstRef vaultSle);
|
||||
|
||||
TER
|
||||
checkLoanGuards(
|
||||
@@ -379,10 +465,10 @@ loanPaymentDeltas(LoanPaymentParts const& parts);
|
||||
|
||||
} // namespace cash_basis
|
||||
|
||||
// Public dispatchers: pick cash_basis:: if featureLendingProtocolV1_1 is
|
||||
// enabled AND the Vault's LEVersion (VaultHelpers::getVaultVersion) is
|
||||
// VaultVersion::CashBasis, else instant_recognition::. These are the only entry points
|
||||
// transactors call.
|
||||
// Public dispatchers: pick cash_basis:: if the Vault's LEVersion
|
||||
// (VaultHelpers::getVaultVersion) is CashBasis or later (CashBasis or
|
||||
// FixedPrecision), else instant_recognition::. These are the only entry
|
||||
// points transactors call.
|
||||
AccountingDeltas
|
||||
loanOriginationDeltas(
|
||||
SLE::ConstRef vaultSle,
|
||||
|
||||
@@ -142,11 +142,11 @@ deleteProposal(ApplyView& view, SLE::pointer const& sleProposal, beast::Journal
|
||||
* off-ledger signatures it carries, and any change to a non-signature field
|
||||
* results in a false-return value.
|
||||
*
|
||||
* Signature (PaymentChannelClaim and the XChain attestation transactions)
|
||||
* is deliberately not compared: it is outside the account's own TxnSignature
|
||||
* even for an ordinary submission, so a proposal cannot bind it more tightly
|
||||
* than the signatures it collects do, and those transactors still validate a
|
||||
* substituted value exactly as they would for an ordinary submission.
|
||||
* Signature (PaymentChannelClaim) is deliberately not compared: it is
|
||||
* outside the account's own TxnSignature even for an ordinary submission, so
|
||||
* a proposal cannot bind it more tightly than the signatures it collects do,
|
||||
* and that transactor still validates a substituted value exactly as it would
|
||||
* for an ordinary submission.
|
||||
* MasterSignature appears in no transaction format.
|
||||
*
|
||||
* @param proposedTx The proposal's ProposedTransaction field.
|
||||
|
||||
@@ -316,6 +316,20 @@ transferRate(ReadView const& view, Asset const& asset);
|
||||
[[nodiscard]] Rate
|
||||
transferRate(ReadView const& view, STAmount const& amount);
|
||||
|
||||
/**
|
||||
* Returns the amount a sender must part with for `amount` to reach the
|
||||
* receiver once the issuer takes the transfer fee. Rounds up.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
addTransferFee(STAmount const& amount, Rate const& rate);
|
||||
|
||||
/**
|
||||
* Returns the amount a receiver gets when `amount` leaves the sender and the
|
||||
* issuer takes the transfer fee. Rounds down.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
subtractTransferFee(STAmount const& amount, Rate const& rate);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Holding operations (Asset-based dispatchers)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -80,6 +81,21 @@ struct VaultBalanceChange
|
||||
[[nodiscard]] TER
|
||||
adjustVaultBalances(SLE::Ref vault, VaultBalanceChange const& change, beast::Journal j);
|
||||
|
||||
/**
|
||||
* @brief Apply a signed cash movement to a Vault of any version. FixedPrecision
|
||||
* Vaults go through adjustVaultBalances; Legacy and CashBasis Vaults add the
|
||||
* amount to both AssetsTotal and AssetsAvailable.
|
||||
*
|
||||
* @param vault The vault SLE.
|
||||
* @param delta Signed change to AssetsAvailable; the exact amount moved on the
|
||||
* Vault pseudo-account.
|
||||
* @param j Journal passed through to adjustVaultBalances.
|
||||
*
|
||||
* @return tesSUCCESS, or the adjustVaultBalances error for FixedPrecision Vaults.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
adjustVaultCash(SLE::Ref vault, STAmount const& delta, beast::Journal j);
|
||||
|
||||
/**
|
||||
* Return the Vault's current live exponent.
|
||||
*
|
||||
@@ -148,18 +164,20 @@ posteriorAssetScale(
|
||||
|
||||
/**
|
||||
* Shared core of creditToPosteriorAvailableScale and
|
||||
* creditToPosteriorBrokerCoverScale: floors reference + raw at scale and
|
||||
* returns the difference from reference, so the delta applied is exactly
|
||||
* what moves reference onto the floored sum. See
|
||||
* creditToPosteriorAvailableScale's doc for why the sum, not raw alone,
|
||||
* must be floored. raw is the exact amount; it is not rounded on its own
|
||||
* before being added to reference.
|
||||
* creditToPosteriorBrokerCoverScale: floors reference + raw at the sum's
|
||||
* own live scale (never finer than baseScale) and returns the difference
|
||||
* from reference, so the delta applied is exactly what moves reference onto
|
||||
* the floored sum. See creditToPosteriorAvailableScale's doc for why the
|
||||
* sum, not raw alone, must be floored. raw is the exact amount; it is not
|
||||
* rounded on its own before being added to reference. The sum and its scale
|
||||
* are computed once, in roundingMode, so a Downward credit is always
|
||||
* between zero and raw.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
creditToPosteriorScale(
|
||||
Asset const& asset,
|
||||
Number const& reference,
|
||||
int atScale,
|
||||
int baseScale,
|
||||
Number const& raw,
|
||||
Number::RoundingMode roundingMode);
|
||||
|
||||
@@ -333,6 +351,18 @@ vaultBaseScale(Asset const& asset, std::uint8_t scale);
|
||||
[[nodiscard]] bool
|
||||
isOnVaultBaseGrid(Asset const& asset, Number const& value, int baseScale);
|
||||
|
||||
/**
|
||||
* Checks that a requested AssetsMaximum is exactly representable on the
|
||||
* Vault's base grid, otherwise associateAsset would silently round the cap
|
||||
* the owner asked for. Used by VaultSet::preclaim on an existing Vault.
|
||||
*
|
||||
* @param vault The vault ledger entry.
|
||||
* @param amount The requested AssetsMaximum.
|
||||
* @return tesSUCCESS, or tecPRECISION_LOSS if amount is not representable.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
checkAssetsMaximum(SLE::ConstRef vault, Number const& amount);
|
||||
|
||||
/**
|
||||
* Controls whether to truncate shares instead of rounding.
|
||||
*/
|
||||
@@ -360,35 +390,24 @@ enum class WaiveUnrealizedLoss : bool { No = false, Yes = true };
|
||||
assetsTotalForWithdrawal(SLE::ConstRef vault, WaiveUnrealizedLoss waive);
|
||||
|
||||
/**
|
||||
* Returns true if debiting amount from total (the current value of a
|
||||
* vault's sfAssetsTotal or sfAssetsAvailable) would canonicalize to the
|
||||
* same STAmount value. This happens when amount is non-zero but too small
|
||||
* to change the stored total at STAmount's precision. Shares would still
|
||||
* move, so the ValidVault invariant would fail after apply; callers use
|
||||
* this to reject the transaction upfront instead.
|
||||
*
|
||||
* @param asset The vault's underlying asset, used to canonicalize both
|
||||
* sides the same way the ledger will when the field is stored.
|
||||
* @param total The field's current value.
|
||||
* @param amount The amount to debit. Zero always returns false; that case
|
||||
* is rejected separately.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
debitIsNonZeroDust(Asset const& asset, Number const& total, Number const& amount);
|
||||
|
||||
/**
|
||||
* Returns the reference balance a cash outflow's dust check
|
||||
* (debitIsNonZeroDust) should compare against: FixedPrecision Vaults use
|
||||
* AssetsAvailable, the balance the cash actually leaves; Legacy/CashBasis
|
||||
* Vaults use the given AssetsTotal. Shared by VaultWithdraw and
|
||||
* VaultClawback.
|
||||
* Reject a cash outflow that is dust (see debitIsNonZeroDust) or whose check
|
||||
* overflows Number, which is easy to hit with a large Scale.
|
||||
*
|
||||
* @param vault The vault SLE.
|
||||
* @param assetsTotal The vault's current AssetsTotal, as already read by the
|
||||
* caller.
|
||||
* @param amount The amount to debit.
|
||||
* @param j Journal for the debug log.
|
||||
* @param name Transaction name used as the log prefix.
|
||||
*
|
||||
* @return tesSUCCESS; tecPRECISION_LOSS if amount is dust; tecPATH_DRY if the
|
||||
* check overflows. Overflow means the transaction cannot apply, but
|
||||
* ledger state is still consistent.
|
||||
*/
|
||||
[[nodiscard]] Number
|
||||
vaultDebitDustReference(SLE::ConstRef vault, Number const& assetsTotal);
|
||||
[[nodiscard]] TER
|
||||
checkDebitNotDust(
|
||||
SLE::ConstRef vault,
|
||||
Number const& amount,
|
||||
beast::Journal j,
|
||||
std::string_view name);
|
||||
|
||||
/**
|
||||
* From the perspective of a vault, return the number of shares to demand from
|
||||
@@ -483,8 +502,9 @@ decodeVaultVersion(std::optional<std::uint8_t> leVersion);
|
||||
*
|
||||
* @param rules The active ledger rules.
|
||||
*
|
||||
* @return VaultVersion::FixedPrecision once featureLendingProtocolV1_2,
|
||||
* fixCleanup3_2_0 and fixCleanup3_4_0 are all enabled; VaultVersion::CashBasis
|
||||
* @return VaultVersion::FixedPrecision once featureLendingProtocolV1_1,
|
||||
* featureLendingProtocolV1_2 and fixCleanup3_4_0 are all enabled;
|
||||
* VaultVersion::CashBasis
|
||||
* once featureLendingProtocolV1_1 is enabled; VaultVersion::Legacy otherwise.
|
||||
*/
|
||||
[[nodiscard]] VaultVersion
|
||||
|
||||
@@ -348,16 +348,19 @@ isAuditorMirrorCurrent(SLE const& issuance, SLE const& mptoken);
|
||||
areMirrorsCurrent(SLE const& issuance, SLE const& mptoken);
|
||||
|
||||
/**
|
||||
* @brief Set the holder's issuer mirror epoch to match the issuance's current issuer key epoch.
|
||||
* @brief Set the holder's issuer mirror epoch, and the issuer mirror key, to match the issuance's
|
||||
* current key.
|
||||
*
|
||||
* Call this after writing the issuer mirror ciphertext under the issuance's
|
||||
* currently registered issuer key, so that the mirror reads as current afterwards.
|
||||
* Also records sfIssuerMirrorEncryptionKey as the issuance's current issuer key
|
||||
* (both fields stay absent at epoch 0, where the original issuer key applies).
|
||||
*
|
||||
* @param issuance The MPTokenIssuance ledger object.
|
||||
* @param mptoken The holder's MPToken ledger entry to update.
|
||||
*/
|
||||
void
|
||||
setIssuerMirrorEpoch(SLE const& issuance, SLE& mptoken);
|
||||
setIssuerMirrorCurrent(SLE const& issuance, SLE& mptoken);
|
||||
|
||||
/**
|
||||
* @brief Set the holder's auditor mirror epoch to match the issuance's current auditor key epoch.
|
||||
@@ -372,16 +375,18 @@ void
|
||||
setAuditorMirrorEpoch(SLE const& issuance, SLE& mptoken);
|
||||
|
||||
/**
|
||||
* @brief Set the holder's MPToken mirror epochs to match the issuance's current key epochs.
|
||||
* @brief Set the holder's MPToken mirror epochs, and the issuer mirror key, to match the issuance's
|
||||
* current keys.
|
||||
*
|
||||
* Call this after writing mirror ciphertexts under the issuance's currently
|
||||
* registered keys, so that the mirrors read as current afterwards.
|
||||
* registered keys, so that the mirrors read as current afterwards. Also records
|
||||
* sfIssuerMirrorEncryptionKey via setIssuerMirrorCurrent.
|
||||
*
|
||||
* @param issuance The MPTokenIssuance ledger object.
|
||||
* @param mptoken The holder's MPToken ledger entry to update.
|
||||
*/
|
||||
void
|
||||
setMirrorEpochs(SLE const& issuance, SLE& mptoken);
|
||||
setMirrorsCurrent(SLE const& issuance, SLE& mptoken);
|
||||
|
||||
/**
|
||||
* @brief Verifies revealed amount encryptions for all recipients.
|
||||
|
||||
@@ -10,6 +10,25 @@ namespace xrpl {
|
||||
// This was the reference fee units used in the old fee calculation.
|
||||
inline constexpr std::uint32_t kFeeUnitsDeprecated = 10;
|
||||
|
||||
// Number of micro-drops in one drop.
|
||||
inline constexpr std::uint32_t microDropsPerDrop{1'000'000};
|
||||
|
||||
/**
|
||||
* Hard protocol bounds on the Feature Extension fee settings. A voted value
|
||||
* can never fall outside these, so `preflight`, which has no view, may bound
|
||||
* against them. Gas and bytecode limits are capped; gas price has a floor
|
||||
* (zero would make WASM execution effectively free).
|
||||
*/
|
||||
inline constexpr std::uint32_t kMaxGasLimit{2'000'000};
|
||||
inline constexpr std::uint32_t kMaxBytecodeSizeLimit{200'000};
|
||||
inline constexpr std::uint32_t kMinGasPrice{1};
|
||||
|
||||
// The following default values of fee settings will seed into FeeSettings
|
||||
// and write to the ledger on featureSmartEscrow activation.
|
||||
inline constexpr std::uint32_t kDefaultGasLimit{1'000'000};
|
||||
inline constexpr std::uint32_t kDefaultBytecodeSizeLimit{100'000};
|
||||
inline constexpr std::uint32_t kDefaultGasPrice{1'000'000};
|
||||
|
||||
/**
|
||||
* Reflects the fee settings for a particular ledger.
|
||||
*
|
||||
@@ -33,13 +52,47 @@ struct Fees
|
||||
*/
|
||||
XRPAmount increment{0};
|
||||
|
||||
/**
|
||||
* @brief Gas limit for Feature Extensions (instructions).
|
||||
*
|
||||
* This and the one below default to the protocol values rather than 0,
|
||||
* because an explicit 0 is the voted kill switch.
|
||||
*/
|
||||
std::uint32_t gasLimit{kDefaultGasLimit};
|
||||
|
||||
/**
|
||||
* @brief Bytecode size limit for Feature Extensions (bytes).
|
||||
*/
|
||||
std::uint32_t bytecodeSizeLimit{kDefaultBytecodeSizeLimit};
|
||||
|
||||
/**
|
||||
* @brief Price of WASM gas (micro-drops).
|
||||
*/
|
||||
std::uint32_t gasPrice{kDefaultGasPrice};
|
||||
|
||||
explicit Fees() = default;
|
||||
Fees(Fees const&) = default;
|
||||
Fees&
|
||||
operator=(Fees const&) = default;
|
||||
|
||||
Fees(XRPAmount base, XRPAmount reserve, XRPAmount increment)
|
||||
: base(base), reserve(reserve), increment(increment)
|
||||
: base{base}, reserve{reserve}, increment{increment}
|
||||
{
|
||||
}
|
||||
|
||||
Fees(
|
||||
XRPAmount base,
|
||||
XRPAmount reserve,
|
||||
XRPAmount increment,
|
||||
std::uint32_t gasLimit,
|
||||
std::uint32_t bytecodeSizeLimit,
|
||||
std::uint32_t gasPrice)
|
||||
: base{base}
|
||||
, reserve{reserve}
|
||||
, increment{increment}
|
||||
, gasLimit{gasLimit}
|
||||
, bytecodeSizeLimit{bytecodeSizeLimit}
|
||||
, gasPrice{gasPrice}
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
|
||||
@@ -321,17 +320,6 @@ amm(UInt256 const& amm) noexcept;
|
||||
Keylet
|
||||
delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept;
|
||||
|
||||
Keylet
|
||||
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType);
|
||||
|
||||
// `seq` is stored as `sfXChainClaimID` in the object
|
||||
Keylet
|
||||
xChainClaimID(STXChainBridge const& bridge, std::uint64_t const seq);
|
||||
|
||||
// `seq` is stored as `sfXChainAccountCreateCount` in the object
|
||||
Keylet
|
||||
xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t const seq);
|
||||
|
||||
Keylet
|
||||
did(AccountID const& account) noexcept;
|
||||
|
||||
|
||||
@@ -103,6 +103,32 @@ enum LedgerEntryType : std::uint16_t {
|
||||
*/
|
||||
ltGENERATOR_MAP [[deprecated("This object type is not supported and should not be used.")]] =
|
||||
0x0067,
|
||||
|
||||
/**
|
||||
* A deprecated type, removed with the XChainBridge amendment.
|
||||
*
|
||||
* @deprecated **This object type is not supported and should not be used.**
|
||||
* The XChainBridge amendment was never enabled on Mainnet.
|
||||
*/
|
||||
ltBRIDGE [[deprecated("This object type is not supported and should not be used.")]] = 0x0069,
|
||||
|
||||
/**
|
||||
* A deprecated type, removed with the XChainBridge amendment.
|
||||
*
|
||||
* @deprecated **This object type is not supported and should not be used.**
|
||||
* The XChainBridge amendment was never enabled on Mainnet.
|
||||
*/
|
||||
ltXCHAIN_OWNED_CLAIM_ID
|
||||
[[deprecated("This object type is not supported and should not be used.")]] = 0x0071,
|
||||
|
||||
/**
|
||||
* A deprecated type, removed with the XChainBridge amendment.
|
||||
*
|
||||
* @deprecated **This object type is not supported and should not be used.**
|
||||
* The XChainBridge amendment was never enabled on Mainnet.
|
||||
*/
|
||||
ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID
|
||||
[[deprecated("This object type is not supported and should not be used.")]] = 0x0074,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -317,12 +317,12 @@ constexpr std::uint8_t kVaultDefaultIouScale = 6;
|
||||
* Chosen so 1 IOU can always convert to shares:
|
||||
* 10^19 > maxMPTokenAmount (2^64-1) > 10^18.
|
||||
*/
|
||||
constexpr std::uint8_t kVaultMaximumIouScale = 18;
|
||||
constexpr std::uint8_t kLegacyVaultMaximumIouScale = 18;
|
||||
|
||||
/**
|
||||
* Maximum Scale for a Vault created under featureLendingProtocolV1_2.
|
||||
*/
|
||||
constexpr std::uint8_t kVaultMaximumFixedPrecisionIouScale = 10;
|
||||
constexpr std::uint8_t kFixedPrecisionVaultMaximumIouScale = 10;
|
||||
|
||||
/**
|
||||
* Vault ledger-entry schema versions, persisted as sfLEVersion.
|
||||
@@ -398,6 +398,11 @@ constexpr std::uint32_t kMaxInvestmentPeriod = std::chrono::seconds{std::chrono:
|
||||
*/
|
||||
constexpr std::uint8_t kMaxAssetCheckDepth = 5;
|
||||
|
||||
/**
|
||||
* Maximum length of a Data field in Escrow object that can be updated by WASM code.
|
||||
*/
|
||||
constexpr std::size_t kMaxWasmDataLength = 1 * 1024; // 1KB
|
||||
|
||||
/**
|
||||
* A ledger index.
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,6 @@ class STBitString;
|
||||
template <class>
|
||||
class STInteger;
|
||||
class STNumber;
|
||||
class STXChainBridge;
|
||||
class STVector256;
|
||||
class STCurrency;
|
||||
|
||||
@@ -71,7 +70,7 @@ class STCurrency;
|
||||
STYPE(STI_UINT384, 22) \
|
||||
STYPE(STI_UINT512, 23) \
|
||||
STYPE(STI_ISSUE, 24) \
|
||||
STYPE(STI_XCHAIN_BRIDGE, 25) \
|
||||
/* 25 is reserved */ \
|
||||
STYPE(STI_CURRENCY, 26) \
|
||||
\
|
||||
/* high-level types */ \
|
||||
@@ -361,7 +360,6 @@ using SF_CURRENCY = TypedField<STCurrency>;
|
||||
using SF_NUMBER = TypedField<STNumber>;
|
||||
using SF_VL = TypedField<STBlob>;
|
||||
using SF_VECTOR256 = TypedField<STVector256>;
|
||||
using SF_XCHAIN_BRIDGE = TypedField<STXChainBridge>;
|
||||
// NOLINTEND(readability-identifier-naming)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -696,6 +696,16 @@ divRound(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundU
|
||||
STAmount
|
||||
divRoundStrict(STAmount const& v1, STAmount const& v2, Asset const& asset, bool roundUp);
|
||||
|
||||
/**
|
||||
* Returns amt * num / den, rounded in the requested direction.
|
||||
*
|
||||
* Dispatches to the XRPAmount, IOUAmount or MPTAmount overload. XRP and MPT
|
||||
* results are exact; an IOU result is rounded to the 16-digit mantissa in the
|
||||
* requested direction. Only Upward and Downward are supported.
|
||||
*/
|
||||
[[nodiscard]] STAmount
|
||||
mulRatio(STAmount const& amt, std::uint32_t num, std::uint32_t den, Number::RoundingMode rounding);
|
||||
|
||||
// Someone is offering X for Y, what is the rate?
|
||||
// Rate: smaller is better, the taker wants the most out: in/out
|
||||
// VFALCO TODO Return a Quality object
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <xrpl/protocol/HashPrefix.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/SOTemplate.h>
|
||||
#include <xrpl/protocol/STAccount.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STBitString.h>
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/CountedObject.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class Serializer;
|
||||
class STObject;
|
||||
|
||||
class STXChainBridge final : public STBase, public CountedObject<STXChainBridge>
|
||||
{
|
||||
STAccount lockingChainDoor_{sfLockingChainDoor};
|
||||
STIssue lockingChainIssue_{sfLockingChainIssue};
|
||||
STAccount issuingChainDoor_{sfIssuingChainDoor};
|
||||
STIssue issuingChainIssue_{sfIssuingChainIssue};
|
||||
|
||||
public:
|
||||
using value_type = STXChainBridge;
|
||||
|
||||
enum class ChainType { Locking, Issuing };
|
||||
|
||||
static ChainType
|
||||
otherChain(ChainType ct);
|
||||
|
||||
static ChainType
|
||||
srcChain(bool wasLockingChainSend);
|
||||
|
||||
static ChainType
|
||||
dstChain(bool wasLockingChainSend);
|
||||
|
||||
STXChainBridge();
|
||||
|
||||
explicit STXChainBridge(SField const& name);
|
||||
|
||||
STXChainBridge(STXChainBridge const& rhs) = default;
|
||||
|
||||
STXChainBridge(STObject const& o);
|
||||
|
||||
STXChainBridge(
|
||||
AccountID const& srcChainDoor,
|
||||
Issue const& srcChainIssue,
|
||||
AccountID const& dstChainDoor,
|
||||
Issue const& dstChainIssue);
|
||||
|
||||
explicit STXChainBridge(json::Value const& v);
|
||||
|
||||
explicit STXChainBridge(SField const& name, json::Value const& v);
|
||||
|
||||
explicit STXChainBridge(SerialIter& sit, SField const& name);
|
||||
|
||||
STXChainBridge&
|
||||
operator=(STXChainBridge const& rhs) = default;
|
||||
|
||||
[[nodiscard]] std::string
|
||||
getText() const override;
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
[[nodiscard]] AccountID const&
|
||||
lockingChainDoor() const;
|
||||
|
||||
[[nodiscard]] Issue const&
|
||||
lockingChainIssue() const;
|
||||
|
||||
[[nodiscard]] AccountID const&
|
||||
issuingChainDoor() const;
|
||||
|
||||
[[nodiscard]] Issue const&
|
||||
issuingChainIssue() const;
|
||||
|
||||
[[nodiscard]] AccountID const&
|
||||
door(ChainType ct) const;
|
||||
|
||||
[[nodiscard]] Issue const&
|
||||
issue(ChainType ct) const;
|
||||
|
||||
[[nodiscard]] SerializedTypeID
|
||||
getSType() const override;
|
||||
|
||||
[[nodiscard]] json::Value getJson(JsonOptions) const override;
|
||||
|
||||
void
|
||||
add(Serializer& s) const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isEquivalent(STBase const& t) const override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
isDefault() const override;
|
||||
|
||||
[[nodiscard]] value_type const&
|
||||
value() const noexcept;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<STXChainBridge>
|
||||
construct(SerialIter&, SField const& name);
|
||||
|
||||
STBase*
|
||||
copy(std::size_t n, void* buf) const override;
|
||||
STBase*
|
||||
move(std::size_t n, void* buf) override;
|
||||
|
||||
friend bool
|
||||
operator==(STXChainBridge const& lhs, STXChainBridge const& rhs);
|
||||
|
||||
friend bool
|
||||
operator<(STXChainBridge const& lhs, STXChainBridge const& rhs);
|
||||
};
|
||||
|
||||
inline bool
|
||||
operator==(STXChainBridge const& lhs, STXChainBridge const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.lockingChainDoor_,
|
||||
lhs.lockingChainIssue_,
|
||||
lhs.issuingChainDoor_,
|
||||
lhs.issuingChainIssue_) ==
|
||||
std::tie(
|
||||
rhs.lockingChainDoor_,
|
||||
rhs.lockingChainIssue_,
|
||||
rhs.issuingChainDoor_,
|
||||
rhs.issuingChainIssue_);
|
||||
}
|
||||
|
||||
inline bool
|
||||
operator<(STXChainBridge const& lhs, STXChainBridge const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.lockingChainDoor_,
|
||||
lhs.lockingChainIssue_,
|
||||
lhs.issuingChainDoor_,
|
||||
lhs.issuingChainIssue_) <
|
||||
std::tie(
|
||||
rhs.lockingChainDoor_,
|
||||
rhs.lockingChainIssue_,
|
||||
rhs.issuingChainDoor_,
|
||||
rhs.issuingChainIssue_);
|
||||
}
|
||||
|
||||
inline AccountID const&
|
||||
STXChainBridge::lockingChainDoor() const
|
||||
{
|
||||
return lockingChainDoor_.value();
|
||||
};
|
||||
|
||||
inline Issue const&
|
||||
STXChainBridge::lockingChainIssue() const
|
||||
{
|
||||
return lockingChainIssue_.value().get<Issue>();
|
||||
};
|
||||
|
||||
inline AccountID const&
|
||||
STXChainBridge::issuingChainDoor() const
|
||||
{
|
||||
return issuingChainDoor_.value();
|
||||
};
|
||||
|
||||
inline Issue const&
|
||||
STXChainBridge::issuingChainIssue() const
|
||||
{
|
||||
return issuingChainIssue_.value().get<Issue>();
|
||||
};
|
||||
|
||||
inline STXChainBridge::value_type const&
|
||||
STXChainBridge::value() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline AccountID const&
|
||||
STXChainBridge::door(ChainType ct) const
|
||||
{
|
||||
if (ct == ChainType::Locking)
|
||||
return lockingChainDoor();
|
||||
return issuingChainDoor();
|
||||
}
|
||||
|
||||
inline Issue const&
|
||||
STXChainBridge::issue(ChainType ct) const
|
||||
{
|
||||
if (ct == ChainType::Locking)
|
||||
return lockingChainIssue();
|
||||
return issuingChainIssue();
|
||||
}
|
||||
|
||||
inline STXChainBridge::ChainType
|
||||
STXChainBridge::otherChain(ChainType ct)
|
||||
{
|
||||
if (ct == ChainType::Locking)
|
||||
return ChainType::Issuing;
|
||||
return ChainType::Locking;
|
||||
}
|
||||
|
||||
inline STXChainBridge::ChainType
|
||||
STXChainBridge::srcChain(bool wasLockingChainSend)
|
||||
{
|
||||
if (wasLockingChainSend)
|
||||
return ChainType::Locking;
|
||||
return ChainType::Issuing;
|
||||
}
|
||||
|
||||
inline STXChainBridge::ChainType
|
||||
STXChainBridge::dstChain(bool wasLockingChainSend)
|
||||
{
|
||||
if (wasLockingChainSend)
|
||||
return ChainType::Issuing;
|
||||
return ChainType::Locking;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -133,7 +133,6 @@ enum TEMcodes : TERUnderlyingType {
|
||||
temBAD_MPT,
|
||||
temBAD_CIPHERTEXT,
|
||||
temINVALID_BYTECODE,
|
||||
temTEMP_DISABLED,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -184,6 +183,8 @@ enum TEFcodes : TERUnderlyingType {
|
||||
tefBAD_PATH_COUNT,
|
||||
tefNO_BYTECODE,
|
||||
tefBYTECODE_NOT_INCLUDED,
|
||||
tefTEMP_DISABLED,
|
||||
tefEXCEEDS_LIMIT,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -189,10 +189,6 @@ inline constexpr FlagValue tfUniversalMask = ~tfUniversal;
|
||||
TF_FLAG(tfClawTwoAssets, 0x00000001), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(XChainModifyBridge, \
|
||||
TF_FLAG(tfClearAccountCreateAmount, 0x00010000), \
|
||||
MASK_ADJ(0)) \
|
||||
\
|
||||
TRANSACTION(VaultCreate, \
|
||||
TF_FLAG(tfVaultPrivate, lsfVaultPrivate) \
|
||||
TF_FLAG(tfVaultShareNonTransferable, 0x00020000), \
|
||||
|
||||
@@ -73,6 +73,54 @@ enum TxType : std::uint16_t
|
||||
* This transaction type installs a hook.
|
||||
*/
|
||||
TtHookSet [[maybe_unused]] = 22,
|
||||
|
||||
/**
|
||||
* This transaction type was removed with the XChainBridge amendment, which was never enabled
|
||||
* on Mainnet. The value is reserved for historical purposes.
|
||||
*/
|
||||
TtXChainCreateClaimID [[deprecated("This transaction type is not supported and should not be used.")]] = 41,
|
||||
|
||||
/**
|
||||
* This transaction type was removed with the XChainBridge amendment, which was never enabled
|
||||
* on Mainnet. The value is reserved for historical purposes.
|
||||
*/
|
||||
TtXChainCommit [[deprecated("This transaction type is not supported and should not be used.")]] = 42,
|
||||
|
||||
/**
|
||||
* This transaction type was removed with the XChainBridge amendment, which was never enabled
|
||||
* on Mainnet. The value is reserved for historical purposes.
|
||||
*/
|
||||
TtXChainClaim [[deprecated("This transaction type is not supported and should not be used.")]] = 43,
|
||||
|
||||
/**
|
||||
* This transaction type was removed with the XChainBridge amendment, which was never enabled
|
||||
* on Mainnet. The value is reserved for historical purposes.
|
||||
*/
|
||||
TtXChainAccountCreateCommit [[deprecated("This transaction type is not supported and should not be used.")]] = 44,
|
||||
|
||||
/**
|
||||
* This transaction type was removed with the XChainBridge amendment, which was never enabled
|
||||
* on Mainnet. The value is reserved for historical purposes.
|
||||
*/
|
||||
TtXChainAddClaimAttestation [[deprecated("This transaction type is not supported and should not be used.")]] = 45,
|
||||
|
||||
/**
|
||||
* This transaction type was removed with the XChainBridge amendment, which was never enabled
|
||||
* on Mainnet. The value is reserved for historical purposes.
|
||||
*/
|
||||
TtXChainAddAccountCreateAttestation [[deprecated("This transaction type is not supported and should not be used.")]] = 46,
|
||||
|
||||
/**
|
||||
* This transaction type was removed with the XChainBridge amendment, which was never enabled
|
||||
* on Mainnet. The value is reserved for historical purposes.
|
||||
*/
|
||||
TtXChainModifyBridge [[deprecated("This transaction type is not supported and should not be used.")]] = 47,
|
||||
|
||||
/**
|
||||
* This transaction type was removed with the XChainBridge amendment, which was never enabled
|
||||
* on Mainnet. The value is reserved for historical purposes.
|
||||
*/
|
||||
TtXChainCreateBridge [[deprecated("This transaction type is not supported and should not be used.")]] = 48,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1,471 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/container/vector.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace attestations {
|
||||
|
||||
struct AttestationBase
|
||||
{
|
||||
// Account associated with the public key
|
||||
AccountID attestationSignerAccount;
|
||||
// Public key from the witness server attesting to the event
|
||||
PublicKey publicKey;
|
||||
// Signature from the witness server attesting to the event
|
||||
Buffer signature;
|
||||
// Account on the sending chain that triggered the event (sent the
|
||||
// transaction)
|
||||
AccountID sendingAccount;
|
||||
// Amount transferred on the sending chain
|
||||
STAmount sendingAmount;
|
||||
// Account on the destination chain that collects a share of the attestation
|
||||
// reward
|
||||
AccountID rewardAccount;
|
||||
// Amount was transferred on the locking chain
|
||||
bool wasLockingChainSend;
|
||||
|
||||
explicit AttestationBase(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend);
|
||||
|
||||
AttestationBase(AttestationBase const&) = default;
|
||||
|
||||
virtual ~AttestationBase() = default;
|
||||
|
||||
AttestationBase&
|
||||
operator=(AttestationBase const&) = default;
|
||||
|
||||
// verify that the signature attests to the data.
|
||||
[[nodiscard]] bool
|
||||
verify(STXChainBridge const& bridge) const;
|
||||
|
||||
protected:
|
||||
explicit AttestationBase(STObject const& o);
|
||||
explicit AttestationBase(json::Value const& v);
|
||||
|
||||
[[nodiscard]] static bool
|
||||
equalHelper(AttestationBase const& lhs, AttestationBase const& rhs);
|
||||
|
||||
[[nodiscard]] static bool
|
||||
sameEventHelper(AttestationBase const& lhs, AttestationBase const& rhs);
|
||||
|
||||
void
|
||||
addHelper(STObject& o) const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] virtual std::vector<std::uint8_t>
|
||||
message(STXChainBridge const& bridge) const = 0;
|
||||
};
|
||||
|
||||
// Attest to a regular cross-chain transfer
|
||||
struct AttestationClaim : AttestationBase
|
||||
{
|
||||
std::uint64_t claimID;
|
||||
std::optional<AccountID> dst;
|
||||
|
||||
explicit AttestationClaim(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimId,
|
||||
std::optional<AccountID> const& dst);
|
||||
|
||||
explicit AttestationClaim(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimId,
|
||||
std::optional<AccountID> const& dst);
|
||||
|
||||
explicit AttestationClaim(STObject const& o);
|
||||
explicit AttestationClaim(json::Value const& v);
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
// return true if the two attestations attest to the same thing
|
||||
[[nodiscard]] bool
|
||||
sameEvent(AttestationClaim const& rhs) const;
|
||||
|
||||
[[nodiscard]] static std::vector<std::uint8_t>
|
||||
message(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimID,
|
||||
std::optional<AccountID> const& dst);
|
||||
|
||||
[[nodiscard]] bool
|
||||
validAmounts() const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::vector<std::uint8_t>
|
||||
message(STXChainBridge const& bridge) const override;
|
||||
|
||||
friend bool
|
||||
operator==(AttestationClaim const& lhs, AttestationClaim const& rhs);
|
||||
};
|
||||
|
||||
struct CmpByClaimID
|
||||
{
|
||||
bool
|
||||
operator()(AttestationClaim const& lhs, AttestationClaim const& rhs) const
|
||||
{
|
||||
return lhs.claimID < rhs.claimID;
|
||||
}
|
||||
};
|
||||
|
||||
// Attest to a cross-chain transfer that creates an account
|
||||
struct AttestationCreateAccount : AttestationBase
|
||||
{
|
||||
// createCount on the sending chain. This is the value of the `CreateCount`
|
||||
// field of the bridge on the sending chain when the transaction was
|
||||
// executed.
|
||||
std::uint64_t createCount;
|
||||
// Account to create on the destination chain
|
||||
AccountID toCreate;
|
||||
// Total amount of the reward pool
|
||||
STAmount rewardAmount;
|
||||
|
||||
explicit AttestationCreateAccount(STObject const& o);
|
||||
|
||||
explicit AttestationCreateAccount(json::Value const& v);
|
||||
|
||||
explicit AttestationCreateAccount(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& toCreate);
|
||||
|
||||
explicit AttestationCreateAccount(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& toCreate);
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
// return true if the two attestations attest to the same thing
|
||||
[[nodiscard]] bool
|
||||
sameEvent(AttestationCreateAccount const& rhs) const;
|
||||
|
||||
friend bool
|
||||
operator==(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs);
|
||||
|
||||
[[nodiscard]] static std::vector<std::uint8_t>
|
||||
message(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& dst);
|
||||
|
||||
[[nodiscard]] bool
|
||||
validAmounts() const;
|
||||
|
||||
private:
|
||||
[[nodiscard]] std::vector<std::uint8_t>
|
||||
message(STXChainBridge const& bridge) const override;
|
||||
};
|
||||
|
||||
struct CmpByCreateCount
|
||||
{
|
||||
bool
|
||||
operator()(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs) const
|
||||
{
|
||||
return lhs.createCount < rhs.createCount;
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace attestations
|
||||
|
||||
// Result when checking when two attestation match.
|
||||
enum class AttestationMatch {
|
||||
// One of the fields doesn't match, and it isn't the dst field
|
||||
NonDstMismatch,
|
||||
// all of the fields match, except the dst field
|
||||
MatchExceptDst,
|
||||
// all of the fields match
|
||||
Match,
|
||||
};
|
||||
|
||||
struct XChainClaimAttestation
|
||||
{
|
||||
using TSignedAttestation = attestations::AttestationClaim;
|
||||
static SField const& arrayFieldName;
|
||||
|
||||
AccountID keyAccount;
|
||||
PublicKey publicKey;
|
||||
STAmount amount;
|
||||
AccountID rewardAccount;
|
||||
bool wasLockingChainSend;
|
||||
std::optional<AccountID> dst;
|
||||
|
||||
struct MatchFields
|
||||
{
|
||||
STAmount amount;
|
||||
bool wasLockingChainSend;
|
||||
std::optional<AccountID> dst;
|
||||
MatchFields(TSignedAttestation const& att);
|
||||
MatchFields(STAmount a, bool b, std::optional<AccountID> const& d)
|
||||
: amount{std::move(a)}, wasLockingChainSend{b}, dst{d}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
explicit XChainClaimAttestation(
|
||||
AccountID const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::optional<AccountID> const& dst);
|
||||
|
||||
explicit XChainClaimAttestation(
|
||||
STAccount const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
STAccount const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::optional<STAccount> const& dst);
|
||||
|
||||
explicit XChainClaimAttestation(TSignedAttestation const& claimAtt);
|
||||
|
||||
explicit XChainClaimAttestation(STObject const& o);
|
||||
|
||||
explicit XChainClaimAttestation(json::Value const& v);
|
||||
|
||||
[[nodiscard]] AttestationMatch
|
||||
match(MatchFields const& rhs) const;
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
friend bool
|
||||
operator==(XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs);
|
||||
};
|
||||
|
||||
struct XChainCreateAccountAttestation
|
||||
{
|
||||
using TSignedAttestation = attestations::AttestationCreateAccount;
|
||||
static SField const& arrayFieldName;
|
||||
|
||||
AccountID keyAccount;
|
||||
PublicKey publicKey;
|
||||
STAmount amount;
|
||||
STAmount rewardAmount;
|
||||
AccountID rewardAccount;
|
||||
bool wasLockingChainSend;
|
||||
AccountID dst;
|
||||
|
||||
struct MatchFields
|
||||
{
|
||||
STAmount amount;
|
||||
STAmount rewardAmount;
|
||||
bool wasLockingChainSend;
|
||||
AccountID dst;
|
||||
|
||||
MatchFields(TSignedAttestation const& att);
|
||||
};
|
||||
|
||||
explicit XChainCreateAccountAttestation(
|
||||
AccountID const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
AccountID const& dst);
|
||||
|
||||
explicit XChainCreateAccountAttestation(TSignedAttestation const& claimAtt);
|
||||
|
||||
explicit XChainCreateAccountAttestation(STObject const& o);
|
||||
|
||||
explicit XChainCreateAccountAttestation(json::Value const& v);
|
||||
|
||||
[[nodiscard]] STObject
|
||||
toSTObject() const;
|
||||
|
||||
[[nodiscard]] AttestationMatch
|
||||
match(MatchFields const& rhs) const;
|
||||
|
||||
friend bool
|
||||
operator==(
|
||||
XChainCreateAccountAttestation const& lhs,
|
||||
XChainCreateAccountAttestation const& rhs);
|
||||
};
|
||||
|
||||
// Attestations from witness servers for a particular claim ID and bridge.
|
||||
// Only one attestation per signature is allowed.
|
||||
template <class TAttestation>
|
||||
class XChainAttestationsBase
|
||||
{
|
||||
public:
|
||||
using AttCollection = std::vector<TAttestation>;
|
||||
|
||||
private:
|
||||
// Set a max number of allowed attestations to limit the amount of memory
|
||||
// allocated and processing time. This number is much larger than the actual
|
||||
// number of attestation a server would ever expect.
|
||||
static constexpr std::uint32_t kMaxAttestations = 256;
|
||||
AttCollection attestations_;
|
||||
|
||||
protected:
|
||||
// Prevent slicing to the base class
|
||||
~XChainAttestationsBase() = default;
|
||||
|
||||
public:
|
||||
XChainAttestationsBase() = default;
|
||||
XChainAttestationsBase(XChainAttestationsBase const& rhs) = default;
|
||||
XChainAttestationsBase&
|
||||
operator=(XChainAttestationsBase const& rhs) = default;
|
||||
|
||||
explicit XChainAttestationsBase(AttCollection&& sigs);
|
||||
|
||||
explicit XChainAttestationsBase(json::Value const& v);
|
||||
|
||||
explicit XChainAttestationsBase(STArray const& arr);
|
||||
|
||||
[[nodiscard]] STArray
|
||||
toSTArray() const;
|
||||
|
||||
[[nodiscard]] AttCollection::const_iterator
|
||||
begin() const;
|
||||
|
||||
[[nodiscard]] AttCollection::const_iterator
|
||||
end() const;
|
||||
|
||||
AttCollection::iterator
|
||||
begin();
|
||||
|
||||
AttCollection::iterator
|
||||
end();
|
||||
|
||||
template <class F>
|
||||
std::size_t
|
||||
eraseIf(F&& f);
|
||||
|
||||
[[nodiscard]] std::size_t
|
||||
size() const;
|
||||
|
||||
[[nodiscard]] bool
|
||||
empty() const;
|
||||
|
||||
[[nodiscard]] AttCollection const&
|
||||
attestations() const;
|
||||
|
||||
template <class T>
|
||||
void
|
||||
emplaceBack(T&& att);
|
||||
};
|
||||
|
||||
template <class TAttestation>
|
||||
[[nodiscard]] inline bool
|
||||
operator==(
|
||||
XChainAttestationsBase<TAttestation> const& lhs,
|
||||
XChainAttestationsBase<TAttestation> const& rhs)
|
||||
{
|
||||
return lhs.attestations() == rhs.attestations();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
inline XChainAttestationsBase<TAttestation>::AttCollection const&
|
||||
XChainAttestationsBase<TAttestation>::attestations() const
|
||||
{
|
||||
return attestations_;
|
||||
};
|
||||
|
||||
template <class TAttestation>
|
||||
template <class T>
|
||||
inline void
|
||||
XChainAttestationsBase<TAttestation>::emplaceBack(T&& att)
|
||||
{
|
||||
attestations_.emplace_back(std::forward<T>(att));
|
||||
};
|
||||
|
||||
template <class TAttestation>
|
||||
template <class F>
|
||||
inline std::size_t
|
||||
XChainAttestationsBase<TAttestation>::eraseIf(F&& f)
|
||||
{
|
||||
return std::erase_if(attestations_, std::forward<F>(f));
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
inline std::size_t
|
||||
XChainAttestationsBase<TAttestation>::size() const
|
||||
{
|
||||
return attestations_.size();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
inline bool
|
||||
XChainAttestationsBase<TAttestation>::empty() const
|
||||
{
|
||||
return attestations_.empty();
|
||||
}
|
||||
|
||||
class XChainClaimAttestations final : public XChainAttestationsBase<XChainClaimAttestation>
|
||||
{
|
||||
using TBase = XChainAttestationsBase<XChainClaimAttestation>;
|
||||
using TBase::TBase;
|
||||
};
|
||||
|
||||
class XChainCreateAccountAttestations final
|
||||
: public XChainAttestationsBase<XChainCreateAccountAttestation>
|
||||
{
|
||||
using TBase = XChainAttestationsBase<XChainCreateAccountAttestation>;
|
||||
using TBase::TBase;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -62,12 +62,9 @@ XRPL_FIX (EnforceNFTokenTrustline, Supported::Yes, VoteBehavior::DefaultNo
|
||||
XRPL_FIX (ReducedOffersV2, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(NFTokenMintOffer, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (PreviousTxnID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (EmptyDID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(PriceOracle, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (FillOrKill, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(DID, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(AMM, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(XRPFees, Supported::Yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::Yes, VoteBehavior::DefaultYes)
|
||||
@@ -85,6 +82,9 @@ XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::Yes, VoteBehavior::DefaultYe
|
||||
// to vote for it, the feature can be removed entirely from the code. Until
|
||||
// then the feature needs to be marked explicitly as obsolete, e.g.
|
||||
// XRPL_FEATURE(Example, Supported::yes, VoteBehavior::Obsolete)
|
||||
XRPL_FEATURE(XChainBridge, Supported::Yes, VoteBehavior::Obsolete)
|
||||
XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::Obsolete)
|
||||
|
||||
// The following amendments have been active for at least two years. Their
|
||||
// pre-amendment code has been removed and the identifiers are deprecated.
|
||||
// All known amendments and amendments that may appear in a validated ledger
|
||||
@@ -109,6 +109,7 @@ XRPL_RETIRE_FIX(AMMOverflowOffer)
|
||||
XRPL_RETIRE_FIX(AMMv1_1)
|
||||
XRPL_RETIRE_FIX(CheckThreading)
|
||||
XRPL_RETIRE_FIX(DisallowIncomingV1)
|
||||
XRPL_RETIRE_FIX(FillOrKill)
|
||||
XRPL_RETIRE_FIX(InnerObjTemplate)
|
||||
XRPL_RETIRE_FIX(MasterKeyAsRegularKey)
|
||||
XRPL_RETIRE_FIX(NonFungibleTokensV1_2)
|
||||
|
||||
@@ -206,23 +206,6 @@ LEDGER_ENTRY(ltLEDGER_HASHES, 0x0068, LedgerHashes, hashes, ({
|
||||
{sfHashes, SoeRequired},
|
||||
}))
|
||||
|
||||
/** The ledger object which lists details about sidechains.
|
||||
|
||||
\sa keylet::bridge
|
||||
*/
|
||||
LEDGER_ENTRY(ltBRIDGE, 0x0069, Bridge, bridge, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfMinAccountCreateAmount, SoeOptional},
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfXChainAccountClaimCount, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes an offer on the DEX.
|
||||
|
||||
\sa keylet::offer
|
||||
@@ -255,22 +238,6 @@ LEDGER_ENTRY_DUPLICATE(ltDEPOSIT_PREAUTH, 0x0070, DepositPreauth, deposit_preaut
|
||||
{sfAuthorizeCredentials, SoeOptional},
|
||||
}))
|
||||
|
||||
/** A claim id for a cross chain transaction.
|
||||
|
||||
\sa keylet::xChainClaimID
|
||||
*/
|
||||
LEDGER_ENTRY(ltXCHAIN_OWNED_CLAIM_ID, 0x0071, XChainOwnedClaimID, xchain_owned_claim_id, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfOtherChainSource, SoeRequired},
|
||||
{sfXChainClaimAttestations, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
}))
|
||||
|
||||
/** A ledger object which describes a bidirectional trust line.
|
||||
|
||||
@note Per Vinnie Falco this should be renamed to ltTRUST_LINE
|
||||
@@ -318,20 +285,6 @@ LEDGER_ENTRY(ltFEE_SETTINGS, 0x0073, FeeSettings, fee, ({
|
||||
{sfPreviousTxnLgrSeq, SoeOptional},
|
||||
}))
|
||||
|
||||
/** A claim id for a cross chain create account transaction.
|
||||
|
||||
\sa keylet::xChainCreateAccountClaimID
|
||||
*/
|
||||
LEDGER_ENTRY(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID, 0x0074, XChainOwnedCreateAccountClaimID, xchain_owned_create_account_claim_id, ({
|
||||
{sfAccount, SoeRequired},
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfXChainCreateAccountAttestations, SoeRequired},
|
||||
{sfOwnerNode, SoeRequired},
|
||||
{sfPreviousTxnID, SoeRequired},
|
||||
{sfPreviousTxnLgrSeq, SoeRequired},
|
||||
}))
|
||||
|
||||
/** A ledger object describing a single escrow.
|
||||
|
||||
\sa keylet::escrow
|
||||
@@ -417,6 +370,7 @@ LEDGER_ENTRY(ltMPTOKEN_ISSUANCE, 0x007e, MPTokenIssuance, mpt_issuance, ({
|
||||
{sfAuditorEncryptionKey, SoeOptional},
|
||||
{sfIssuerKeyEpoch, SoeOptional},
|
||||
{sfAuditorKeyEpoch, SoeOptional},
|
||||
{sfInitialIssuerEncryptionKey, SoeOptional},
|
||||
{sfConfidentialOutstandingAmount, SoeDefault},
|
||||
}))
|
||||
|
||||
@@ -438,6 +392,7 @@ LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({
|
||||
{sfAuditorEncryptedBalance, SoeOptional},
|
||||
{sfIssuerKeyMirrorEpoch, SoeOptional},
|
||||
{sfAuditorKeyMirrorEpoch, SoeOptional},
|
||||
{sfIssuerMirrorEncryptionKey, SoeOptional},
|
||||
{sfHolderEncryptionKey, SoeOptional},
|
||||
{sfRecoveryKey, SoeOptional},
|
||||
}))
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#error "undefined macro: TYPED_SFIELD"
|
||||
#endif
|
||||
|
||||
// A code marked "reserved" is not assigned to a field. Do not reuse a reserved
|
||||
// code until a year or two after its field was removed, so that no supported
|
||||
// release or tool still knows the old meaning.
|
||||
|
||||
// untyped
|
||||
UNTYPED_SFIELD(sfLedgerEntry, LEDGERENTRY, 257)
|
||||
@@ -23,8 +26,7 @@ TYPED_SFIELD(sfLEVersion, UINT8, 6)
|
||||
// 8-bit integers (uncommon)
|
||||
TYPED_SFIELD(sfTickSize, UINT8, 16)
|
||||
TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
|
||||
// 18 unused
|
||||
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
|
||||
// 18 to 19 reserved
|
||||
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
|
||||
TYPED_SFIELD(sfContractResult, UINT8, 21)
|
||||
TYPED_SFIELD(sfVaultKind, UINT8, 22)
|
||||
@@ -39,7 +41,7 @@ TYPED_SFIELD(sfDiscountedFee, UINT16, 6)
|
||||
|
||||
// 16-bit integers (uncommon)
|
||||
TYPED_SFIELD(sfVersion, UINT16, 16)
|
||||
// 17 to 20 unused
|
||||
// 17 to 20 reserved
|
||||
TYPED_SFIELD(sfLedgerFixType, UINT16, 21)
|
||||
TYPED_SFIELD(sfManagementFeeRate, UINT16, 22) // 1/10 basis points (bips)
|
||||
|
||||
@@ -90,7 +92,7 @@ TYPED_SFIELD(sfTicketSequence, UINT32, 41)
|
||||
TYPED_SFIELD(sfNFTokenTaxon, UINT32, 42)
|
||||
TYPED_SFIELD(sfMintedNFTokens, UINT32, 43)
|
||||
TYPED_SFIELD(sfBurnedNFTokens, UINT32, 44)
|
||||
// 45 to 47 unused
|
||||
// 45 to 47 reserved
|
||||
TYPED_SFIELD(sfVoteWeight, UINT32, 48)
|
||||
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
|
||||
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
|
||||
@@ -145,11 +147,9 @@ TYPED_SFIELD(sfNFTokenOfferNode, UINT64, 12)
|
||||
TYPED_SFIELD(sfEmitBurden, UINT64, 13)
|
||||
|
||||
// 64-bit integers (uncommon)
|
||||
// 16 to 18 unused
|
||||
// 16 to 18 reserved
|
||||
TYPED_SFIELD(sfReferenceCount, UINT64, 19)
|
||||
TYPED_SFIELD(sfXChainClaimID, UINT64, 20)
|
||||
TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21)
|
||||
TYPED_SFIELD(sfXChainAccountClaimCount, UINT64, 22)
|
||||
// 20 to 22 reserved
|
||||
TYPED_SFIELD(sfAssetPrice, UINT64, 23)
|
||||
TYPED_SFIELD(sfMaximumAmount, UINT64, 24, SField::kSmdBaseTen|SField::kSmdDefault)
|
||||
TYPED_SFIELD(sfOutstandingAmount, UINT64, 25, SField::kSmdBaseTen|SField::kSmdDefault)
|
||||
@@ -199,7 +199,7 @@ TYPED_SFIELD(sfBookDirectory, UINT256, 16)
|
||||
TYPED_SFIELD(sfInvoiceID, UINT256, 17)
|
||||
TYPED_SFIELD(sfNickname, UINT256, 18)
|
||||
TYPED_SFIELD(sfAmendment, UINT256, 19)
|
||||
// 20 unused
|
||||
// 20 reserved
|
||||
TYPED_SFIELD(sfDigest, UINT256, 21)
|
||||
TYPED_SFIELD(sfChannel, UINT256, 22)
|
||||
TYPED_SFIELD(sfConsensusHash, UINT256, 23)
|
||||
@@ -209,7 +209,7 @@ TYPED_SFIELD(sfPreviousPageMin, UINT256, 26)
|
||||
TYPED_SFIELD(sfNextPageMin, UINT256, 27)
|
||||
TYPED_SFIELD(sfNFTokenBuyOffer, UINT256, 28)
|
||||
TYPED_SFIELD(sfNFTokenSellOffer, UINT256, 29)
|
||||
// 30 to 33 unused
|
||||
// 30 to 33 reserved
|
||||
TYPED_SFIELD(sfDomainID, UINT256, 34)
|
||||
TYPED_SFIELD(sfVaultID, UINT256, 35,
|
||||
SField::kSmdPseudoAccount | SField::kSmdDefault)
|
||||
@@ -268,7 +268,7 @@ TYPED_SFIELD(sfMinimumOffer, AMOUNT, 16)
|
||||
TYPED_SFIELD(sfRippleEscrow, AMOUNT, 17)
|
||||
TYPED_SFIELD(sfDeliveredAmount, AMOUNT, 18)
|
||||
TYPED_SFIELD(sfNFTokenBrokerFee, AMOUNT, 19)
|
||||
// 20 to 21 unused
|
||||
// 20 to 21 reserved
|
||||
// currency amount (fees)
|
||||
TYPED_SFIELD(sfBaseFeeDrops, AMOUNT, 22)
|
||||
TYPED_SFIELD(sfReserveBaseDrops, AMOUNT, 23)
|
||||
@@ -279,8 +279,7 @@ TYPED_SFIELD(sfLPTokenOut, AMOUNT, 25)
|
||||
TYPED_SFIELD(sfLPTokenIn, AMOUNT, 26)
|
||||
TYPED_SFIELD(sfEPrice, AMOUNT, 27)
|
||||
TYPED_SFIELD(sfPrice, AMOUNT, 28)
|
||||
TYPED_SFIELD(sfSignatureReward, AMOUNT, 29)
|
||||
TYPED_SFIELD(sfMinAccountCreateAmount, AMOUNT, 30)
|
||||
// 29 to 30 reserved
|
||||
TYPED_SFIELD(sfLPTokenBalance, AMOUNT, 31)
|
||||
TYPED_SFIELD(sfFeeAmount, AMOUNT, 32)
|
||||
TYPED_SFIELD(sfMaxFee, AMOUNT, 33)
|
||||
@@ -309,7 +308,7 @@ TYPED_SFIELD(sfMasterSignature, VL, 18, SField::kSmdDefault, SFi
|
||||
TYPED_SFIELD(sfUNLModifyValidator, VL, 19)
|
||||
TYPED_SFIELD(sfValidatorToDisable, VL, 20)
|
||||
TYPED_SFIELD(sfValidatorToReEnable, VL, 21)
|
||||
// 22 to 25 unused
|
||||
// 22 to 25 reserved
|
||||
TYPED_SFIELD(sfDIDDocument, VL, 26)
|
||||
TYPED_SFIELD(sfData, VL, 27)
|
||||
TYPED_SFIELD(sfAssetClass, VL, 28)
|
||||
@@ -333,6 +332,8 @@ TYPED_SFIELD(sfAmountCommitment, VL, 45)
|
||||
TYPED_SFIELD(sfBalanceCommitment, VL, 46)
|
||||
TYPED_SFIELD(sfBytecode, VL, 47)
|
||||
TYPED_SFIELD(sfRecoveryKey, VL, 48)
|
||||
TYPED_SFIELD(sfInitialIssuerEncryptionKey, VL, 49)
|
||||
TYPED_SFIELD(sfIssuerMirrorEncryptionKey, VL, 50)
|
||||
|
||||
// account (common)
|
||||
TYPED_SFIELD(sfAccount, ACCOUNT, 1)
|
||||
@@ -341,7 +342,7 @@ TYPED_SFIELD(sfDestination, ACCOUNT, 3)
|
||||
TYPED_SFIELD(sfIssuer, ACCOUNT, 4)
|
||||
TYPED_SFIELD(sfAuthorize, ACCOUNT, 5)
|
||||
TYPED_SFIELD(sfUnauthorize, ACCOUNT, 6)
|
||||
// 7 unused
|
||||
// 7 reserved
|
||||
TYPED_SFIELD(sfRegularKey, ACCOUNT, 8)
|
||||
TYPED_SFIELD(sfNFTokenMinter, ACCOUNT, 9)
|
||||
TYPED_SFIELD(sfEmitCallback, ACCOUNT, 10)
|
||||
@@ -349,13 +350,7 @@ TYPED_SFIELD(sfHolder, ACCOUNT, 11)
|
||||
TYPED_SFIELD(sfDelegate, ACCOUNT, 12)
|
||||
|
||||
// account (uncommon)
|
||||
// 16 unused
|
||||
TYPED_SFIELD(sfOtherChainSource, ACCOUNT, 18)
|
||||
TYPED_SFIELD(sfOtherChainDestination, ACCOUNT, 19)
|
||||
TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20)
|
||||
TYPED_SFIELD(sfAttestationRewardAccount, ACCOUNT, 21)
|
||||
TYPED_SFIELD(sfLockingChainDoor, ACCOUNT, 22)
|
||||
TYPED_SFIELD(sfIssuingChainDoor, ACCOUNT, 23)
|
||||
// 16 to 23 reserved
|
||||
TYPED_SFIELD(sfSubject, ACCOUNT, 24)
|
||||
TYPED_SFIELD(sfBorrower, ACCOUNT, 25)
|
||||
TYPED_SFIELD(sfCounterparty, ACCOUNT, 26)
|
||||
@@ -381,14 +376,10 @@ TYPED_SFIELD(sfBaseAsset, CURRENCY, 1)
|
||||
TYPED_SFIELD(sfQuoteAsset, CURRENCY, 2)
|
||||
|
||||
// issue
|
||||
TYPED_SFIELD(sfLockingChainIssue, ISSUE, 1)
|
||||
TYPED_SFIELD(sfIssuingChainIssue, ISSUE, 2)
|
||||
// 1 to 2 reserved
|
||||
TYPED_SFIELD(sfAsset, ISSUE, 3)
|
||||
TYPED_SFIELD(sfAsset2, ISSUE, 4)
|
||||
|
||||
// bridge
|
||||
TYPED_SFIELD(sfXChainBridge, XCHAIN_BRIDGE, 1)
|
||||
|
||||
// inner object
|
||||
// OBJECT/1 is reserved for end of object
|
||||
UNTYPED_SFIELD(sfTransactionMetaData, OBJECT, 2)
|
||||
@@ -403,22 +394,19 @@ UNTYPED_SFIELD(sfMemo, OBJECT, 10)
|
||||
UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11)
|
||||
UNTYPED_SFIELD(sfNFToken, OBJECT, 12)
|
||||
UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13)
|
||||
// 14 unused
|
||||
// 14 reserved
|
||||
UNTYPED_SFIELD(sfPermission, OBJECT, 15)
|
||||
|
||||
// inner object (uncommon)
|
||||
UNTYPED_SFIELD(sfSigner, OBJECT, 16)
|
||||
// 17 unused
|
||||
// 17 reserved
|
||||
UNTYPED_SFIELD(sfMajority, OBJECT, 18)
|
||||
UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19)
|
||||
// 20 to 24 unused
|
||||
// 20 to 24 reserved
|
||||
UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25)
|
||||
UNTYPED_SFIELD(sfAuctionSlot, OBJECT, 26)
|
||||
UNTYPED_SFIELD(sfAuthAccount, OBJECT, 27)
|
||||
UNTYPED_SFIELD(sfXChainClaimProofSig, OBJECT, 28)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountProofSig, OBJECT, 29)
|
||||
UNTYPED_SFIELD(sfXChainClaimAttestationCollectionElement, OBJECT, 30)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountAttestationCollectionElement, OBJECT, 31)
|
||||
// 28 to 31 reserved
|
||||
UNTYPED_SFIELD(sfPriceData, OBJECT, 32)
|
||||
UNTYPED_SFIELD(sfCredential, OBJECT, 33)
|
||||
UNTYPED_SFIELD(sfRawTransaction, OBJECT, 34)
|
||||
@@ -440,17 +428,14 @@ UNTYPED_SFIELD(sfSufficient, ARRAY, 7)
|
||||
UNTYPED_SFIELD(sfAffectedNodes, ARRAY, 8)
|
||||
UNTYPED_SFIELD(sfMemos, ARRAY, 9)
|
||||
UNTYPED_SFIELD(sfNFTokens, ARRAY, 10)
|
||||
// 11 unused
|
||||
// 11 reserved
|
||||
UNTYPED_SFIELD(sfVoteSlots, ARRAY, 12)
|
||||
UNTYPED_SFIELD(sfAdditionalBooks, ARRAY, 13)
|
||||
|
||||
// array of objects (uncommon)
|
||||
UNTYPED_SFIELD(sfMajorities, ARRAY, 16)
|
||||
UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17)
|
||||
// 18 to 20 unused
|
||||
UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21)
|
||||
UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22)
|
||||
// 23 unused
|
||||
// 18 to 23 reserved
|
||||
UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24)
|
||||
UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25)
|
||||
UNTYPED_SFIELD(sfAuthorizeCredentials, ARRAY, 26)
|
||||
|
||||
@@ -457,111 +457,7 @@ TRANSACTION(ttAMM_DELETE, 40, AMMDelete,
|
||||
{sfAsset2, SoeRequired, SoeMptSupported},
|
||||
}))
|
||||
|
||||
/** This transactions creates a crosschain sequence number */
|
||||
#if TRANSACTION_INCLUDE
|
||||
# include <xrpl/tx/transactors/bridge/XChainBridge.h>
|
||||
#endif
|
||||
TRANSACTION(ttXCHAIN_CREATE_CLAIM_ID, 41, XChainCreateClaimID,
|
||||
({.delegable = Delegation::Delegable, .amendment = featureXChainBridge}),
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfOtherChainSource, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transactions initiates a crosschain transaction */
|
||||
TRANSACTION(ttXCHAIN_COMMIT, 42, XChainCommit,
|
||||
({.delegable = Delegation::Delegable, .amendment = featureXChainBridge}),
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfOtherChainDestination, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction completes a crosschain transaction */
|
||||
TRANSACTION(ttXCHAIN_CLAIM, 43, XChainClaim,
|
||||
({.delegable = Delegation::Delegable, .amendment = featureXChainBridge}),
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfDestinationTag, SoeOptional},
|
||||
{sfAmount, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction initiates a crosschain account create transaction */
|
||||
TRANSACTION(ttXCHAIN_ACCOUNT_CREATE_COMMIT, 44, XChainAccountCreateCommit,
|
||||
({.delegable = Delegation::Delegable, .amendment = featureXChainBridge}),
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction adds an attestation to a claim */
|
||||
TRANSACTION(ttXCHAIN_ADD_CLAIM_ATTESTATION, 45, XChainAddClaimAttestation,
|
||||
({
|
||||
.delegable = Delegation::Delegable,
|
||||
.amendment = featureXChainBridge,
|
||||
.privileges = Privilege::CreateAcct,
|
||||
}),
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfOtherChainSource, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transaction adds an attestation to an account */
|
||||
TRANSACTION(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, 46, XChainAddAccountCreateAttestation,
|
||||
({
|
||||
.delegable = Delegation::Delegable,
|
||||
.amendment = featureXChainBridge,
|
||||
.privileges = Privilege::CreateAcct,
|
||||
}),
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfOtherChainSource, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
}))
|
||||
|
||||
/** This transaction modifies a sidechain */
|
||||
TRANSACTION(ttXCHAIN_MODIFY_BRIDGE, 47, XChainModifyBridge,
|
||||
({.delegable = Delegation::Delegable, .amendment = featureXChainBridge}),
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeOptional},
|
||||
{sfMinAccountCreateAmount, SoeOptional},
|
||||
}))
|
||||
|
||||
/** This transactions creates a sidechain */
|
||||
TRANSACTION(ttXCHAIN_CREATE_BRIDGE, 48, XChainCreateBridge,
|
||||
({.delegable = Delegation::Delegable, .amendment = featureXChainBridge}),
|
||||
({
|
||||
{sfXChainBridge, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfMinAccountCreateAmount, SoeOptional},
|
||||
}))
|
||||
// 41 to 48 deprecated
|
||||
|
||||
/** This transaction type creates or updates a DID */
|
||||
#if TRANSACTION_INCLUDE
|
||||
|
||||
@@ -159,7 +159,6 @@ JSS(both); // in: Subscribe, Unsubscribe
|
||||
JSS(both_sides); // in: Subscribe, Unsubscribe
|
||||
JSS(branch); // out: server_info
|
||||
JSS(broadcast); // out: SubmitTransaction
|
||||
JSS(bridge_account); // in: LedgerEntry
|
||||
JSS(build_path); // in: TransactionSign
|
||||
JSS(build_version); // out: NetworkOPs
|
||||
JSS(cancel_after); // out: AccountChannels
|
||||
@@ -252,6 +251,9 @@ 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(gas_limit); // out: NetworkOPs
|
||||
JSS(bytecode_size_limit); // out: NetworkOPs
|
||||
JSS(gas_price); // out: NetworkOPs
|
||||
JSS(fail_hard); // in: Sign, Submit
|
||||
JSS(failed); // out: InboundLedger
|
||||
JSS(feature); // in: Feature
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
|
||||
@@ -1,348 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class BridgeBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: Bridge
|
||||
*
|
||||
* Type: ltBRIDGE (0x0069)
|
||||
* RPC Name: bridge
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use BridgeBuilder to construct new ledger entries.
|
||||
*/
|
||||
class Bridge : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltBRIDGE;
|
||||
|
||||
/**
|
||||
* @brief Construct a Bridge ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit Bridge(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for Bridge");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAccount() const
|
||||
{
|
||||
return this->sle_->at(sfAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->sle_->at(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getMinAccountCreateAmount() const
|
||||
{
|
||||
if (hasMinAccountCreateAmount())
|
||||
return this->sle_->at(sfMinAccountCreateAmount);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMinAccountCreateAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMinAccountCreateAmount() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfMinAccountCreateAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->sle_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->sle_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainAccountCreateCount() const
|
||||
{
|
||||
return this->sle_->at(sfXChainAccountCreateCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainAccountClaimCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainAccountClaimCount() const
|
||||
{
|
||||
return this->sle_->at(sfXChainAccountClaimCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for Bridge ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class BridgeBuilder : public LedgerEntryBuilderBase<BridgeBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new BridgeBuilder with required fields.
|
||||
* @param account The sfAccount field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param xChainAccountCreateCount The sfXChainAccountCreateCount field value.
|
||||
* @param xChainAccountClaimCount The sfXChainAccountClaimCount field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
*/
|
||||
BridgeBuilder(std::decay_t<typename SF_ACCOUNT::type::value_type> const& account,std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward,std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge,std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID,std::decay_t<typename SF_UINT64::type::value_type> const& xChainAccountCreateCount,std::decay_t<typename SF_UINT64::type::value_type> const& xChainAccountClaimCount,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq)
|
||||
: LedgerEntryBuilderBase<BridgeBuilder>(ltBRIDGE)
|
||||
{
|
||||
setAccount(account);
|
||||
setSignatureReward(signatureReward);
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
setXChainAccountCreateCount(xChainAccountCreateCount);
|
||||
setXChainAccountClaimCount(xChainAccountClaimCount);
|
||||
setOwnerNode(ownerNode);
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a BridgeBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
BridgeBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltBRIDGE)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for Bridge");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ledger entry-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setMinAccountCreateAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMinAccountCreateAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setXChainAccountCreateCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainAccountCreateCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainAccountClaimCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setXChainAccountClaimCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainAccountClaimCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
BridgeBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed Bridge wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
Bridge
|
||||
build(UInt256 const& index)
|
||||
{
|
||||
return Bridge{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
@@ -316,6 +316,30 @@ public:
|
||||
return this->sle_->isFieldPresent(sfAuditorKeyMirrorEpoch);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfIssuerMirrorEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getIssuerMirrorEncryptionKey() const
|
||||
{
|
||||
if (hasIssuerMirrorEncryptionKey())
|
||||
return this->sle_->at(sfIssuerMirrorEncryptionKey);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfIssuerMirrorEncryptionKey is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasIssuerMirrorEncryptionKey() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfIssuerMirrorEncryptionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfHolderEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
@@ -565,6 +589,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfIssuerMirrorEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenBuilder&
|
||||
setIssuerMirrorEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfIssuerMirrorEncryptionKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfHolderEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
|
||||
@@ -399,6 +399,30 @@ public:
|
||||
return this->sle_->isFieldPresent(sfAuditorKeyEpoch);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfInitialIssuerEncryptionKey (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_VL::type::value_type>
|
||||
getInitialIssuerEncryptionKey() const
|
||||
{
|
||||
if (hasInitialIssuerEncryptionKey())
|
||||
return this->sle_->at(sfInitialIssuerEncryptionKey);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfInitialIssuerEncryptionKey is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasInitialIssuerEncryptionKey() const
|
||||
{
|
||||
return this->sle_->isFieldPresent(sfInitialIssuerEncryptionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfConfidentialOutstandingAmount (SoeDefault)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
@@ -670,6 +694,17 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfInitialIssuerEncryptionKey (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
MPTokenIssuanceBuilder&
|
||||
setInitialIssuerEncryptionKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfInitialIssuerEncryptionKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfConfidentialOutstandingAmount (SoeDefault)
|
||||
* @return Reference to this builder for method chaining.
|
||||
|
||||
@@ -1,314 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class XChainOwnedClaimIDBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: XChainOwnedClaimID
|
||||
*
|
||||
* Type: ltXCHAIN_OWNED_CLAIM_ID (0x0071)
|
||||
* RPC Name: xchain_owned_claim_id
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use XChainOwnedClaimIDBuilder to construct new ledger entries.
|
||||
*/
|
||||
class XChainOwnedClaimID : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltXCHAIN_OWNED_CLAIM_ID;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainOwnedClaimID ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit XChainOwnedClaimID(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for XChainOwnedClaimID");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAccount() const
|
||||
{
|
||||
return this->sle_->at(sfAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->sle_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->sle_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainSource (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOtherChainSource() const
|
||||
{
|
||||
return this->sle_->at(sfOtherChainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimAttestations (SoeRequired)
|
||||
* @note This is an untyped field (unknown).
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
STArray const&
|
||||
getXChainClaimAttestations() const
|
||||
{
|
||||
return this->sle_->getFieldArray(sfXChainClaimAttestations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->sle_->at(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainOwnedClaimID ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class XChainOwnedClaimIDBuilder : public LedgerEntryBuilderBase<XChainOwnedClaimIDBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainOwnedClaimIDBuilder with required fields.
|
||||
* @param account The sfAccount field value.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param otherChainSource The sfOtherChainSource field value.
|
||||
* @param xChainClaimAttestations The sfXChainClaimAttestations field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder(std::decay_t<typename SF_ACCOUNT::type::value_type> const& account,std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge,std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID,std::decay_t<typename SF_ACCOUNT::type::value_type> const& otherChainSource,STArray const& xChainClaimAttestations,std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq)
|
||||
: LedgerEntryBuilderBase<XChainOwnedClaimIDBuilder>(ltXCHAIN_OWNED_CLAIM_ID)
|
||||
{
|
||||
setAccount(account);
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
setOtherChainSource(otherChainSource);
|
||||
setXChainClaimAttestations(xChainClaimAttestations);
|
||||
setSignatureReward(signatureReward);
|
||||
setOwnerNode(ownerNode);
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainOwnedClaimIDBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltXCHAIN_OWNED_CLAIM_ID)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for XChainOwnedClaimID");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ledger entry-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainSource (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setOtherChainSource(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainSource] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimAttestations (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setXChainClaimAttestations(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfXChainClaimAttestations, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedClaimIDBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed XChainOwnedClaimID wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
XChainOwnedClaimID
|
||||
build(UInt256 const& index)
|
||||
{
|
||||
return XChainOwnedClaimID{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
@@ -1,266 +0,0 @@
|
||||
// This file is auto-generated. Do not edit.
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STParsedJSON.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBase.h>
|
||||
#include <xrpl/protocol_autogen/LedgerEntryBuilderBase.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl::ledger_entries {
|
||||
|
||||
class XChainOwnedCreateAccountClaimIDBuilder;
|
||||
|
||||
/**
|
||||
* @brief Ledger Entry: XChainOwnedCreateAccountClaimID
|
||||
*
|
||||
* Type: ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID (0x0074)
|
||||
* RPC Name: xchain_owned_create_account_claim_id
|
||||
*
|
||||
* Immutable wrapper around SLE providing type-safe field access.
|
||||
* Use XChainOwnedCreateAccountClaimIDBuilder to construct new ledger entries.
|
||||
*/
|
||||
class XChainOwnedCreateAccountClaimID : public LedgerEntryBase
|
||||
{
|
||||
public:
|
||||
static constexpr LedgerEntryType entryType = ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainOwnedCreateAccountClaimID ledger entry wrapper from an existing SLE object.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
explicit XChainOwnedCreateAccountClaimID(SLE::const_pointer sle)
|
||||
: LedgerEntryBase(std::move(sle))
|
||||
{
|
||||
// Verify ledger entry type
|
||||
if (sle_->getType() != entryType)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for XChainOwnedCreateAccountClaimID");
|
||||
}
|
||||
}
|
||||
|
||||
// Ledger entry-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAccount() const
|
||||
{
|
||||
return this->sle_->at(sfAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->sle_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainAccountCreateCount() const
|
||||
{
|
||||
return this->sle_->at(sfXChainAccountCreateCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainCreateAccountAttestations (SoeRequired)
|
||||
* @note This is an untyped field (unknown).
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
STArray const&
|
||||
getXChainCreateAccountAttestations() const
|
||||
{
|
||||
return this->sle_->getFieldArray(sfXChainCreateAccountAttestations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOwnerNode (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getOwnerNode() const
|
||||
{
|
||||
return this->sle_->at(sfOwnerNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT256::type::value_type
|
||||
getPreviousTxnID() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT32::type::value_type
|
||||
getPreviousTxnLgrSeq() const
|
||||
{
|
||||
return this->sle_->at(sfPreviousTxnLgrSeq);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainOwnedCreateAccountClaimID ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class XChainOwnedCreateAccountClaimIDBuilder : public LedgerEntryBuilderBase<XChainOwnedCreateAccountClaimIDBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainOwnedCreateAccountClaimIDBuilder with required fields.
|
||||
* @param account The sfAccount field value.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainAccountCreateCount The sfXChainAccountCreateCount field value.
|
||||
* @param xChainCreateAccountAttestations The sfXChainCreateAccountAttestations field value.
|
||||
* @param ownerNode The sfOwnerNode field value.
|
||||
* @param previousTxnID The sfPreviousTxnID field value.
|
||||
* @param previousTxnLgrSeq The sfPreviousTxnLgrSeq field value.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder(std::decay_t<typename SF_ACCOUNT::type::value_type> const& account,std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge,std::decay_t<typename SF_UINT64::type::value_type> const& xChainAccountCreateCount,STArray const& xChainCreateAccountAttestations,std::decay_t<typename SF_UINT64::type::value_type> const& ownerNode,std::decay_t<typename SF_UINT256::type::value_type> const& previousTxnID,std::decay_t<typename SF_UINT32::type::value_type> const& previousTxnLgrSeq)
|
||||
: LedgerEntryBuilderBase<XChainOwnedCreateAccountClaimIDBuilder>(ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID)
|
||||
{
|
||||
setAccount(account);
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainAccountCreateCount(xChainAccountCreateCount);
|
||||
setXChainCreateAccountAttestations(xChainCreateAccountAttestations);
|
||||
setOwnerNode(ownerNode);
|
||||
setPreviousTxnID(previousTxnID);
|
||||
setPreviousTxnLgrSeq(previousTxnLgrSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainOwnedCreateAccountClaimIDBuilder from an existing SLE object.
|
||||
* @param sle The existing ledger entry to copy from.
|
||||
* @throws std::runtime_error if the ledger entry type doesn't match.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder(SLE::const_pointer sle)
|
||||
{
|
||||
if (sle->at(sfLedgerEntryType) != ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID)
|
||||
{
|
||||
throw std::runtime_error("Invalid ledger entry type for XChainOwnedCreateAccountClaimID");
|
||||
}
|
||||
object_ = *sle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Ledger entry-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setXChainAccountCreateCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainAccountCreateCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainCreateAccountAttestations (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setXChainCreateAccountAttestations(STArray const& value)
|
||||
{
|
||||
object_.setFieldArray(sfXChainCreateAccountAttestations, value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOwnerNode (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setOwnerNode(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOwnerNode] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setPreviousTxnID(std::decay_t<typename SF_UINT256::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPreviousTxnLgrSeq (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimIDBuilder&
|
||||
setPreviousTxnLgrSeq(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPreviousTxnLgrSeq] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the completed XChainOwnedCreateAccountClaimID wrapper.
|
||||
* @param index The ledger entry index.
|
||||
* @return The constructed ledger entry wrapper.
|
||||
*/
|
||||
XChainOwnedCreateAccountClaimID
|
||||
build(UInt256 const& index)
|
||||
{
|
||||
return XChainOwnedCreateAccountClaimID{std::make_shared<SLE>(std::move(object_), index)};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::ledger_entries
|
||||
@@ -1,203 +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 XChainAccountCreateCommitBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainAccountCreateCommit
|
||||
*
|
||||
* Type: ttXCHAIN_ACCOUNT_CREATE_COMMIT (44)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: Privilege::NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainAccountCreateCommitBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainAccountCreateCommit : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_ACCOUNT_CREATE_COMMIT;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAccountCreateCommit transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainAccountCreateCommit(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 XChainAccountCreateCommit");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestination (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getDestination() const
|
||||
{
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainAccountCreateCommit 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 XChainAccountCreateCommitBuilder : public TransactionBuilderBase<XChainAccountCreateCommitBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainAccountCreateCommitBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param destination The sfDestination field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_ACCOUNT::type::value_type> const& destination, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainAccountCreateCommitBuilder>(ttXCHAIN_ACCOUNT_CREATE_COMMIT, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setDestination(destination);
|
||||
setAmount(amount);
|
||||
setSignatureReward(signatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAccountCreateCommitBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_ACCOUNT_CREATE_COMMIT)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAccountCreateCommitBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder&
|
||||
setDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAccountCreateCommitBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainAccountCreateCommit wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainAccountCreateCommit
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainAccountCreateCommit{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,371 +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 XChainAddAccountCreateAttestationBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainAddAccountCreateAttestation
|
||||
*
|
||||
* Type: ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION (46)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: Privilege::CreateAcct
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainAddAccountCreateAttestationBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainAddAccountCreateAttestation : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAddAccountCreateAttestation transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainAddAccountCreateAttestation(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 XChainAddAccountCreateAttestation");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAttestationSignerAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAttestationSignerAccount() const
|
||||
{
|
||||
return this->tx_->at(sfAttestationSignerAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPublicKey (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getPublicKey() const
|
||||
{
|
||||
return this->tx_->at(sfPublicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignature (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getSignature() const
|
||||
{
|
||||
return this->tx_->at(sfSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainSource (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOtherChainSource() const
|
||||
{
|
||||
return this->tx_->at(sfOtherChainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAttestationRewardAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAttestationRewardAccount() const
|
||||
{
|
||||
return this->tx_->at(sfAttestationRewardAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfWasLockingChainSend (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT8::type::value_type
|
||||
getWasLockingChainSend() const
|
||||
{
|
||||
return this->tx_->at(sfWasLockingChainSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainAccountCreateCount() const
|
||||
{
|
||||
return this->tx_->at(sfXChainAccountCreateCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestination (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getDestination() const
|
||||
{
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainAddAccountCreateAttestation 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 XChainAddAccountCreateAttestationBuilder : public TransactionBuilderBase<XChainAddAccountCreateAttestationBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainAddAccountCreateAttestationBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param attestationSignerAccount The sfAttestationSignerAccount field value.
|
||||
* @param publicKey The sfPublicKey field value.
|
||||
* @param signature The sfSignature field value.
|
||||
* @param otherChainSource The sfOtherChainSource field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param attestationRewardAccount The sfAttestationRewardAccount field value.
|
||||
* @param wasLockingChainSend The sfWasLockingChainSend field value.
|
||||
* @param xChainAccountCreateCount The sfXChainAccountCreateCount field value.
|
||||
* @param destination The sfDestination field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_ACCOUNT::type::value_type> const& attestationSignerAccount, std::decay_t<typename SF_VL::type::value_type> const& publicKey, std::decay_t<typename SF_VL::type::value_type> const& signature, std::decay_t<typename SF_ACCOUNT::type::value_type> const& otherChainSource, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::decay_t<typename SF_ACCOUNT::type::value_type> const& attestationRewardAccount, std::decay_t<typename SF_UINT8::type::value_type> const& wasLockingChainSend, std::decay_t<typename SF_UINT64::type::value_type> const& xChainAccountCreateCount, std::decay_t<typename SF_ACCOUNT::type::value_type> const& destination, std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainAddAccountCreateAttestationBuilder>(ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setAttestationSignerAccount(attestationSignerAccount);
|
||||
setPublicKey(publicKey);
|
||||
setSignature(signature);
|
||||
setOtherChainSource(otherChainSource);
|
||||
setAmount(amount);
|
||||
setAttestationRewardAccount(attestationRewardAccount);
|
||||
setWasLockingChainSend(wasLockingChainSend);
|
||||
setXChainAccountCreateCount(xChainAccountCreateCount);
|
||||
setDestination(destination);
|
||||
setSignatureReward(signatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAddAccountCreateAttestationBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_ADD_ACCOUNT_CREATE_ATTESTATION)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAddAccountCreateAttestationBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAttestationSignerAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setAttestationSignerAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAttestationSignerAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPublicKey (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setPublicKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPublicKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignature (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setSignature(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignature] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainSource (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setOtherChainSource(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainSource] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAttestationRewardAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setAttestationRewardAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAttestationRewardAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfWasLockingChainSend (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setWasLockingChainSend(std::decay_t<typename SF_UINT8::type::value_type> const& value)
|
||||
{
|
||||
object_[sfWasLockingChainSend] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainAccountCreateCount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setXChainAccountCreateCount(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainAccountCreateCount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddAccountCreateAttestationBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainAddAccountCreateAttestation wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainAddAccountCreateAttestation
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainAddAccountCreateAttestation{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,360 +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 XChainAddClaimAttestationBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainAddClaimAttestation
|
||||
*
|
||||
* Type: ttXCHAIN_ADD_CLAIM_ATTESTATION (45)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: Privilege::CreateAcct
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainAddClaimAttestationBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainAddClaimAttestation : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_ADD_CLAIM_ATTESTATION;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAddClaimAttestation transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainAddClaimAttestation(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 XChainAddClaimAttestation");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAttestationSignerAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAttestationSignerAccount() const
|
||||
{
|
||||
return this->tx_->at(sfAttestationSignerAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfPublicKey (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getPublicKey() const
|
||||
{
|
||||
return this->tx_->at(sfPublicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignature (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_VL::type::value_type
|
||||
getSignature() const
|
||||
{
|
||||
return this->tx_->at(sfSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainSource (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOtherChainSource() const
|
||||
{
|
||||
return this->tx_->at(sfOtherChainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAttestationRewardAccount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getAttestationRewardAccount() const
|
||||
{
|
||||
return this->tx_->at(sfAttestationRewardAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfWasLockingChainSend (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT8::type::value_type
|
||||
getWasLockingChainSend() const
|
||||
{
|
||||
return this->tx_->at(sfWasLockingChainSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->tx_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfDestination (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getDestination() const
|
||||
{
|
||||
if (hasDestination())
|
||||
{
|
||||
return this->tx_->at(sfDestination);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfDestination is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasDestination() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfDestination);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainAddClaimAttestation 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 XChainAddClaimAttestationBuilder : public TransactionBuilderBase<XChainAddClaimAttestationBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainAddClaimAttestationBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param attestationSignerAccount The sfAttestationSignerAccount field value.
|
||||
* @param publicKey The sfPublicKey field value.
|
||||
* @param signature The sfSignature field value.
|
||||
* @param otherChainSource The sfOtherChainSource field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param attestationRewardAccount The sfAttestationRewardAccount field value.
|
||||
* @param wasLockingChainSend The sfWasLockingChainSend field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_ACCOUNT::type::value_type> const& attestationSignerAccount, std::decay_t<typename SF_VL::type::value_type> const& publicKey, std::decay_t<typename SF_VL::type::value_type> const& signature, std::decay_t<typename SF_ACCOUNT::type::value_type> const& otherChainSource, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::decay_t<typename SF_ACCOUNT::type::value_type> const& attestationRewardAccount, std::decay_t<typename SF_UINT8::type::value_type> const& wasLockingChainSend, std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainAddClaimAttestationBuilder>(ttXCHAIN_ADD_CLAIM_ATTESTATION, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setAttestationSignerAccount(attestationSignerAccount);
|
||||
setPublicKey(publicKey);
|
||||
setSignature(signature);
|
||||
setOtherChainSource(otherChainSource);
|
||||
setAmount(amount);
|
||||
setAttestationRewardAccount(attestationRewardAccount);
|
||||
setWasLockingChainSend(wasLockingChainSend);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainAddClaimAttestationBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_ADD_CLAIM_ATTESTATION)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainAddClaimAttestationBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAttestationSignerAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setAttestationSignerAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAttestationSignerAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfPublicKey (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setPublicKey(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfPublicKey] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignature (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setSignature(std::decay_t<typename SF_VL::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignature] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainSource (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setOtherChainSource(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainSource] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAttestationRewardAccount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setAttestationRewardAccount(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAttestationRewardAccount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfWasLockingChainSend (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setWasLockingChainSend(std::decay_t<typename SF_UINT8::type::value_type> const& value)
|
||||
{
|
||||
object_[sfWasLockingChainSend] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainAddClaimAttestationBuilder&
|
||||
setDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainAddClaimAttestation wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainAddClaimAttestation
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainAddClaimAttestation{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,240 +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 XChainClaimBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainClaim
|
||||
*
|
||||
* Type: ttXCHAIN_CLAIM (43)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: Privilege::NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainClaimBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainClaim : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_CLAIM;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainClaim transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainClaim(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 XChainClaim");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->tx_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainClaim 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 XChainClaimBuilder : public TransactionBuilderBase<XChainClaimBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainClaimBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param destination The sfDestination field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainClaimBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID, std::decay_t<typename SF_ACCOUNT::type::value_type> const& destination, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainClaimBuilder>(ttXCHAIN_CLAIM, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
setDestination(destination);
|
||||
setAmount(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainClaimBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainClaimBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_CLAIM)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainClaimBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfDestination (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
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.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setDestinationTag(std::decay_t<typename SF_UINT32::type::value_type> const& value)
|
||||
{
|
||||
object_[sfDestinationTag] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainClaimBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainClaim wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainClaim
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainClaim{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,216 +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 XChainCommitBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainCommit
|
||||
*
|
||||
* Type: ttXCHAIN_COMMIT (42)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: Privilege::NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainCommitBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainCommit : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_COMMIT;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCommit transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainCommit(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 XChainCommit");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainClaimID (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_UINT64::type::value_type
|
||||
getXChainClaimID() const
|
||||
{
|
||||
return this->tx_->at(sfXChainClaimID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfAmount (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getAmount() const
|
||||
{
|
||||
return this->tx_->at(sfAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainDestination (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_ACCOUNT::type::value_type>
|
||||
getOtherChainDestination() const
|
||||
{
|
||||
if (hasOtherChainDestination())
|
||||
{
|
||||
return this->tx_->at(sfOtherChainDestination);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfOtherChainDestination is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasOtherChainDestination() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfOtherChainDestination);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainCommit 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 XChainCommitBuilder : public TransactionBuilderBase<XChainCommitBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainCommitBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param xChainClaimID The sfXChainClaimID field value.
|
||||
* @param amount The sfAmount field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainCommitBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_UINT64::type::value_type> const& xChainClaimID, std::decay_t<typename SF_AMOUNT::type::value_type> const& amount, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainCommitBuilder>(ttXCHAIN_COMMIT, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setXChainClaimID(xChainClaimID);
|
||||
setAmount(amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCommitBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainCommitBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_COMMIT)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCommitBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCommitBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainClaimID (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCommitBuilder&
|
||||
setXChainClaimID(std::decay_t<typename SF_UINT64::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainClaimID] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfAmount (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCommitBuilder&
|
||||
setAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainDestination (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCommitBuilder&
|
||||
setOtherChainDestination(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainDestination] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainCommit wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainCommit
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainCommit{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,192 +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 XChainCreateBridgeBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainCreateBridge
|
||||
*
|
||||
* Type: ttXCHAIN_CREATE_BRIDGE (48)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: Privilege::NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainCreateBridgeBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainCreateBridge : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_CREATE_BRIDGE;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCreateBridge transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainCreateBridge(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 XChainCreateBridge");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getMinAccountCreateAmount() const
|
||||
{
|
||||
if (hasMinAccountCreateAmount())
|
||||
{
|
||||
return this->tx_->at(sfMinAccountCreateAmount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMinAccountCreateAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMinAccountCreateAmount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMinAccountCreateAmount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainCreateBridge 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 XChainCreateBridgeBuilder : public TransactionBuilderBase<XChainCreateBridgeBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainCreateBridgeBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainCreateBridgeBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainCreateBridgeBuilder>(ttXCHAIN_CREATE_BRIDGE, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setSignatureReward(signatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCreateBridgeBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainCreateBridgeBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_CREATE_BRIDGE)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCreateBridgeBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateBridgeBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateBridgeBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateBridgeBuilder&
|
||||
setMinAccountCreateAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMinAccountCreateAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainCreateBridge wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainCreateBridge
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainCreateBridge{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,179 +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 XChainCreateClaimIDBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainCreateClaimID
|
||||
*
|
||||
* Type: ttXCHAIN_CREATE_CLAIM_ID (41)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: Privilege::NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainCreateClaimIDBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainCreateClaimID : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_CREATE_CLAIM_ID;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCreateClaimID transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainCreateClaimID(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 XChainCreateClaimID");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_AMOUNT::type::value_type
|
||||
getSignatureReward() const
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfOtherChainSource (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_ACCOUNT::type::value_type
|
||||
getOtherChainSource() const
|
||||
{
|
||||
return this->tx_->at(sfOtherChainSource);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainCreateClaimID 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 XChainCreateClaimIDBuilder : public TransactionBuilderBase<XChainCreateClaimIDBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainCreateClaimIDBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param signatureReward The sfSignatureReward field value.
|
||||
* @param otherChainSource The sfOtherChainSource field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::decay_t<typename SF_AMOUNT::type::value_type> const& signatureReward, std::decay_t<typename SF_ACCOUNT::type::value_type> const& otherChainSource, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainCreateClaimIDBuilder>(ttXCHAIN_CREATE_CLAIM_ID, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
setSignatureReward(signatureReward);
|
||||
setOtherChainSource(otherChainSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainCreateClaimIDBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_CREATE_CLAIM_ID)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainCreateClaimIDBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfOtherChainSource (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainCreateClaimIDBuilder&
|
||||
setOtherChainSource(std::decay_t<typename SF_ACCOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfOtherChainSource] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainCreateClaimID wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainCreateClaimID
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainCreateClaimID{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
@@ -1,205 +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 XChainModifyBridgeBuilder;
|
||||
|
||||
/**
|
||||
* @brief Transaction: XChainModifyBridge
|
||||
*
|
||||
* Type: ttXCHAIN_MODIFY_BRIDGE (47)
|
||||
* Delegable: Delegation::Delegable
|
||||
* Amendment: featureXChainBridge
|
||||
* Privileges: Privilege::NoPriv
|
||||
*
|
||||
* Immutable wrapper around STTx providing type-safe field access.
|
||||
* Use XChainModifyBridgeBuilder to construct new transactions.
|
||||
*/
|
||||
class XChainModifyBridge : public TransactionBase
|
||||
{
|
||||
public:
|
||||
static constexpr xrpl::TxType txType = ttXCHAIN_MODIFY_BRIDGE;
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainModifyBridge transaction wrapper from an existing STTx object.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
explicit XChainModifyBridge(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 XChainModifyBridge");
|
||||
}
|
||||
}
|
||||
|
||||
// Transaction-specific field getters
|
||||
|
||||
/**
|
||||
* @brief Get sfXChainBridge (SoeRequired)
|
||||
* @return The field value.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
SF_XCHAIN_BRIDGE::type::value_type
|
||||
getXChainBridge() const
|
||||
{
|
||||
return this->tx_->at(sfXChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfSignatureReward (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getSignatureReward() const
|
||||
{
|
||||
if (hasSignatureReward())
|
||||
{
|
||||
return this->tx_->at(sfSignatureReward);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfSignatureReward is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasSignatureReward() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfSignatureReward);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
protocol_autogen::Optional<SF_AMOUNT::type::value_type>
|
||||
getMinAccountCreateAmount() const
|
||||
{
|
||||
if (hasMinAccountCreateAmount())
|
||||
{
|
||||
return this->tx_->at(sfMinAccountCreateAmount);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if sfMinAccountCreateAmount is present.
|
||||
* @return True if the field is present, false otherwise.
|
||||
*/
|
||||
[[nodiscard]]
|
||||
bool
|
||||
hasMinAccountCreateAmount() const
|
||||
{
|
||||
return this->tx_->isFieldPresent(sfMinAccountCreateAmount);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Builder for XChainModifyBridge 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 XChainModifyBridgeBuilder : public TransactionBuilderBase<XChainModifyBridgeBuilder>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new XChainModifyBridgeBuilder with required fields.
|
||||
* @param account The account initiating the transaction.
|
||||
* @param xChainBridge The sfXChainBridge field value.
|
||||
* @param sequence Optional sequence number for the transaction.
|
||||
* @param fee Optional fee for the transaction.
|
||||
*/
|
||||
XChainModifyBridgeBuilder(SF_ACCOUNT::type::value_type account,
|
||||
std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& xChainBridge, std::optional<SF_UINT32::type::value_type> sequence = std::nullopt,
|
||||
std::optional<SF_AMOUNT::type::value_type> fee = std::nullopt
|
||||
)
|
||||
: TransactionBuilderBase<XChainModifyBridgeBuilder>(ttXCHAIN_MODIFY_BRIDGE, account, sequence, fee)
|
||||
{
|
||||
setXChainBridge(xChainBridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Construct a XChainModifyBridgeBuilder from an existing STTx object.
|
||||
* @param tx The existing transaction to copy from.
|
||||
* @throws std::runtime_error if the transaction type doesn't match.
|
||||
*/
|
||||
XChainModifyBridgeBuilder(std::shared_ptr<STTx const> tx)
|
||||
{
|
||||
if (tx->getTxnType() != ttXCHAIN_MODIFY_BRIDGE)
|
||||
{
|
||||
throw std::runtime_error("Invalid transaction type for XChainModifyBridgeBuilder");
|
||||
}
|
||||
object_ = *tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transaction-specific field setters
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Set sfXChainBridge (SoeRequired)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainModifyBridgeBuilder&
|
||||
setXChainBridge(std::decay_t<typename SF_XCHAIN_BRIDGE::type::value_type> const& value)
|
||||
{
|
||||
object_[sfXChainBridge] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfSignatureReward (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainModifyBridgeBuilder&
|
||||
setSignatureReward(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfSignatureReward] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set sfMinAccountCreateAmount (SoeOptional)
|
||||
* @return Reference to this builder for method chaining.
|
||||
*/
|
||||
XChainModifyBridgeBuilder&
|
||||
setMinAccountCreateAmount(std::decay_t<typename SF_AMOUNT::type::value_type> const& value)
|
||||
{
|
||||
object_[sfMinAccountCreateAmount] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build and return the XChainModifyBridge wrapper.
|
||||
* @param publicKey The public key for signing.
|
||||
* @param secretKey The secret key for signing.
|
||||
* @return The constructed transaction wrapper.
|
||||
*/
|
||||
XChainModifyBridge
|
||||
build(PublicKey const& publicKey, SecretKey const& secretKey)
|
||||
{
|
||||
sign(publicKey, secretKey);
|
||||
return XChainModifyBridge{std::make_shared<STTx>(std::move(object_))};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace xrpl::transactions
|
||||
+250
-28
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <xrpl/basics/Blob.h>
|
||||
#include <xrpl/basics/IntrusivePointer.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/SHAMapHash.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
@@ -17,6 +18,7 @@
|
||||
#include <xrpl/shamap/SHAMapNodeID.h>
|
||||
#include <xrpl/shamap/SHAMapTreeNode.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@@ -40,7 +42,7 @@ class SHAMapSyncFilter;
|
||||
/**
|
||||
* Describes the current state of a given SHAMap
|
||||
*/
|
||||
enum class SHAMapState {
|
||||
enum class SHAMapState : std::uint8_t {
|
||||
/**
|
||||
* The map is in flux and objects can be added and removed.
|
||||
*
|
||||
@@ -120,16 +122,42 @@ private:
|
||||
*/
|
||||
std::uint32_t cowid_ = 1;
|
||||
|
||||
// ledgerSeq_, state_ and full_ are touched on the nodestore fetch path and on a
|
||||
// getMissingNodes() walk, neither of which may block, so pin them lock-free.
|
||||
static_assert(std::atomic<std::uint32_t>::is_always_lock_free);
|
||||
static_assert(std::atomic<SHAMapState>::is_always_lock_free);
|
||||
static_assert(std::atomic<bool>::is_always_lock_free);
|
||||
|
||||
/**
|
||||
* The sequence of the ledger that this map references, if any.
|
||||
*
|
||||
* Written when a map's ledger sequence is established (Ledger::setFull(),
|
||||
* InboundLedger) while a nodestore reader thread reads it. Relaxed either
|
||||
* way: it serves as a lookup hint for a nodestore keyed by hash.
|
||||
*/
|
||||
std::uint32_t ledgerSeq_ = 0;
|
||||
std::atomic<std::uint32_t> ledgerSeq_ = 0;
|
||||
|
||||
SHAMapTreeNodePtr root_;
|
||||
mutable SHAMapState state_;
|
||||
|
||||
/**
|
||||
* The map's state.
|
||||
*
|
||||
* A getMissingNodes() walk writes it, through setInvalid() and
|
||||
* clearSynching(), while whatever drives the acquisition reads it.
|
||||
* The walk runs with the acquisition's lock released, so this is atomic
|
||||
* rather than guarded.
|
||||
*/
|
||||
mutable std::atomic<SHAMapState> state_;
|
||||
SHAMapType const type_;
|
||||
bool backed_ = true; // Map is backed by the database
|
||||
mutable bool full_ = false; // Map is believed complete in database
|
||||
bool backed_ = true; // Map is backed by the database
|
||||
|
||||
/**
|
||||
* Map is believed complete in database.
|
||||
*
|
||||
* Atomic because finishFetch() clears it on any nodestore reader thread,
|
||||
* several of which can run at once.
|
||||
*/
|
||||
mutable std::atomic<bool> full_ = false;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -152,7 +180,14 @@ public:
|
||||
SHAMap&
|
||||
operator=(SHAMap const&) = delete;
|
||||
|
||||
// Take a snapshot of the given map:
|
||||
/**
|
||||
* Take a snapshot of the given map.
|
||||
*
|
||||
* @param other The map to snapshot. An Invalid source yields an Invalid
|
||||
* snapshot.
|
||||
* @param isMutable Whether the snapshot may be modified. Ignored when other
|
||||
* is Invalid.
|
||||
*/
|
||||
SHAMap(SHAMap const& other, bool isMutable);
|
||||
|
||||
// build new map
|
||||
@@ -190,17 +225,33 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Returns a new map that's a snapshot of this one.
|
||||
// Handles copy on write for mutable snapshots.
|
||||
/**
|
||||
* Return a new map that is a snapshot of this one.
|
||||
*
|
||||
* Handles copy on write for mutable snapshots. An invalid map yields an
|
||||
* invalid snapshot.
|
||||
*
|
||||
* @param isMutable Whether the snapshot may be modified.
|
||||
* @return The snapshot.
|
||||
*/
|
||||
std::shared_ptr<SHAMap>
|
||||
snapShot(bool isMutable) const;
|
||||
|
||||
/* Mark this SHAMap as "should be full", indicating
|
||||
that the local server wants all the corresponding nodes
|
||||
in durable storage.
|
||||
*/
|
||||
/**
|
||||
* Mark this map as "should be full": the local server wants every node
|
||||
* it references in durable storage, so a nodestore miss is a gap to report.
|
||||
*
|
||||
* Publishes the ledger sequence before the flag. The sequence store is
|
||||
* relaxed and the flag store is release, and finishFetch() reads the
|
||||
* sequence only after acquiring the flag, so the one miss that withdraws
|
||||
* the flag always reports the sequence stored here. Keeping both stores in
|
||||
* one place is what makes that order impossible to get wrong.
|
||||
*
|
||||
* @param ledgerSeq Sequence of the ledger this map belongs to, which the
|
||||
* gap report names.
|
||||
*/
|
||||
void
|
||||
setFull();
|
||||
setFull(std::uint32_t ledgerSeq);
|
||||
|
||||
void
|
||||
setLedgerSeq(std::uint32_t lseq);
|
||||
@@ -296,9 +347,13 @@ public:
|
||||
* concurrency, to discover nodes referenced in the
|
||||
* SHAMap but not available locally.
|
||||
*
|
||||
* Only a leaf may occupy a position at or beyond kLeafDepth. A map that
|
||||
* breaks that is marked Invalid and the traversal is abandoned, so callers
|
||||
* ask isValid() to tell an empty result from a satisfied map.
|
||||
*
|
||||
* @param maxNodes The maximum number of found nodes to return
|
||||
* @param filter The filter to use when retrieving nodes
|
||||
* @param return The nodes known to be missing
|
||||
* @return The nodes known to be missing, or empty if the map is Invalid
|
||||
*/
|
||||
std::vector<std::pair<SHAMapNodeID, UInt256>>
|
||||
getMissingNodes(int maxNodes, SHAMapSyncFilter const* filter);
|
||||
@@ -341,6 +396,9 @@ public:
|
||||
* This function is used when receiving the root node of a SHAMap from a peer during ledger
|
||||
* synchronization. The node must already have been deserialized.
|
||||
*
|
||||
* A root offered under a hash the map does not hold names another tree and
|
||||
* is reported as invalid data. A root matching that hash is a duplicate.
|
||||
*
|
||||
* @param hash The expected hash of the root node.
|
||||
* @param rootNode A deserialized root node to add.
|
||||
* @param filter Optional sync filter to track received nodes.
|
||||
@@ -360,6 +418,10 @@ public:
|
||||
* is inserted at the position specified by nodeID. The node must already have been
|
||||
* deserialized.
|
||||
*
|
||||
* A node that no valid tree can hold makes the map Invalid, which is
|
||||
* terminal: the root hash committed to an impossible shape, so no peer
|
||||
* can satisfy it.
|
||||
*
|
||||
* @param nodeID The position in the tree where this node belongs.
|
||||
* @param treeNode A deserialized tree node to add.
|
||||
* @param filter Optional sync filter to track received nodes.
|
||||
@@ -375,16 +437,57 @@ public:
|
||||
SHAMapTreeNodePtr treeNode,
|
||||
SHAMapSyncFilter const* filter);
|
||||
|
||||
// status functions
|
||||
void
|
||||
/**
|
||||
* Mark this map as immutable, so it can no longer be modified.
|
||||
*
|
||||
* @return false if the map is Invalid and was left unchanged, true
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
setImmutable();
|
||||
bool
|
||||
|
||||
/**
|
||||
* @return Whether the map is being synced against a hash it was given, so
|
||||
* its hash is fixed while nodes may still be added.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isSynching() const;
|
||||
|
||||
/**
|
||||
* @return Whether the map is settled, with its hash and nodes fixed.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isImmutable() const;
|
||||
|
||||
/**
|
||||
* Mark this map as syncing, fixing its hash while still allowing missing
|
||||
* nodes to be added.
|
||||
*
|
||||
* The map must be freshly constructed. The body asserts that the map is not
|
||||
* Invalid, so a caller that ignores the precondition stops a build with
|
||||
* assertions enabled.
|
||||
*/
|
||||
void
|
||||
setSynching();
|
||||
|
||||
/**
|
||||
* Mark this map as no longer syncing, so it can be modified again.
|
||||
*
|
||||
* Moves only a Synching map. An Immutable map stays settled, a Modifying
|
||||
* map has nothing to clear, and Invalid is terminal.
|
||||
*/
|
||||
void
|
||||
clearSynching();
|
||||
bool
|
||||
|
||||
/**
|
||||
* Whether the map can still be the map it claims to be.
|
||||
*
|
||||
* A map that is merely missing nodes is valid, and stays valid until
|
||||
* something proves the tree it is syncing against cannot exist.
|
||||
*
|
||||
* @return Whether the map has not been proven impossible.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isValid() const;
|
||||
|
||||
// caution: otherMap must be accessed only by this function
|
||||
@@ -524,6 +627,51 @@ private:
|
||||
using DeltaRef =
|
||||
std::pair<boost::intrusive_ptr<SHAMapItem const>, boost::intrusive_ptr<SHAMapItem const>>;
|
||||
|
||||
/**
|
||||
* The sequence of the ledger this map references, read atomically.
|
||||
*
|
||||
* @return The sequence, or zero if the map references no ledger.
|
||||
*/
|
||||
[[nodiscard]] std::uint32_t
|
||||
ledgerSeq() const;
|
||||
|
||||
/**
|
||||
* The current state, read atomically.
|
||||
*
|
||||
* Orders state_ alone. The tree's nodes carry no ordering guarantees.
|
||||
*
|
||||
* @return The state as of the call, which a concurrent walk may already
|
||||
* have moved past.
|
||||
*/
|
||||
[[nodiscard]] SHAMapState
|
||||
state() const;
|
||||
|
||||
/**
|
||||
* Record that the map is provably not the one it claims to be.
|
||||
*
|
||||
* Private because only the map itself can prove that, from a node that
|
||||
* contradicts the hashes it is syncing against. Cannot fail, since
|
||||
* Invalid outranks every other state; see trySetState().
|
||||
*/
|
||||
void
|
||||
setInvalid();
|
||||
|
||||
/**
|
||||
* Move the map to a new state, atomically.
|
||||
*
|
||||
* With clearSynching(), the only writer of state_ past construction, so
|
||||
* the order between the states lives in one place: Invalid outranks all
|
||||
* of them and is always stored, while every other transition is refused
|
||||
* once the map is Invalid, which is what makes that verdict terminal.
|
||||
* clearSynching() is narrower and moves only Synching.
|
||||
*
|
||||
* @param desired The state to move to.
|
||||
* @return false if the map is Invalid and the requested state is not,
|
||||
* leaving it unchanged; true otherwise.
|
||||
*/
|
||||
bool
|
||||
trySetState(SHAMapState desired);
|
||||
|
||||
// tree node cache operations
|
||||
SHAMapTreeNodePtr
|
||||
cacheLookup(SHAMapHash const& hash) const;
|
||||
@@ -739,46 +887,120 @@ private:
|
||||
};
|
||||
|
||||
inline void
|
||||
SHAMap::setFull()
|
||||
SHAMap::setFull(std::uint32_t ledgerSeq)
|
||||
{
|
||||
full_ = true;
|
||||
ledgerSeq_.store(ledgerSeq, std::memory_order_relaxed);
|
||||
full_.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
inline void
|
||||
SHAMap::setLedgerSeq(std::uint32_t lseq)
|
||||
{
|
||||
ledgerSeq_ = lseq;
|
||||
ledgerSeq_.store(lseq, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline void
|
||||
inline std::uint32_t
|
||||
SHAMap::ledgerSeq() const
|
||||
{
|
||||
return ledgerSeq_.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
inline SHAMapState
|
||||
SHAMap::state() const
|
||||
{
|
||||
return state_.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
inline bool
|
||||
SHAMap::trySetState(SHAMapState desired)
|
||||
{
|
||||
// Invalid is stored outright: a walk reaching that verdict has to win against a thread
|
||||
// settling the map.
|
||||
if (desired == SHAMapState::Invalid)
|
||||
{
|
||||
state_.store(SHAMapState::Invalid, std::memory_order_release);
|
||||
return true;
|
||||
}
|
||||
|
||||
// A failed exchange both reports the state and refreshes expected, so no load is needed
|
||||
// ahead of the loop.
|
||||
auto expected = SHAMapState::Modifying;
|
||||
while (expected != SHAMapState::Invalid)
|
||||
{
|
||||
if (state_.compare_exchange_weak(
|
||||
expected, desired, std::memory_order_acq_rel, std::memory_order_acquire))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
SHAMap::setImmutable()
|
||||
{
|
||||
XRPL_ASSERT(state_ != SHAMapState::Invalid, "xrpl::SHAMap::setImmutable : state is valid");
|
||||
state_ = SHAMapState::Immutable;
|
||||
SOMETIMES(!isValid(), "xrpl::SHAMap::setImmutable : map is invalid");
|
||||
return trySetState(SHAMapState::Immutable);
|
||||
}
|
||||
|
||||
inline bool
|
||||
SHAMap::isSynching() const
|
||||
{
|
||||
return state_ == SHAMapState::Synching;
|
||||
return state() == SHAMapState::Synching;
|
||||
}
|
||||
|
||||
inline bool
|
||||
SHAMap::isImmutable() const
|
||||
{
|
||||
return state() == SHAMapState::Immutable;
|
||||
}
|
||||
|
||||
inline void
|
||||
SHAMap::setSynching()
|
||||
{
|
||||
state_ = SHAMapState::Synching;
|
||||
// Guarded, so this is not a way out of Invalid.
|
||||
if (!trySetState(SHAMapState::Synching))
|
||||
{
|
||||
// Only ever called on a freshly constructed map.
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::SHAMap::setSynching : map is invalid");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
SHAMap::clearSynching()
|
||||
{
|
||||
state_ = SHAMapState::Modifying;
|
||||
// Only Synching moves. A walk can end after the ledger settled, and then the map stays
|
||||
// Immutable; a Modifying map has nothing to clear; an invalid map stays invalid. Only that
|
||||
// last refusal is logged, since a concurrent walk is what produces it.
|
||||
auto expected = SHAMapState::Synching;
|
||||
if (state_.compare_exchange_strong(
|
||||
expected, SHAMapState::Modifying, std::memory_order_acq_rel, std::memory_order_acquire))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool const invalid = expected == SHAMapState::Invalid;
|
||||
SOMETIMES(invalid, "xrpl::SHAMap::clearSynching : map is invalid");
|
||||
if (invalid)
|
||||
{
|
||||
JLOG(journal_.warn()) << "Refused to clear synching on an invalid map, root hash "
|
||||
<< root_->getHash();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
SHAMap::isValid() const
|
||||
{
|
||||
return state_ != SHAMapState::Invalid;
|
||||
return state() != SHAMapState::Invalid;
|
||||
}
|
||||
|
||||
inline void
|
||||
SHAMap::setInvalid()
|
||||
{
|
||||
// Through trySetState() like every other transition, so state_ has one writer funnel.
|
||||
trySetState(SHAMapState::Invalid);
|
||||
}
|
||||
|
||||
inline void
|
||||
|
||||
@@ -31,7 +31,19 @@ private:
|
||||
*/
|
||||
TaggedPointer hashesAndChildren_;
|
||||
|
||||
std::uint32_t fullBelowGen_ = 0;
|
||||
// Pin that wrapping fullBelowGen_ in an atomic keeps the packed layout, and that the load
|
||||
// isFullBelow() does once per node of every walk stays lock-free.
|
||||
static_assert(std::atomic<std::uint32_t>::is_always_lock_free);
|
||||
static_assert(sizeof(std::atomic<std::uint32_t>) == sizeof(std::uint32_t));
|
||||
static_assert(alignof(std::atomic<std::uint32_t>) == alignof(std::uint32_t));
|
||||
|
||||
/**
|
||||
* Written from more than one thread, since canonicalization shares a node
|
||||
* between maps and a walk can run with the acquisition lock released (see
|
||||
* SHAMap::state_). Relaxed both ways, since a generation is only compared
|
||||
* for equality and the children it vouches for are published through lock_.
|
||||
*/
|
||||
std::atomic<std::uint32_t> fullBelowGen_ = 0;
|
||||
std::uint16_t isBranch_ = 0;
|
||||
|
||||
/**
|
||||
@@ -204,13 +216,13 @@ SHAMapInnerNode::getBranchCount() const
|
||||
inline bool
|
||||
SHAMapInnerNode::isFullBelow(std::uint32_t generation) const
|
||||
{
|
||||
return fullBelowGen_ == generation;
|
||||
return fullBelowGen_.load(std::memory_order_relaxed) == generation;
|
||||
}
|
||||
|
||||
inline void
|
||||
SHAMapInnerNode::setFullBelowGen(std::uint32_t gen)
|
||||
{
|
||||
fullBelowGen_ = gen;
|
||||
fullBelowGen_.store(gen, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class ReadView;
|
||||
|
||||
/**
|
||||
* @brief Invariants for TransactionProposal ledger entries.
|
||||
*
|
||||
* - Only transaction types implementing proposal lifecycle operations may
|
||||
* create or modify proposals, and a failed one leaves no proposal effect.
|
||||
* - A proposal is deleted only by TransactionProposalCancel or together with
|
||||
* the Ticket it is keyed to, and a deleted Ticket takes the proposal keyed
|
||||
* to it along.
|
||||
* - Collected signer arrays remain sorted, unique, and bounded.
|
||||
*/
|
||||
class ValidTransactionProposal
|
||||
{
|
||||
// The Ticket each deleted proposal was keyed to; a proposal may go with
|
||||
// its Ticket, or by Cancel, and no other way.
|
||||
std::vector<uint256> ticketsOfDeletedProposals_;
|
||||
// The proposal each deleted Ticket was keyed to, whether or not one
|
||||
// existed; none may survive its Ticket.
|
||||
std::vector<Keylet> proposalsOfDeletedTickets_;
|
||||
std::set<uint256> deletedTickets_;
|
||||
std::uint32_t created_ = 0;
|
||||
std::uint32_t modified_ = 0;
|
||||
std::uint32_t deleted_ = 0;
|
||||
bool invalidSignerArrays_ = false;
|
||||
|
||||
public:
|
||||
void
|
||||
visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after);
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalize(STTx const& tx, TER result, XRPAmount, ReadView const& view, beast::Journal const& j)
|
||||
const;
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -1,12 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/invariants/AMMInvariant.h>
|
||||
#include <xrpl/tx/invariants/CosignerInvariant.h>
|
||||
#include <xrpl/tx/invariants/DirectoryInvariant.h>
|
||||
#include <xrpl/tx/invariants/FreezeInvariant.h>
|
||||
#include <xrpl/tx/invariants/LoanBrokerInvariant.h>
|
||||
@@ -21,6 +24,7 @@
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
@@ -363,11 +367,27 @@ public:
|
||||
* unique to pseudo-accounts. Check that all pseudo-accounts are following the
|
||||
* rules, and that only pseudo-accounts look like pseudo-accounts.
|
||||
*
|
||||
* Post-fixCleanup3_5_0, a pseudo-account also owns only entries that belong
|
||||
* to its own AMM, Vault or LoanBroker:
|
||||
* - AMM: its AMM entry, its holdings of the two pool assets, and the trust
|
||||
* lines of its LP token,
|
||||
* - Vault: its share MPTokenIssuance, its holding of the vault asset, and the
|
||||
* LoanBrokers operating on this vault,
|
||||
* - LoanBroker: its Loans and its holding of the vault asset (the cover).
|
||||
*
|
||||
* A pseudo-account cannot sign transactions, so it could never accept or
|
||||
* remove any other object linked into its owner directory. Such an object
|
||||
* would pin the directory and block deletion of the owning object.
|
||||
*/
|
||||
class ValidPseudoAccounts
|
||||
{
|
||||
std::vector<std::string> errors_;
|
||||
|
||||
// Entries newly linked into owner directories, keyed by the directory
|
||||
// owner. Whether an owner is a pseudo-account is decided in finalize,
|
||||
// where the view is available.
|
||||
std::map<AccountID, std::vector<uint256>> ownerDirAdditions_;
|
||||
|
||||
public:
|
||||
void
|
||||
visitEntry(bool, SLE::ConstRef, SLE::ConstRef);
|
||||
@@ -464,6 +484,7 @@ using InvariantChecks = std::tuple<
|
||||
ValidAmounts,
|
||||
ValidMPTTransfer,
|
||||
ObjectHasPseudoAccount,
|
||||
ValidTransactionProposal,
|
||||
SponsorshipOwnerCountsMatch,
|
||||
SponsorshipAccountCountMatchesField>;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/Rules.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
@@ -29,7 +30,7 @@ namespace xrpl {
|
||||
* - vault must have MPTokenIssuance for shares
|
||||
* - vault without shares outstanding must have no shares
|
||||
* - loss unrealized does not exceed the difference between assets total and
|
||||
* assets available
|
||||
* assets available (Legacy/CashBasis), or AssetsDeployed (FixedPrecision)
|
||||
* - assets available do not exceed assets total
|
||||
* - vault deposit increases assets and share issuance, and adds to:
|
||||
* total assets, assets available, shares outstanding
|
||||
@@ -46,6 +47,14 @@ namespace xrpl {
|
||||
* - vault withdrawal may not succeed when the vault phase is Investment
|
||||
* - closed-ended loan origination (ttLOAN_SET) may only succeed when the
|
||||
* vault phase is Investment
|
||||
* - FixedPrecision only: AssetsDeployed is non-negative and exactly
|
||||
* representable at the asset's precision; AssetsDeployed changes only for
|
||||
* ttLOAN_SET, ttLOAN_PAY and ttLOAN_MANAGE; AssetsDeployed is zero right
|
||||
* after ttVAULT_CREATE and whenever shares outstanding return to zero; the
|
||||
* stored AssetsTotal cache equals AssetsAvailable + AssetsDeployed, rounded
|
||||
* Downward to the asset's precision
|
||||
* - FixedPrecision only: YieldUnrealized is non-negative; YieldUnrealized
|
||||
* changes only for ttLOAN_SET, ttLOAN_PAY and ttLOAN_MANAGE
|
||||
*
|
||||
* Immutability of VaultKind, SubscriptionDate and RedemptionDate is enforced
|
||||
* by NoModifiedUnmodifiableFields (see InvariantCheck.cpp). From
|
||||
@@ -68,6 +77,9 @@ class ValidVault
|
||||
Number assetsAvailable = 0;
|
||||
Number assetsMaximum = 0;
|
||||
Number lossUnrealized = 0;
|
||||
Number assetsDeployed = 0;
|
||||
Number yieldUnrealized = 0;
|
||||
VaultVersion version = VaultVersion::Legacy;
|
||||
std::optional<std::uint8_t> vaultKind;
|
||||
std::optional<std::uint32_t> subscriptionDate;
|
||||
std::optional<std::uint32_t> redemptionDate;
|
||||
@@ -217,6 +229,39 @@ private:
|
||||
[[nodiscard]] bool
|
||||
finalizeLoanSet(ReadView const& view, beast::Journal const& j) const;
|
||||
|
||||
/**
|
||||
* @brief Check that a vault's AssetsTotal and AssetsAvailable deltas add
|
||||
* up against the real transfer, for deposit/withdraw/clawback.
|
||||
*
|
||||
* Shared body of the ttVAULT_DEPOSIT, ttVAULT_WITHDRAW and
|
||||
* ttVAULT_CLAWBACK "assets outstanding"/"assets available" add-up checks,
|
||||
* which differ only in the rounded/exact deltas plugged in and the verb
|
||||
* used in the log message.
|
||||
*
|
||||
* @param afterVault Snapshot of the vault after the transaction.
|
||||
* @param beforeVault Snapshot of the vault before the transaction.
|
||||
* @param vaultAsset The vault's underlying asset.
|
||||
* @param fix340Enabled Whether fixCleanup3_4_0 is enabled.
|
||||
* @param minScale The posterior scale computed by computeVaultMinScale.
|
||||
* @param roundedVaultDelta The real transfer's delta, rounded to minScale.
|
||||
* @param exactVaultDelta The real transfer's exact (unrounded) delta.
|
||||
* @param verb The transaction name used in the log message ("deposit",
|
||||
* "withdrawal" or "clawback").
|
||||
* @param j Journal for logging.
|
||||
* @return false if either add-up check fails.
|
||||
*/
|
||||
[[nodiscard]] static bool
|
||||
checkTotalsAddUp(
|
||||
Vault const& afterVault,
|
||||
Vault const& beforeVault,
|
||||
Asset const& vaultAsset,
|
||||
bool fix340Enabled,
|
||||
std::int32_t minScale,
|
||||
Number const& roundedVaultDelta,
|
||||
Number const& exactVaultDelta,
|
||||
char const* verb,
|
||||
beast::Journal const& j);
|
||||
|
||||
public:
|
||||
// Compute the coarsest scale required to represent all numbers
|
||||
[[nodiscard]] static std::int32_t
|
||||
|
||||
@@ -818,13 +818,10 @@ flow(
|
||||
* TakerPays. We reverse pays and gets because during crossing
|
||||
* we are taking, therefore the owner must deliver the full TakerPays and
|
||||
* the entire TakerGets doesn't have to be spent.
|
||||
* Pre-fixFillOrKill amendment code fails if the entire TakerGets
|
||||
* is not spent. fixFillOrKill addresses this issue.
|
||||
* 2. If tfSell is also set then the owner must spend the entire TakerGets
|
||||
* even if it means obtaining more than TakerPays. Since the pays and gets
|
||||
* are reversed, the owner must send the entire TakerGets.
|
||||
*/
|
||||
bool const fillOrKillEnabled = baseView.rules().enabled(fixFillOrKill);
|
||||
|
||||
if (actualOut != outReq)
|
||||
{
|
||||
@@ -840,13 +837,9 @@ flow(
|
||||
}
|
||||
if (!partialPayment)
|
||||
{
|
||||
// If we're offerCrossing a !partialPayment, then we're handling tfFillOrKill.
|
||||
// Pre-fixFillOrKill amendment:
|
||||
// That case is handled below; not here.
|
||||
// fixFillOrKill amendment:
|
||||
// That case is handled here if tfSell is also not set; i.e, case 1.
|
||||
if (offerCrossing == OfferCrossing::No ||
|
||||
(fillOrKillEnabled && offerCrossing != OfferCrossing::Sell))
|
||||
// If partialPayment is false, the caller requires full outReq (payments, or FillOrKill
|
||||
// offers).
|
||||
if (offerCrossing != OfferCrossing::Sell)
|
||||
{
|
||||
return {tecPATH_PARTIAL, actualIn, actualOut, std::move(ofrsToRmOnFail)};
|
||||
}
|
||||
@@ -856,16 +849,10 @@ flow(
|
||||
return {tecPATH_DRY, std::move(ofrsToRmOnFail)};
|
||||
}
|
||||
}
|
||||
if (offerCrossing != OfferCrossing::No &&
|
||||
(!partialPayment && (!fillOrKillEnabled || offerCrossing == OfferCrossing::Sell)))
|
||||
if (!partialPayment && offerCrossing == OfferCrossing::Sell)
|
||||
{
|
||||
// If we're offer crossing and partialPayment is *not* true, then
|
||||
// we're handling a FillOrKill offer. In this case remainingIn must
|
||||
// be zero (all funds must be consumed) or else we kill the offer.
|
||||
// Pre-fixFillOrKill amendment:
|
||||
// Handles both cases 1. and 2.
|
||||
// fixFillOrKill amendment:
|
||||
// Handles 2. 1. is handled above and falls through for tfSell.
|
||||
// we're handling a FillOrKill offer.
|
||||
XRPL_ASSERT(remainingIn, "xrpl::flow : nonzero remainingIn");
|
||||
if (remainingIn && *remainingIn != beast::kZero)
|
||||
return {tecPATH_PARTIAL, actualIn, actualOut, std::move(ofrsToRmOnFail)};
|
||||
|
||||
@@ -1,336 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
#include <xrpl/tx/ApplyContext.h>
|
||||
#include <xrpl/tx/Transactor.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
constexpr size_t kXbridgeMaxAccountCreateClaims = 128;
|
||||
|
||||
// Attach a new bridge to a door account. Once this is done, the cross-chain
|
||||
// transfer transactions may be used to transfer funds from this account.
|
||||
class XChainCreateBridge : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit XChainCreateBridge(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
class BridgeModify : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit BridgeModify(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static std::uint32_t
|
||||
getFlagsMask(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
using XChainModifyBridge = BridgeModify;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Claim funds from a `XChainCommit` transaction. This is normally not needed,
|
||||
// but may be used to handle transaction failures or if the destination account
|
||||
// was not specified in the `XChainCommit` transaction. It may only be used
|
||||
// after a quorum of signatures have been sent from the witness servers.
|
||||
//
|
||||
// If the transaction succeeds in moving funds, the referenced `XChainClaimID`
|
||||
// ledger object will be destroyed. This prevents transaction replay. If the
|
||||
// transaction fails, the `XChainClaimID` will not be destroyed and the
|
||||
// transaction may be re-run with different parameters.
|
||||
class XChainClaim : public Transactor
|
||||
{
|
||||
public:
|
||||
// Blocker since we cannot accurately calculate the consequences
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker;
|
||||
|
||||
explicit XChainClaim(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Put assets into trust on the locking-chain so they may be wrapped on the
|
||||
// issuing-chain, or return wrapped assets on the issuing-chain so they can be
|
||||
// unlocked on the locking-chain. The second step in a cross-chain transfer.
|
||||
class XChainCommit : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Custom;
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
explicit XChainCommit(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Create a new claim id owned by the account. This is the first step in a
|
||||
// cross-chain transfer. The claim id must be created on the destination chain
|
||||
// before the `XChainCommit` transaction (which must reference this number) can
|
||||
// be sent on the source chain. The account that will send the `XChainCommit` on
|
||||
// the source chain must be specified in this transaction (see note on the
|
||||
// `SourceAccount` field in the `XChainClaimID` ledger object for
|
||||
// justification). The actual sequence number must be retrieved from a validated
|
||||
// ledger.
|
||||
class XChainCreateClaimID : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit XChainCreateClaimID(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Provide attestations from a witness server attesting to events on
|
||||
// the other chain. The signatures must be from one of the keys on the door's
|
||||
// signer's list at the time the signature was provided. However, if the
|
||||
// signature list changes between the time the signature was submitted and the
|
||||
// quorum is reached, the new signature set is used and some of the currently
|
||||
// collected signatures may be removed. Also note the reward is only sent to
|
||||
// accounts that have keys on the current list.
|
||||
class XChainAddClaimAttestation : public Transactor
|
||||
{
|
||||
public:
|
||||
// Blocker since we cannot accurately calculate the consequences
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker;
|
||||
|
||||
explicit XChainAddClaimAttestation(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
class XChainAddAccountCreateAttestation : public Transactor
|
||||
{
|
||||
public:
|
||||
// Blocker since we cannot accurately calculate the consequences
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Blocker;
|
||||
|
||||
explicit XChainAddAccountCreateAttestation(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// This is a special transaction used for creating accounts through a
|
||||
// cross-chain transfer. A normal cross-chain transfer requires a "chain claim
|
||||
// id" (which requires an existing account on the destination chain). One
|
||||
// purpose of the "chain claim id" is to prevent transaction replay. For this
|
||||
// transaction, we use a different mechanism: the accounts must be claimed on
|
||||
// the destination chain in the same order that the `XChainCreateAccountCommit`
|
||||
// transactions occurred on the source chain.
|
||||
//
|
||||
// This transaction can only be used for XRP to XRP bridges.
|
||||
//
|
||||
// IMPORTANT: This transaction should only be enabled if the witness
|
||||
// attestations will be reliably delivered to the destination chain. If the
|
||||
// signatures are not delivered (for example, the chain relies on user wallets
|
||||
// to collect signatures) then account creation would be blocked for all
|
||||
// transactions that happened after the one waiting on attestations. This could
|
||||
// be used maliciously. To disable this transaction on XRP to XRP bridges, the
|
||||
// bridge's `MinAccountCreateAmount` should not be present.
|
||||
//
|
||||
// Note: If this account already exists, the XRP is transferred to the existing
|
||||
// account. However, note that unlike the `XChainCommit` transaction, there is
|
||||
// no error handling mechanism. If the claim transaction fails, there is no
|
||||
// mechanism for refunds. The funds are permanently lost. This transaction
|
||||
// should still only be used for account creation.
|
||||
class XChainCreateAccountCommit : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr auto kConsequencesFactory = ConsequencesFactoryType::Normal;
|
||||
|
||||
explicit XChainCreateAccountCommit(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
|
||||
void
|
||||
visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override;
|
||||
|
||||
[[nodiscard]] bool
|
||||
finalizeInvariants(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount fee,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) override;
|
||||
};
|
||||
|
||||
using XChainAccountCreateCommit = XChainCreateAccountCommit;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -20,11 +20,14 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static bool
|
||||
checkExtraFeatures(PreflightContext const& ctx);
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
@@ -45,9 +46,29 @@ public:
|
||||
SLE::Ref loanSle,
|
||||
SLE::Ref brokerSle,
|
||||
SLE::Ref vaultSle,
|
||||
Asset const& vaultAsset,
|
||||
beast::Journal j);
|
||||
|
||||
/**
|
||||
* @brief Compute the First-Loss Capital cover amount for a defaulted Loan on a FixedPrecision
|
||||
* Vault, capped at the LoanBroker's CoverAvailable and floored so that AssetsAvailable + cover
|
||||
* is exactly on its posterior grid.
|
||||
*
|
||||
* The LoanBroker absorbs the rounding. When CoverAvailable - cover needs finer digits than the
|
||||
* broker's posterior grid, it rounds to nearest, as the broker's trust line does, so
|
||||
* CoverAvailable can move by up to half a posterior ulp more or less than the cover. When the
|
||||
* two grids differ, no cover is exact on both sides; the Vault side is kept exact.
|
||||
*
|
||||
* The one exception: when AssetsAvailable has digits finer than the 16-digit cover can carry,
|
||||
* no cover cancels them, and the balance writer rounds AssetsAvailable + cover to nearest,
|
||||
* by at most half a posterior ulp. VaultDeposit and LoanPay credits have the same limit.
|
||||
* @param loanSle The Loan being defaulted.
|
||||
* @param brokerSle The Loan's LoanBroker.
|
||||
* @param vaultSle The LoanBroker's Vault.
|
||||
* @return The cover amount, in the Vault's Asset.
|
||||
*/
|
||||
static STAmount
|
||||
calculateDefaultCover(SLE::Ref loanSle, SLE::Ref brokerSle, SLE::Ref vaultSle);
|
||||
|
||||
/**
|
||||
* Helper function that might be needed by other transactors
|
||||
*/
|
||||
|
||||
@@ -52,6 +52,13 @@ private:
|
||||
TER
|
||||
applyFee();
|
||||
|
||||
/**
|
||||
* Write the default Feature Extension fee settings into FeeSettings on
|
||||
* `featureSmartEscrow` activation.
|
||||
*/
|
||||
void
|
||||
initializeVMFees();
|
||||
|
||||
TER
|
||||
applyUNLModify();
|
||||
};
|
||||
|
||||
@@ -200,11 +200,23 @@ Ledger::Ledger(
|
||||
sle->at(sfReserveIncrement) = *f;
|
||||
sle->at(sfReferenceFeeUnits) = kFeeUnitsDeprecated;
|
||||
}
|
||||
if (std::ranges::find(amendments, featureSmartEscrow) != amendments.end())
|
||||
{
|
||||
sle->at(sfGasLimit) = fees.gasLimit;
|
||||
sle->at(sfBytecodeSizeLimit) = fees.bytecodeSizeLimit;
|
||||
sle->at(sfGasPrice) = fees.gasPrice;
|
||||
}
|
||||
rawInsert(sle);
|
||||
}
|
||||
|
||||
stateMap_.flushDirty(NodeObjectType::AccountNode);
|
||||
setImmutable();
|
||||
// Built locally. See Ledger::setImmutable().
|
||||
if (!setImmutable())
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
logicError("Ledger::Ledger(CreateGenesisT, ...): genesis ledger map is invalid");
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
|
||||
Ledger::Ledger(
|
||||
@@ -215,7 +227,7 @@ Ledger::Ledger(
|
||||
Fees const& fees,
|
||||
Family& family,
|
||||
beast::Journal j)
|
||||
: immutable_(true)
|
||||
: immutable_(false)
|
||||
, txMap_(SHAMapType::TRANSACTION, info.txHash, family)
|
||||
, stateMap_(SHAMapType::STATE, info.accountHash, family)
|
||||
, fees_(fees)
|
||||
@@ -238,8 +250,20 @@ Ledger::Ledger(
|
||||
JLOG(j.warn()) << "Don't have state data root for ledger" << header_.seq;
|
||||
}
|
||||
|
||||
txMap_.setImmutable();
|
||||
stateMap_.setImmutable();
|
||||
// Loaded locally. See Ledger::setImmutable().
|
||||
if (setMapsImmutable())
|
||||
{
|
||||
immutable_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.error()) << "Invalid map for ledger " << header_.seq;
|
||||
UNREACHABLE("xrpl::Ledger::Ledger(LedgerHeader const&, ...) : map is invalid");
|
||||
// Treat it as a damaged ledger: the code below recomputes the hash and re-acquires.
|
||||
loaded = false;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
if (!setup())
|
||||
loaded = false;
|
||||
@@ -310,27 +334,50 @@ Ledger::Ledger(
|
||||
setup();
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
Ledger::setImmutable(bool rehash)
|
||||
{
|
||||
// Force update, since this is the only
|
||||
// place the hash transitions to valid
|
||||
if (!immutable_ && rehash)
|
||||
// A map found structurally invalid during sync must never be made immutable: isValid() tests
|
||||
// only for Invalid, and an immutable ledger is treated as persistable. Asked before anything is
|
||||
// written, so a refusal leaves the header exactly as it was rather than half relabeled.
|
||||
if (!mapsValid())
|
||||
return false;
|
||||
|
||||
// Read here but written to the header below, once the maps are settled: getHash() can unshare a
|
||||
// dirty tree, so it has to run while the map is still mutable, while a write to the header must
|
||||
// wait until both maps have made it. Skipped once the ledger is immutable, since its maps can
|
||||
// no longer change.
|
||||
bool const deriveMapHashes = !immutable_ && rehash;
|
||||
UInt256 const txHash = deriveMapHashes ? txMap_.getHash().asUInt256() : UInt256{};
|
||||
UInt256 const accountHash = deriveMapHashes ? stateMap_.getHash().asUInt256() : UInt256{};
|
||||
|
||||
// Both were valid at the check above, but a concurrent walk can invalidate one in between (see
|
||||
// SHAMap::state_), so the result is checked. setInvalid() outranks Immutable and can land
|
||||
// after both maps have been settled, so this narrows the window it guards.
|
||||
bool const bothImmutable = setMapsImmutable();
|
||||
SOMETIMES(!bothImmutable, "xrpl::Ledger::setImmutable : map invalidated while going immutable");
|
||||
if (!bothImmutable)
|
||||
return false;
|
||||
|
||||
// Written only now, so losing the race above leaves the header describing what the ledger was
|
||||
// built from rather than a map that has since been abandoned. Forced rather than conditional,
|
||||
// since this is the only place the hash transitions to valid.
|
||||
if (deriveMapHashes)
|
||||
{
|
||||
header_.txHash = txMap_.getHash().asUInt256();
|
||||
header_.accountHash = stateMap_.getHash().asUInt256();
|
||||
header_.txHash = txHash;
|
||||
header_.accountHash = accountHash;
|
||||
}
|
||||
|
||||
if (rehash)
|
||||
header_.hash = calculateLedgerHash(header_);
|
||||
|
||||
// Set last, so isImmutable() reports only a ledger whose maps are both immutable.
|
||||
immutable_ = true;
|
||||
txMap_.setImmutable();
|
||||
stateMap_.setImmutable();
|
||||
setup();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
Ledger::setAccepted(
|
||||
NetClock::time_point closeTime,
|
||||
NetClock::duration closeResolution,
|
||||
@@ -342,7 +389,17 @@ Ledger::setAccepted(
|
||||
header_.closeTime = closeTime;
|
||||
header_.closeTimeResolution = closeResolution;
|
||||
header_.closeFlags = correctCloseTime ? 0 : kSLcfNoConsensusTime;
|
||||
setImmutable();
|
||||
// Built locally. See Ledger::setImmutable().
|
||||
if (!setImmutable())
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j_.error()) << "Invalid map for accepted ledger " << header_.seq;
|
||||
UNREACHABLE("xrpl::Ledger::setAccepted : map is invalid");
|
||||
return false;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -566,6 +623,7 @@ Ledger::setup()
|
||||
{
|
||||
bool oldFees = false;
|
||||
bool newFees = false;
|
||||
bool extensionFees = false;
|
||||
{
|
||||
auto const baseFee = sle->at(~sfBaseFee);
|
||||
auto const reserveBase = sle->at(~sfReserveBase);
|
||||
@@ -600,6 +658,20 @@ Ledger::setup()
|
||||
assign(fees_.increment, reserveIncrementXRP);
|
||||
newFees = baseFeeXRP || reserveBaseXRP || reserveIncrementXRP;
|
||||
}
|
||||
{
|
||||
auto const gasLimit = sle->at(~sfGasLimit);
|
||||
auto const bytecodeSizeLimit = sle->at(~sfBytecodeSizeLimit);
|
||||
auto const gasPrice = sle->at(~sfGasPrice);
|
||||
|
||||
// An absent field resolves to the protocol constant.
|
||||
if (rules_.enabled(featureSmartEscrow))
|
||||
{
|
||||
fees_.gasLimit = gasLimit.value_or(kDefaultGasLimit);
|
||||
fees_.bytecodeSizeLimit = bytecodeSizeLimit.value_or(kDefaultBytecodeSizeLimit);
|
||||
fees_.gasPrice = gasPrice.value_or(kDefaultGasPrice);
|
||||
}
|
||||
extensionFees = gasLimit || bytecodeSizeLimit || gasPrice;
|
||||
}
|
||||
if (oldFees && newFees)
|
||||
{
|
||||
// Should be all of one or the other, but not both
|
||||
@@ -610,6 +682,12 @@ Ledger::setup()
|
||||
// Can't populate the new fees before the amendment is enabled
|
||||
ret = false;
|
||||
}
|
||||
if (!rules_.enabled(featureSmartEscrow) && extensionFees)
|
||||
{
|
||||
// Can't populate the extension fees before the amendment is
|
||||
// enabled
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SHAMapMissingNode const&)
|
||||
|
||||
@@ -511,9 +511,14 @@ doWithdraw(
|
||||
AccountID const& dstAcct,
|
||||
AccountID const& sourceAcct,
|
||||
XRPAmount priorBalance,
|
||||
STAmount const& amount,
|
||||
STAmount const& destinationAmount,
|
||||
STAmount const& sourceAmount,
|
||||
beast::Journal j)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
destinationAmount.asset() == sourceAmount.asset(),
|
||||
"xrpl::doWithdraw : delivered and source amounts use the same asset");
|
||||
|
||||
auto const dstSle = ctx.view.read(keylet::account(dstAcct));
|
||||
|
||||
// Create a trust line or MPToken for a self-destination only when there
|
||||
@@ -523,9 +528,10 @@ doWithdraw(
|
||||
// create+delete MPTokens in the same transaction.
|
||||
if (dstAcct == senderAcct)
|
||||
{
|
||||
if (amount > beast::kZero || !ctx.view.rules().enabled(fixCleanup3_4_0))
|
||||
if (destinationAmount > beast::kZero || !ctx.view.rules().enabled(fixCleanup3_4_0))
|
||||
{
|
||||
if (auto const ter = addEmptyHolding(ctx, senderAcct, priorBalance, amount.asset(), j);
|
||||
if (auto const ter =
|
||||
addEmptyHolding(ctx, senderAcct, priorBalance, destinationAmount.asset(), j);
|
||||
!isTesSuccess(ter) && ter != tecDUPLICATE)
|
||||
return ter;
|
||||
}
|
||||
@@ -540,17 +546,33 @@ doWithdraw(
|
||||
if (accountHolds(
|
||||
ctx.view,
|
||||
sourceAcct,
|
||||
amount.asset(),
|
||||
destinationAmount.asset(),
|
||||
FreezeHandling::IgnoreFreeze,
|
||||
AuthHandling::IgnoreAuth,
|
||||
j) < amount)
|
||||
j) < sourceAmount)
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
JLOG(j.error()) << "doWithdraw: negative balance of broker cover assets.";
|
||||
JLOG(j.error()) << "doWithdraw: source account holds fewer assets than the withdrawal.";
|
||||
return tefINTERNAL;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
// A transfer fee applies. Redeem the gross amount with the issuer, then
|
||||
// issue the net amount to the destination.
|
||||
if (sourceAmount != destinationAmount)
|
||||
{
|
||||
auto const issuer = destinationAmount.getIssuer();
|
||||
XRPL_ASSERT(
|
||||
!destinationAmount.native() && sourceAcct != issuer && dstAcct != issuer,
|
||||
"xrpl::doWithdraw : transfer fee applies between token holders");
|
||||
|
||||
if (auto const ter = directSendNoFee(ctx.view, sourceAcct, issuer, sourceAmount, false, j);
|
||||
!isTesSuccess(ter))
|
||||
return ter; // LCOV_EXCL_LINE
|
||||
|
||||
return directSendNoFee(ctx.view, issuer, dstAcct, destinationAmount, false, j);
|
||||
}
|
||||
|
||||
// A reserve sponsor only covers tx.Account's own objects, so resolve the
|
||||
// sponsor against the destination. accountSend can auto-create a holding
|
||||
// for dstAcct; keying on the destination ensures a third-party destination's
|
||||
@@ -562,7 +584,7 @@ doWithdraw(
|
||||
// Move the funds directly from the broker's pseudo-account to the
|
||||
// dstAcct
|
||||
return accountSend(
|
||||
ctx.view, sourceAcct, dstAcct, amount, j, *sponsorSle, WaiveTransferFee::Yes);
|
||||
ctx.view, sourceAcct, dstAcct, destinationAmount, j, *sponsorSle, WaiveTransferFee::Yes);
|
||||
}
|
||||
|
||||
TER
|
||||
|
||||
@@ -66,6 +66,161 @@ canApplyToBrokerCover(
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
[[nodiscard]] int
|
||||
getPosteriorBrokerCoverScale(SLE::ConstRef vault, SLE::ConstRef broker, Number const& delta)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
vault && vault->getType() == ltVAULT,
|
||||
"xrpl::detail::getPosteriorBrokerCoverScale : valid Vault sle");
|
||||
XRPL_ASSERT(
|
||||
broker && broker->getType() == ltLOAN_BROKER,
|
||||
"xrpl::detail::getPosteriorBrokerCoverScale : valid LoanBroker sle");
|
||||
|
||||
return posteriorAssetScale(
|
||||
getVaultVersion(vault),
|
||||
vault->at(sfAsset),
|
||||
getVaultBaseScale(vault),
|
||||
broker->at(sfCoverAvailable),
|
||||
delta);
|
||||
}
|
||||
|
||||
[[nodiscard]] STAmount
|
||||
roundToPosteriorBrokerCoverScale(
|
||||
SLE::ConstRef vault,
|
||||
SLE::ConstRef broker,
|
||||
STAmount const& delta,
|
||||
Number::RoundingMode roundingMode)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
vault && vault->getType() == ltVAULT,
|
||||
"xrpl::detail::roundToPosteriorBrokerCoverScale : valid Vault sle");
|
||||
XRPL_ASSERT(
|
||||
broker && broker->getType() == ltLOAN_BROKER,
|
||||
"xrpl::detail::roundToPosteriorBrokerCoverScale : valid LoanBroker sle");
|
||||
XRPL_ASSERT(
|
||||
delta.asset() == vault->at(sfAsset),
|
||||
"xrpl::detail::roundToPosteriorBrokerCoverScale : delta and Vault asset match");
|
||||
if (delta.integral())
|
||||
return delta;
|
||||
return roundToScale(delta, getPosteriorBrokerCoverScale(vault, broker, delta), roundingMode);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
[[nodiscard]] STAmount
|
||||
creditToPosteriorBrokerCoverScale(
|
||||
SLE::ConstRef vault,
|
||||
SLE::ConstRef broker,
|
||||
Number const& raw,
|
||||
Number::RoundingMode roundingMode)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
vault && vault->getType() == ltVAULT,
|
||||
"xrpl::creditToPosteriorBrokerCoverScale : valid Vault sle");
|
||||
XRPL_ASSERT(
|
||||
broker && broker->getType() == ltLOAN_BROKER,
|
||||
"xrpl::creditToPosteriorBrokerCoverScale : valid LoanBroker sle");
|
||||
Asset const asset = vault->at(sfAsset);
|
||||
if (asset.integral())
|
||||
{
|
||||
NumberRoundModeGuard const rg(roundingMode);
|
||||
return STAmount{asset, raw};
|
||||
}
|
||||
|
||||
Number const reference = broker->at(sfCoverAvailable);
|
||||
return detail::creditToPosteriorScale(
|
||||
asset, reference, getVaultBaseScale(vault), raw, roundingMode);
|
||||
}
|
||||
|
||||
[[nodiscard]] STAmount
|
||||
debitToPosteriorBrokerCoverScale(
|
||||
SLE::ConstRef vault,
|
||||
SLE::ConstRef broker,
|
||||
STAmount const& amount,
|
||||
Number::RoundingMode roundingMode)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
vault && vault->getType() == ltVAULT,
|
||||
"xrpl::debitToPosteriorBrokerCoverScale : valid Vault sle");
|
||||
XRPL_ASSERT(
|
||||
broker && broker->getType() == ltLOAN_BROKER,
|
||||
"xrpl::debitToPosteriorBrokerCoverScale : valid LoanBroker sle");
|
||||
XRPL_ASSERT(
|
||||
amount.asset() == vault->at(sfAsset),
|
||||
"xrpl::debitToPosteriorBrokerCoverScale : amount and Vault asset match");
|
||||
XRPL_ASSERT(!amount.negative(), "xrpl::debitToPosteriorBrokerCoverScale : non-negative amount");
|
||||
return -detail::roundToPosteriorBrokerCoverScale(vault, broker, -amount, roundingMode);
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkOptionalBrokerCoverInflow(SLE::ConstRef vault, SLE::ConstRef broker, STAmount const& amount)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
vault && vault->getType() == ltVAULT,
|
||||
"xrpl::checkOptionalBrokerCoverInflow : valid Vault sle");
|
||||
XRPL_ASSERT(
|
||||
broker && broker->getType() == ltLOAN_BROKER,
|
||||
"xrpl::checkOptionalBrokerCoverInflow : valid LoanBroker sle");
|
||||
XRPL_ASSERT(
|
||||
amount.asset() == vault->at(sfAsset),
|
||||
"xrpl::checkOptionalBrokerCoverInflow : amount and Vault asset match");
|
||||
XRPL_ASSERT(!amount.negative(), "xrpl::checkOptionalBrokerCoverInflow : non-negative amount");
|
||||
if (getVaultVersion(vault) != VaultVersion::FixedPrecision)
|
||||
return tesSUCCESS;
|
||||
|
||||
// amount is the effective credit (already floored on the posterior
|
||||
// CoverAvailable grid by creditToPosteriorBrokerCoverScale); rounding it
|
||||
// again as a standalone delta could hide a crossing.
|
||||
STAmount const& rounded = amount;
|
||||
int const baseScale = getVaultBaseScale(vault);
|
||||
// Keep this explicit even though the Open-limit capacity check below rejects
|
||||
// every coarsening transition too. The protocol defines both conditions
|
||||
// independently.
|
||||
if (detail::getPosteriorBrokerCoverScale(vault, broker, rounded) != baseScale)
|
||||
return tecLIMIT_EXCEEDED;
|
||||
|
||||
Number const posterior = [&] {
|
||||
NumberRoundModeGuard const rg(Number::RoundingMode::TowardsZero);
|
||||
return broker->at(sfCoverAvailable) + rounded;
|
||||
}();
|
||||
if (posterior > getVaultOpenLimit(vault))
|
||||
return tecLIMIT_EXCEEDED;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
adjustBrokerDebtTotal(
|
||||
SLE::Ref brokerSle,
|
||||
SLE::ConstRef vaultSle,
|
||||
Number const& delta,
|
||||
int vaultScale)
|
||||
{
|
||||
// On FixedPrecision Vaults, LoanSet adds principal to DebtTotal exactly, LoanPay and default
|
||||
// subtract exact amounts. Thus DebtTotal must not be rounded coarser than the base scale.
|
||||
if (getVaultVersion(vaultSle) == VaultVersion::FixedPrecision)
|
||||
{
|
||||
brokerSle->at(sfDebtTotal) += delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
adjustImpreciseNumber(brokerSle->at(sfDebtTotal), delta, vaultSle->at(sfAsset), vaultScale);
|
||||
}
|
||||
}
|
||||
|
||||
Number
|
||||
minimumBrokerCover(Number const& debtTotal, TenthBips32 coverRateMinimum, SLE::ConstRef vaultSle)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
vaultSle && vaultSle->getType() == ltVAULT, "xrpl::minimumBrokerCover : valid Vault sle");
|
||||
NumberRoundModeGuard const mg(Number::RoundingMode::Upward);
|
||||
return roundToAsset(
|
||||
vaultSle->at(sfAsset),
|
||||
tenthBipsOfValue(debtTotal, coverRateMinimum),
|
||||
getVaultBaseScale(vaultSle));
|
||||
}
|
||||
|
||||
bool
|
||||
checkLendingProtocolDependencies(Rules const& rules, STTx const& tx)
|
||||
{
|
||||
@@ -250,14 +405,13 @@ loanPaymentDeltas(LoanPaymentParts const& parts)
|
||||
|
||||
namespace {
|
||||
|
||||
// Cash-basis accounting applies only when featureLendingProtocolV1_1 is
|
||||
// enabled AND the specific Vault was created under it (LEVersion ==
|
||||
// VaultVersion::CashBasis). Vaults created before activation keep instant
|
||||
// interest recognition forever, even after the amendment later turns on.
|
||||
// Cash-basis accounting applies to Vaults created under
|
||||
// featureLendingProtocolV1_1 or a later version. Vaults created before
|
||||
// activation keep instant interest recognition forever.
|
||||
bool
|
||||
cashBasisEnabled(SLE::ConstRef vaultSle)
|
||||
{
|
||||
return getVaultVersion(vaultSle) == VaultVersion::CashBasis;
|
||||
return getVaultVersion(vaultSle) >= VaultVersion::CashBasis;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -43,6 +43,9 @@ constexpr auto kProposalTxTypes = std::to_array<TxType>({
|
||||
bool
|
||||
isValidProposalTxnType(STObject const& proposedTx)
|
||||
{
|
||||
if (!proposedTx.isFieldPresent(sfTransactionType))
|
||||
return false;
|
||||
|
||||
auto const type = proposedTx.getFieldU16(sfTransactionType);
|
||||
|
||||
if (std::ranges::find(kProposalTxTypes, type) != kProposalTxTypes.end())
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/EscrowHelpers.h>
|
||||
#include <xrpl/ledger/helpers/OracleHelpers.h>
|
||||
#include <xrpl/ledger/helpers/ProposalHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -319,6 +320,8 @@ getLedgerEntryOwnerCount(SLE const& sle)
|
||||
UNREACHABLE("AccountRoots are not supported by object sponsorship.");
|
||||
return 0;
|
||||
// LCOV_EXCL_STOP
|
||||
case ltESCROW:
|
||||
return calculateAdditionalReserve(sle[~sfBytecode]);
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/MathUtilities.h>
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
@@ -551,6 +552,22 @@ transferRate(ReadView const& view, STAmount const& amount)
|
||||
return transferRate(view, amount.asset());
|
||||
}
|
||||
|
||||
STAmount
|
||||
addTransferFee(STAmount const& amount, Rate const& rate)
|
||||
{
|
||||
if (rate == kParityRate)
|
||||
return amount;
|
||||
return mulRatio(amount, rate.value, QUALITY_ONE, Number::RoundingMode::Upward);
|
||||
}
|
||||
|
||||
STAmount
|
||||
subtractTransferFee(STAmount const& amount, Rate const& rate)
|
||||
{
|
||||
if (rate == kParityRate)
|
||||
return amount;
|
||||
return mulRatio(amount, QUALITY_ONE, rate.value, Number::RoundingMode::Downward);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Holding operations
|
||||
@@ -1347,9 +1364,8 @@ directSendNoLimitMPT(
|
||||
{
|
||||
// Number math loses precision on large MPT amounts, which can
|
||||
// overcharge the sender. MPTs are integral, so compute the cost
|
||||
// exactly and round it up, matching the payment engine.
|
||||
auto const cost = mulRatio(saAmount.mpt(), rate.value, QUALITY_ONE, true);
|
||||
saActual = STAmount(saAmount.asset(), cost.value());
|
||||
// exactly, matching the payment engine.
|
||||
saActual = addTransferFee(saAmount, rate);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1474,9 +1490,8 @@ directSendNoLimitMultiMPT(
|
||||
{
|
||||
// Number math loses precision on large MPT amounts, which can
|
||||
// overcharge the sender. MPTs are integral, so compute the
|
||||
// cost exactly and round it up, matching the payment engine.
|
||||
auto const cost = mulRatio(amount.mpt(), rate.value, QUALITY_ONE, true);
|
||||
actualSend = STAmount(amount.asset(), cost.value());
|
||||
// cost exactly, matching the payment engine.
|
||||
actualSend = addTransferFee(amount, rate);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -46,7 +48,7 @@ fixedBaseScale(SLE::ConstRef vault)
|
||||
}
|
||||
|
||||
// Thin, vault-specific wrapper over posteriorAssetScale: used by
|
||||
// getPosteriorVaultScale and creditToPosteriorAvailableScale.
|
||||
// getPosteriorVaultScale and the cash outflow rounding below.
|
||||
[[nodiscard]] int
|
||||
posteriorScale(SLE::ConstRef vault, Number const& reference, Number const& delta)
|
||||
{
|
||||
@@ -134,6 +136,18 @@ syncAssetsTotal(SLE::Ref vault)
|
||||
vault->at(sfAssetsTotal) = STAmount{asset, getAssetsTotal(vault)};
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
debitIsNonZeroDust(SLE::ConstRef vault, Number const& amount)
|
||||
{
|
||||
if (amount == 0)
|
||||
return false;
|
||||
|
||||
auto const total = getVaultVersion(vault) == VaultVersion::FixedPrecision
|
||||
? vault->at(sfAssetsAvailable)
|
||||
: getAssetsTotal(vault);
|
||||
auto const asset = vault->at(sfAsset);
|
||||
return STAmount{asset, total - amount} == STAmount{asset, total};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace detail {
|
||||
@@ -181,11 +195,11 @@ posteriorAssetScale(
|
||||
creditToPosteriorScale(
|
||||
Asset const& asset,
|
||||
Number const& reference,
|
||||
int atScale,
|
||||
int baseScale,
|
||||
Number const& raw,
|
||||
Number::RoundingMode roundingMode)
|
||||
{
|
||||
// Floor the SUM (reference + raw), not just raw, at atScale. See
|
||||
// Floor the SUM (reference + raw), not just raw. See
|
||||
// creditToPosteriorAvailableScale's doc: a delta floored on its own grid
|
||||
// can still leave a 17-digit sum once the reference has crossed a power
|
||||
// of ten.
|
||||
@@ -194,9 +208,21 @@ creditToPosteriorScale(
|
||||
// than Number holds (the sum is on the posterior grid, the reference on
|
||||
// the finer one). Compute both under roundingMode, not the caller's
|
||||
// ambient mode, so the credit this returns never exceeds raw.
|
||||
//
|
||||
// Take the grid from this same sum. A sum just under a power of ten that
|
||||
// rounds up to it in another mode would pick the coarser grid, and
|
||||
// flooring the unrounded sum on it would land below reference.
|
||||
NumberRoundModeGuard const rg(roundingMode);
|
||||
Number const flooredSum = roundToAsset(asset, reference + raw, atScale, roundingMode);
|
||||
return STAmount{asset, flooredSum - reference};
|
||||
Number const sum = reference + raw;
|
||||
int const atScale = liveScale(sum, asset, baseScale);
|
||||
Number const flooredSum = roundToAsset(asset, sum, atScale, roundingMode);
|
||||
STAmount const credit{asset, flooredSum - reference};
|
||||
XRPL_ASSERT_PARTS(
|
||||
roundingMode != Number::RoundingMode::Downward ||
|
||||
(credit >= beast::kZero && Number(credit) <= raw),
|
||||
"xrpl::detail::creditToPosteriorScale",
|
||||
"credit is between zero and raw");
|
||||
return credit;
|
||||
}
|
||||
|
||||
[[nodiscard]] int
|
||||
@@ -302,6 +328,17 @@ adjustVaultBalances(SLE::Ref vault, VaultBalanceChange const& change, beast::Jou
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
adjustVaultCash(SLE::Ref vault, STAmount const& delta, beast::Journal j)
|
||||
{
|
||||
if (getVaultVersion(vault) == VaultVersion::FixedPrecision)
|
||||
return adjustVaultBalances(vault, {.cash = delta}, j);
|
||||
|
||||
vault->at(sfAssetsTotal) += delta;
|
||||
vault->at(sfAssetsAvailable) += delta;
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] int
|
||||
getVaultScale(SLE::ConstRef vault)
|
||||
{
|
||||
@@ -374,8 +411,8 @@ creditToPosteriorAvailableScale(
|
||||
}
|
||||
|
||||
Number const reference = vault->at(sfAssetsAvailable);
|
||||
int const scale = posteriorScale(vault, reference, raw);
|
||||
return detail::creditToPosteriorScale(asset, reference, scale, raw, roundingMode);
|
||||
return detail::creditToPosteriorScale(
|
||||
asset, reference, fixedBaseScale(vault), raw, roundingMode);
|
||||
}
|
||||
|
||||
[[nodiscard]] Number
|
||||
@@ -428,6 +465,36 @@ vaultOpenZoneCapacity(SLE::ConstRef vault, Number const& roundedAmount)
|
||||
return getAssetsTotal(vault) + vault->at(sfYieldUnrealized) + roundedAmount;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkDebitNotDust(
|
||||
SLE::ConstRef vault,
|
||||
Number const& amount,
|
||||
beast::Journal j,
|
||||
std::string_view name)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (debitIsNonZeroDust(vault, amount))
|
||||
{
|
||||
JLOG(j.debug()) << name << ": amount too small to change stored vault balance";
|
||||
return tecPRECISION_LOSS;
|
||||
}
|
||||
}
|
||||
// LCOV_EXCL_START
|
||||
catch (std::overflow_error const&)
|
||||
{
|
||||
// It's easy to hit this exception from Number with large enough Scale
|
||||
// so we avoid spamming the log and only use debug here.
|
||||
JLOG(j.debug()) //
|
||||
<< name << ": overflow error with"
|
||||
<< " scale=" << (int)vault->at(sfScale) //
|
||||
<< ", assetsTotal=" << vault->at(sfAssetsTotal) << ", amount=" << amount;
|
||||
return tecPATH_DRY;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<STAmount>
|
||||
assetsToSharesDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount const& assets)
|
||||
{
|
||||
@@ -575,6 +642,14 @@ isOnVaultBaseGrid(Asset const& asset, Number const& value, int baseScale)
|
||||
roundToAsset(asset, value, baseScale, Number::RoundingMode::TowardsZero) == value;
|
||||
}
|
||||
|
||||
[[nodiscard]] TER
|
||||
checkAssetsMaximum(SLE::ConstRef vault, Number const& amount)
|
||||
{
|
||||
return isOnVaultBaseGrid(vault->at(sfAsset), amount, getVaultBaseScale(vault))
|
||||
? TER{tesSUCCESS}
|
||||
: TER{tecPRECISION_LOSS};
|
||||
}
|
||||
|
||||
[[nodiscard]] Number
|
||||
assetsTotalForWithdrawal(SLE::ConstRef vault, WaiveUnrealizedLoss waive)
|
||||
{
|
||||
@@ -584,22 +659,6 @@ assetsTotalForWithdrawal(SLE::ConstRef vault, WaiveUnrealizedLoss waive)
|
||||
return assetTotal;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
debitIsNonZeroDust(Asset const& asset, Number const& total, Number const& amount)
|
||||
{
|
||||
if (amount == 0)
|
||||
return false;
|
||||
return STAmount{asset, total - amount} == STAmount{asset, total};
|
||||
}
|
||||
|
||||
[[nodiscard]] Number
|
||||
vaultDebitDustReference(SLE::ConstRef vault, Number const& assetsTotal)
|
||||
{
|
||||
return getVaultVersion(vault) == VaultVersion::FixedPrecision
|
||||
? Number(vault->at(sfAssetsAvailable))
|
||||
: assetsTotal;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<STAmount>
|
||||
assetsToSharesWithdraw(
|
||||
SLE::ConstRef vault,
|
||||
@@ -695,9 +754,10 @@ getVaultVersion(SLE::ConstRef vault)
|
||||
[[nodiscard]] VaultVersion
|
||||
getVaultDefaultVersion(Rules const& rules)
|
||||
{
|
||||
// FixedPrecision requires both cleanups, so a FixedPrecision Vault always
|
||||
// sees them enabled.
|
||||
if (rules.enabled(featureLendingProtocolV1_2) && rules.enabled(fixCleanup3_2_0) &&
|
||||
// FixedPrecision requires featureLendingProtocolV1_1 (closed-ended Vaults and
|
||||
// cash-basis accounting) and fixCleanup3_4_0, so a FixedPrecision Vault always
|
||||
// sees both enabled. fixCleanup3_2_0 is already enabled on the network.
|
||||
if (rules.enabled(featureLendingProtocolV1_1) && rules.enabled(featureLendingProtocolV1_2) &&
|
||||
rules.enabled(fixCleanup3_4_0))
|
||||
return VaultVersion::FixedPrecision;
|
||||
if (rules.enabled(featureLendingProtocolV1_1))
|
||||
|
||||
@@ -435,18 +435,25 @@ areMirrorsCurrent(SLE const& issuance, SLE const& mptoken)
|
||||
}
|
||||
|
||||
void
|
||||
setIssuerMirrorEpoch(SLE const& issuance, SLE& mptoken)
|
||||
setIssuerMirrorCurrent(SLE const& issuance, SLE& mptoken)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
issuance.getType() == ltMPTOKEN_ISSUANCE,
|
||||
"xrpl::setIssuerMirrorEpoch : issuance MPTokenIssuance object");
|
||||
"xrpl::setIssuerMirrorCurrent : issuance MPTokenIssuance object");
|
||||
XRPL_ASSERT(
|
||||
mptoken.getType() == ltMPTOKEN, "xrpl::setIssuerMirrorEpoch : mptoken MPToken object");
|
||||
mptoken.getType() == ltMPTOKEN, "xrpl::setIssuerMirrorCurrent : mptoken MPToken object");
|
||||
|
||||
// Unlike the auditor mirror, the issuer mirror is not optional: every
|
||||
// confidential MPToken carries one, so there is no existence check here.
|
||||
//
|
||||
// Record the key and epoch under which the mirror is now encrypted. Both fields remain absent
|
||||
// at epoch 0: such mirrors use the original issuer key. The original key is stored in
|
||||
// sfInitialIssuerEncryptionKey after the first rotation.
|
||||
if (auto const epoch = issuance[~sfIssuerKeyEpoch].value_or(0); epoch != 0)
|
||||
{
|
||||
mptoken[sfIssuerKeyMirrorEpoch] = epoch;
|
||||
mptoken[sfIssuerMirrorEncryptionKey] = issuance[sfIssuerEncryptionKey];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -466,9 +473,9 @@ setAuditorMirrorEpoch(SLE const& issuance, SLE& mptoken)
|
||||
}
|
||||
|
||||
void
|
||||
setMirrorEpochs(SLE const& issuance, SLE& mptoken)
|
||||
setMirrorsCurrent(SLE const& issuance, SLE& mptoken)
|
||||
{
|
||||
setIssuerMirrorEpoch(issuance, mptoken);
|
||||
setIssuerMirrorCurrent(issuance, mptoken);
|
||||
setAuditorMirrorEpoch(issuance, mptoken);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/MPTIssue.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
#include <xrpl/protocol/digest.h>
|
||||
@@ -105,9 +103,6 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
NftokenBuyOffers = 'h',
|
||||
NftokenSellOffers = 'i',
|
||||
Amm = 'A',
|
||||
Bridge = 'H',
|
||||
XchainClaimId = 'Q',
|
||||
XchainCreateAccountClaimId = 'K',
|
||||
Did = 'I',
|
||||
Oracle = 'R',
|
||||
MPTokenIssuance = '~',
|
||||
@@ -125,6 +120,9 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
Contract [[deprecated]] = 'c',
|
||||
Generator [[deprecated]] = 'g',
|
||||
Nickname [[deprecated]] = 'n',
|
||||
Bridge [[deprecated]] = 'H',
|
||||
XchainClaimId [[deprecated]] = 'Q',
|
||||
XchainCreateAccountClaimId [[deprecated]] = 'K',
|
||||
};
|
||||
|
||||
template <class... Args>
|
||||
@@ -527,44 +525,6 @@ delegate(AccountID const& account, AccountID const& authorizedAccount) noexcept
|
||||
return {ltDELEGATE, indexHash(LedgerNameSpace::Delegate, account, authorizedAccount)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
bridge(STXChainBridge const& bridge, STXChainBridge::ChainType chainType)
|
||||
{
|
||||
// A door account can support multiple bridges. On the locking chain
|
||||
// there can only be one bridge per lockingChainCurrency. On the issuing
|
||||
// chain there can only be one bridge per issuingChainCurrency.
|
||||
auto const& issue = bridge.issue(chainType);
|
||||
return {ltBRIDGE, indexHash(LedgerNameSpace::Bridge, bridge.door(chainType), issue.currency)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
xChainClaimID(STXChainBridge const& bridge, std::uint64_t const seq)
|
||||
{
|
||||
return {
|
||||
ltXCHAIN_OWNED_CLAIM_ID,
|
||||
indexHash(
|
||||
LedgerNameSpace::XchainClaimId,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
bridge.issuingChainIssue(),
|
||||
seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
xChainCreateAccountClaimID(STXChainBridge const& bridge, std::uint64_t const seq)
|
||||
{
|
||||
return {
|
||||
ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID,
|
||||
indexHash(
|
||||
LedgerNameSpace::XchainCreateAccountClaimId,
|
||||
bridge.lockingChainDoor(),
|
||||
bridge.lockingChainIssue(),
|
||||
bridge.issuingChainDoor(),
|
||||
bridge.issuingChainIssue(),
|
||||
seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
did(AccountID const& account) noexcept
|
||||
{
|
||||
|
||||
@@ -65,58 +65,6 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfAuthAccounts, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfXChainClaimAttestationCollectionElement.jsonName,
|
||||
sfXChainClaimAttestationCollectionElement.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfXChainClaimID, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfXChainCreateAccountAttestationCollectionElement.jsonName,
|
||||
sfXChainCreateAccountAttestationCollectionElement.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfSignature, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAccount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfXChainAccountCreateCount, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfXChainClaimProofSig.jsonName,
|
||||
sfXChainClaimProofSig.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfDestination, SoeOptional},
|
||||
});
|
||||
|
||||
add(sfXChainCreateAccountProofSig.jsonName,
|
||||
sfXChainCreateAccountProofSig.getCode(),
|
||||
{
|
||||
{sfAttestationSignerAccount, SoeRequired},
|
||||
{sfPublicKey, SoeRequired},
|
||||
{sfAmount, SoeRequired},
|
||||
{sfSignatureReward, SoeRequired},
|
||||
{sfAttestationRewardAccount, SoeRequired},
|
||||
{sfWasLockingChainSend, SoeRequired},
|
||||
{sfDestination, SoeRequired},
|
||||
});
|
||||
|
||||
add(sfAuthAccount.jsonName,
|
||||
sfAuthAccount.getCode(),
|
||||
{
|
||||
|
||||
@@ -1763,6 +1763,24 @@ divRoundStrict(STAmount const& num, STAmount const& den, Asset const& asset, boo
|
||||
return divRoundImpl<NumberRoundModeGuard>(num, den, asset, roundUp);
|
||||
}
|
||||
|
||||
STAmount
|
||||
mulRatio(STAmount const& amt, std::uint32_t num, std::uint32_t den, Number::RoundingMode rounding)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
rounding == Number::RoundingMode::Upward || rounding == Number::RoundingMode::Downward,
|
||||
"xrpl::mulRatio(STAmount) : rounding is Upward or Downward");
|
||||
bool const roundUp = rounding == Number::RoundingMode::Upward;
|
||||
return amt.asset().visit(
|
||||
[&](Issue const& issue) -> STAmount {
|
||||
if (amt.native())
|
||||
return mulRatio(amt.xrp(), num, den, roundUp);
|
||||
return {mulRatio(amt.iou(), num, den, roundUp), issue};
|
||||
},
|
||||
[&](MPTIssue const& issue) -> STAmount {
|
||||
return {mulRatio(amt.mpt(), num, den, roundUp), issue};
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
STAmount::isZeroAtScale(int scale) const
|
||||
{
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
#include <xrpl/protocol/STInteger.h>
|
||||
#include <xrpl/protocol/STIssue.h>
|
||||
#include <xrpl/protocol/STNumber.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
@@ -956,18 +956,6 @@ parseLeaf(
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_XCHAIN_BRIDGE:
|
||||
try
|
||||
{
|
||||
ret = detail::makeStvar<STXChainBridge>(STXChainBridge(field, value));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
error = invalidData(jsonName, fieldName);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
case STI_CURRENCY:
|
||||
try
|
||||
{
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STPathSet.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -217,9 +216,6 @@ STVar::constructST(SerializedTypeID id, int depth, Args&&... args)
|
||||
case STI_ISSUE:
|
||||
construct<STIssue>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_XCHAIN_BRIDGE:
|
||||
construct<STXChainBridge>(std::forward<Args>(args)...);
|
||||
return;
|
||||
case STI_CURRENCY:
|
||||
construct<STCurrency>(std::forward<Args>(args)...);
|
||||
return;
|
||||
|
||||
@@ -1,204 +0,0 @@
|
||||
#include <xrpl/protocol/STXChainBridge.h>
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STBase.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <format>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
STXChainBridge::STXChainBridge() : STBase{sfXChainBridge}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(SField const& name) : STBase{name}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(
|
||||
AccountID const& srcChainDoor,
|
||||
Issue const& srcChainIssue,
|
||||
AccountID const& dstChainDoor,
|
||||
Issue const& dstChainIssue)
|
||||
: STBase{sfXChainBridge}
|
||||
, lockingChainDoor_{sfLockingChainDoor, srcChainDoor}
|
||||
, lockingChainIssue_{sfLockingChainIssue, srcChainIssue}
|
||||
, issuingChainDoor_{sfIssuingChainDoor, dstChainDoor}
|
||||
, issuingChainIssue_{sfIssuingChainIssue, dstChainIssue}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(STObject const& o)
|
||||
: STBase{sfXChainBridge}
|
||||
, lockingChainDoor_{sfLockingChainDoor, o[sfLockingChainDoor]}
|
||||
, lockingChainIssue_{sfLockingChainIssue, o[sfLockingChainIssue]}
|
||||
, issuingChainDoor_{sfIssuingChainDoor, o[sfIssuingChainDoor]}
|
||||
, issuingChainIssue_{sfIssuingChainIssue, o[sfIssuingChainIssue]}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(json::Value const& v) : STXChainBridge{sfXChainBridge, v}
|
||||
{
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(SField const& name, json::Value const& v) : STBase{name}
|
||||
{
|
||||
if (!v.isObject())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"STXChainBridge can only be specified with a 'object' Json value");
|
||||
}
|
||||
|
||||
auto const checkExtra = [](json::Value const& v) {
|
||||
static auto const kBridgeJson =
|
||||
xrpl::STXChainBridge().getJson(xrpl::JsonOptions::Values::None);
|
||||
for (auto it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
std::string const name = it.memberName();
|
||||
if (!kBridgeJson.isMember(name))
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
std::format("STXChainBridge extra field detected: {}", name));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
checkExtra(v);
|
||||
|
||||
json::Value const& lockingChainDoorStr = v[jss::LockingChainDoor];
|
||||
json::Value const& lockingChainIssue = v[jss::LockingChainIssue];
|
||||
json::Value const& issuingChainDoorStr = v[jss::IssuingChainDoor];
|
||||
json::Value const& issuingChainIssue = v[jss::IssuingChainIssue];
|
||||
|
||||
if (!lockingChainDoorStr.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge LockingChainDoor must be a string Json value");
|
||||
}
|
||||
if (!issuingChainDoorStr.isString())
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge IssuingChainDoor must be a string Json value");
|
||||
}
|
||||
|
||||
auto const lockingChainDoor = parseBase58<AccountID>(lockingChainDoorStr.asString());
|
||||
auto const issuingChainDoor = parseBase58<AccountID>(issuingChainDoorStr.asString());
|
||||
if (!lockingChainDoor)
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge LockingChainDoor must be a valid account");
|
||||
}
|
||||
if (!issuingChainDoor)
|
||||
{
|
||||
Throw<std::runtime_error>("STXChainBridge IssuingChainDoor must be a valid account");
|
||||
}
|
||||
|
||||
lockingChainDoor_ = STAccount{sfLockingChainDoor, *lockingChainDoor};
|
||||
lockingChainIssue_ = STIssue{sfLockingChainIssue, issueFromJson(lockingChainIssue)};
|
||||
issuingChainDoor_ = STAccount{sfIssuingChainDoor, *issuingChainDoor};
|
||||
issuingChainIssue_ = STIssue{sfIssuingChainIssue, issueFromJson(issuingChainIssue)};
|
||||
}
|
||||
|
||||
STXChainBridge::STXChainBridge(SerialIter& sit, SField const& name)
|
||||
: STBase{name}
|
||||
, lockingChainDoor_{sit, sfLockingChainDoor}
|
||||
, lockingChainIssue_{sit, sfLockingChainIssue}
|
||||
, issuingChainDoor_{sit, sfIssuingChainDoor}
|
||||
, issuingChainIssue_{sit, sfIssuingChainIssue}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
STXChainBridge::add(Serializer& s) const
|
||||
{
|
||||
lockingChainDoor_.add(s);
|
||||
lockingChainIssue_.add(s);
|
||||
issuingChainDoor_.add(s);
|
||||
issuingChainIssue_.add(s);
|
||||
}
|
||||
|
||||
json::Value
|
||||
STXChainBridge::getJson(JsonOptions jo) const
|
||||
{
|
||||
json::Value v;
|
||||
v[jss::LockingChainDoor] = lockingChainDoor_.getJson(jo);
|
||||
v[jss::LockingChainIssue] = lockingChainIssue_.getJson(jo);
|
||||
v[jss::IssuingChainDoor] = issuingChainDoor_.getJson(jo);
|
||||
v[jss::IssuingChainIssue] = issuingChainIssue_.getJson(jo);
|
||||
return v;
|
||||
}
|
||||
|
||||
std::string
|
||||
STXChainBridge::getText() const
|
||||
{
|
||||
return std::format(
|
||||
"{{ {} = {}, {} = {}, {} = {}, {} = {} }}",
|
||||
sfLockingChainDoor.getName(),
|
||||
lockingChainDoor_.getText(),
|
||||
sfLockingChainIssue.getName(),
|
||||
lockingChainIssue_.getText(),
|
||||
sfIssuingChainDoor.getName(),
|
||||
issuingChainDoor_.getText(),
|
||||
sfIssuingChainIssue.getName(),
|
||||
issuingChainIssue_.getText());
|
||||
}
|
||||
|
||||
STObject
|
||||
STXChainBridge::toSTObject() const
|
||||
{
|
||||
STObject o{sfXChainBridge};
|
||||
o[sfLockingChainDoor] = lockingChainDoor_;
|
||||
o[sfLockingChainIssue] = lockingChainIssue_;
|
||||
o[sfIssuingChainDoor] = issuingChainDoor_;
|
||||
o[sfIssuingChainIssue] = issuingChainIssue_;
|
||||
return o;
|
||||
}
|
||||
|
||||
SerializedTypeID
|
||||
STXChainBridge::getSType() const
|
||||
{
|
||||
return STI_XCHAIN_BRIDGE;
|
||||
}
|
||||
|
||||
bool
|
||||
STXChainBridge::isEquivalent(STBase const& t) const
|
||||
{
|
||||
auto const* v = dynamic_cast<STXChainBridge const*>(&t);
|
||||
return (v != nullptr) && (*v == *this);
|
||||
}
|
||||
|
||||
bool
|
||||
STXChainBridge::isDefault() const
|
||||
{
|
||||
return lockingChainDoor_.isDefault() && lockingChainIssue_.isDefault() &&
|
||||
issuingChainDoor_.isDefault() && issuingChainIssue_.isDefault();
|
||||
}
|
||||
|
||||
std::unique_ptr<STXChainBridge>
|
||||
STXChainBridge::construct(SerialIter& sit, SField const& name)
|
||||
{
|
||||
return std::make_unique<STXChainBridge>(sit, name);
|
||||
}
|
||||
|
||||
STBase*
|
||||
STXChainBridge::copy(std::size_t n, void* buf) const
|
||||
{
|
||||
return emplace(n, buf, *this);
|
||||
}
|
||||
|
||||
STBase*
|
||||
STXChainBridge::move(std::size_t n, void* buf)
|
||||
{
|
||||
return emplace(n, buf, std::move(*this));
|
||||
}
|
||||
} // namespace xrpl
|
||||
@@ -137,6 +137,8 @@ transResults()
|
||||
MAKE_ERROR(tefBAD_PATH_COUNT, "Malformed: Too many paths."),
|
||||
MAKE_ERROR(tefNO_BYTECODE, "There is no WASM code to run, but a WASM-specific field was included."),
|
||||
MAKE_ERROR(tefBYTECODE_NOT_INCLUDED, "WASM code requires a field that was not included."),
|
||||
MAKE_ERROR(tefTEMP_DISABLED, "The transaction requires logic that is currently temporarily disabled."),
|
||||
MAKE_ERROR(tefEXCEEDS_LIMIT, "The transaction exceeds a limit set by fee voting."),
|
||||
|
||||
MAKE_ERROR(telLOCAL_ERROR, "Local failure."),
|
||||
MAKE_ERROR(telBAD_DOMAIN, "Domain too long."),
|
||||
@@ -209,7 +211,6 @@ transResults()
|
||||
MAKE_ERROR(temINVALID_INNER_BATCH, "Malformed: Invalid inner batch transaction."),
|
||||
MAKE_ERROR(temBAD_CIPHERTEXT, "Malformed: Invalid ciphertext."),
|
||||
MAKE_ERROR(temINVALID_BYTECODE, "Malformed: Provided byte code is invalid."),
|
||||
MAKE_ERROR(temTEMP_DISABLED, "The transaction requires logic that is currently temporarily disabled."),
|
||||
|
||||
MAKE_ERROR(terRETRY, "Retry transaction."),
|
||||
MAKE_ERROR(terFUNDS_SPENT, "DEPRECATED."),
|
||||
|
||||
@@ -1,706 +0,0 @@
|
||||
#include <xrpl/protocol/XChainAttestations.h>
|
||||
|
||||
#include <xrpl/basics/Buffer.h>
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STAccount.h>
|
||||
#include <xrpl/protocol/STAmount.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/SecretKey.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
#include <xrpl/protocol/json_get_or_throw.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace xrpl {
|
||||
namespace attestations {
|
||||
|
||||
AttestationBase::AttestationBase(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend)
|
||||
: attestationSignerAccount{attestationSignerAccount}
|
||||
, publicKey{publicKey}
|
||||
, signature{std::move(signature)}
|
||||
, sendingAccount{sendingAccount}
|
||||
, sendingAmount{std::move(sendingAmount)}
|
||||
, rewardAccount{rewardAccount}
|
||||
, wasLockingChainSend{wasLockingChainSend}
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationBase::equalHelper(AttestationBase const& lhs, AttestationBase const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.attestationSignerAccount,
|
||||
lhs.publicKey,
|
||||
lhs.signature,
|
||||
lhs.sendingAccount,
|
||||
lhs.sendingAmount,
|
||||
lhs.rewardAccount,
|
||||
lhs.wasLockingChainSend) ==
|
||||
std::tie(
|
||||
rhs.attestationSignerAccount,
|
||||
rhs.publicKey,
|
||||
rhs.signature,
|
||||
rhs.sendingAccount,
|
||||
rhs.sendingAmount,
|
||||
rhs.rewardAccount,
|
||||
rhs.wasLockingChainSend);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationBase::sameEventHelper(AttestationBase const& lhs, AttestationBase const& rhs)
|
||||
{
|
||||
return std::tie(lhs.sendingAccount, lhs.sendingAmount, lhs.wasLockingChainSend) ==
|
||||
std::tie(rhs.sendingAccount, rhs.sendingAmount, rhs.wasLockingChainSend);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationBase::verify(STXChainBridge const& bridge) const
|
||||
{
|
||||
std::vector<std::uint8_t> const msg = message(bridge);
|
||||
return xrpl::verify(publicKey, makeSlice(msg), signature);
|
||||
}
|
||||
|
||||
AttestationBase::AttestationBase(STObject const& o)
|
||||
: attestationSignerAccount{o[sfAttestationSignerAccount]}
|
||||
, publicKey{o[sfPublicKey]}
|
||||
, signature{o[sfSignature]}
|
||||
, sendingAccount{o[sfAccount]}
|
||||
, sendingAmount{o[sfAmount]}
|
||||
, rewardAccount{o[sfAttestationRewardAccount]}
|
||||
, wasLockingChainSend{bool(o[sfWasLockingChainSend])}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationBase::AttestationBase(json::Value const& v)
|
||||
: attestationSignerAccount{json::getOrThrow<AccountID>(v, sfAttestationSignerAccount)}
|
||||
, publicKey{json::getOrThrow<PublicKey>(v, sfPublicKey)}
|
||||
, signature{json::getOrThrow<Buffer>(v, sfSignature)}
|
||||
, sendingAccount{json::getOrThrow<AccountID>(v, sfAccount)}
|
||||
, sendingAmount{json::getOrThrow<STAmount>(v, sfAmount)}
|
||||
, rewardAccount{json::getOrThrow<AccountID>(v, sfAttestationRewardAccount)}
|
||||
, wasLockingChainSend{json::getOrThrow<bool>(v, sfWasLockingChainSend)}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AttestationBase::addHelper(STObject& o) const
|
||||
{
|
||||
o[sfAttestationSignerAccount] = attestationSignerAccount;
|
||||
o[sfPublicKey] = publicKey;
|
||||
o[sfSignature] = signature;
|
||||
o[sfAmount] = sendingAmount;
|
||||
o[sfAccount] = sendingAccount;
|
||||
o[sfAttestationRewardAccount] = rewardAccount;
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend;
|
||||
}
|
||||
|
||||
AttestationClaim::AttestationClaim(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimId,
|
||||
std::optional<AccountID> const& dst)
|
||||
: AttestationBase(
|
||||
attestationSignerAccount,
|
||||
publicKey,
|
||||
std::move(signature),
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend)
|
||||
, claimID{claimId}
|
||||
, dst{dst}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationClaim::AttestationClaim(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimId,
|
||||
std::optional<AccountID> const& dst)
|
||||
: AttestationClaim{
|
||||
attestationSignerAccount,
|
||||
publicKey,
|
||||
Buffer{},
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend,
|
||||
claimId,
|
||||
dst}
|
||||
{
|
||||
auto const toSign = message(bridge);
|
||||
signature = sign(publicKey, secretKey, makeSlice(toSign));
|
||||
}
|
||||
|
||||
AttestationClaim::AttestationClaim(STObject const& o)
|
||||
: AttestationBase(o), claimID{o[sfXChainClaimID]}, dst{o[~sfDestination]}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationClaim::AttestationClaim(json::Value const& v)
|
||||
: AttestationBase{v}, claimID{json::getOrThrow<std::uint64_t>(v, sfXChainClaimID)}
|
||||
{
|
||||
if (v.isMember(sfDestination.getJsonName()))
|
||||
dst = json::getOrThrow<AccountID>(v, sfDestination);
|
||||
}
|
||||
|
||||
STObject
|
||||
AttestationClaim::toSTObject() const
|
||||
{
|
||||
STObject o = STObject::makeInnerObject(sfXChainClaimAttestationCollectionElement);
|
||||
addHelper(o);
|
||||
o[sfXChainClaimID] = claimID;
|
||||
if (dst)
|
||||
o[sfDestination] = *dst;
|
||||
return o;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
AttestationClaim::message(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t claimID,
|
||||
std::optional<AccountID> const& dst)
|
||||
{
|
||||
STObject o{sfGeneric};
|
||||
// Serialize in SField order to make python serializers easier to write
|
||||
o[sfXChainClaimID] = claimID;
|
||||
o[sfAmount] = sendingAmount;
|
||||
if (dst)
|
||||
o[sfDestination] = *dst;
|
||||
o[sfOtherChainSource] = sendingAccount;
|
||||
o[sfAttestationRewardAccount] = rewardAccount;
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend ? 1 : 0;
|
||||
o[sfXChainBridge] = bridge;
|
||||
|
||||
Serializer s;
|
||||
o.add(s);
|
||||
|
||||
return std::move(s.modData());
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
AttestationClaim::message(STXChainBridge const& bridge) const
|
||||
{
|
||||
return AttestationClaim::message(
|
||||
bridge, sendingAccount, sendingAmount, rewardAccount, wasLockingChainSend, claimID, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationClaim::validAmounts() const
|
||||
{
|
||||
return isLegalNet(sendingAmount);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationClaim::sameEvent(AttestationClaim const& rhs) const
|
||||
{
|
||||
return AttestationClaim::sameEventHelper(*this, rhs) &&
|
||||
tie(claimID, dst) == tie(rhs.claimID, rhs.dst);
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(AttestationClaim const& lhs, AttestationClaim const& rhs)
|
||||
{
|
||||
return AttestationClaim::equalHelper(lhs, rhs) &&
|
||||
tie(lhs.claimID, lhs.dst) == tie(rhs.claimID, rhs.dst);
|
||||
}
|
||||
|
||||
AttestationCreateAccount::AttestationCreateAccount(STObject const& o)
|
||||
: AttestationBase(o)
|
||||
, createCount{o[sfXChainAccountCreateCount]}
|
||||
, toCreate{o[sfDestination]}
|
||||
, rewardAmount{o[sfSignatureReward]}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationCreateAccount::AttestationCreateAccount(json::Value const& v)
|
||||
: AttestationBase{v}
|
||||
, createCount{json::getOrThrow<std::uint64_t>(v, sfXChainAccountCreateCount)}
|
||||
, toCreate{json::getOrThrow<AccountID>(v, sfDestination)}
|
||||
, rewardAmount{json::getOrThrow<STAmount>(v, sfSignatureReward)}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationCreateAccount::AttestationCreateAccount(
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
Buffer signature,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& toCreate)
|
||||
: AttestationBase(
|
||||
attestationSignerAccount,
|
||||
publicKey,
|
||||
std::move(signature),
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend)
|
||||
, createCount{createCount}
|
||||
, toCreate{toCreate}
|
||||
, rewardAmount{std::move(rewardAmount)}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationCreateAccount::AttestationCreateAccount(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID attestationSignerAccount,
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& toCreate)
|
||||
: AttestationCreateAccount{
|
||||
attestationSignerAccount,
|
||||
publicKey,
|
||||
Buffer{},
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend,
|
||||
createCount,
|
||||
toCreate}
|
||||
{
|
||||
auto const toSign = message(bridge);
|
||||
signature = sign(publicKey, secretKey, makeSlice(toSign));
|
||||
}
|
||||
|
||||
STObject
|
||||
AttestationCreateAccount::toSTObject() const
|
||||
{
|
||||
STObject o = STObject::makeInnerObject(sfXChainCreateAccountAttestationCollectionElement);
|
||||
addHelper(o);
|
||||
|
||||
o[sfXChainAccountCreateCount] = createCount;
|
||||
o[sfDestination] = toCreate;
|
||||
o[sfSignatureReward] = rewardAmount;
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
AttestationCreateAccount::message(
|
||||
STXChainBridge const& bridge,
|
||||
AccountID const& sendingAccount,
|
||||
STAmount const& sendingAmount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::uint64_t createCount,
|
||||
AccountID const& dst)
|
||||
{
|
||||
STObject o{sfGeneric};
|
||||
// Serialize in SField order to make python serializers easier to write
|
||||
o[sfXChainAccountCreateCount] = createCount;
|
||||
o[sfAmount] = sendingAmount;
|
||||
o[sfSignatureReward] = rewardAmount;
|
||||
o[sfDestination] = dst;
|
||||
o[sfOtherChainSource] = sendingAccount;
|
||||
o[sfAttestationRewardAccount] = rewardAccount;
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend ? 1 : 0;
|
||||
o[sfXChainBridge] = bridge;
|
||||
|
||||
Serializer s;
|
||||
o.add(s);
|
||||
|
||||
return std::move(s.modData());
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
AttestationCreateAccount::message(STXChainBridge const& bridge) const
|
||||
{
|
||||
return AttestationCreateAccount::message(
|
||||
bridge,
|
||||
sendingAccount,
|
||||
sendingAmount,
|
||||
rewardAmount,
|
||||
rewardAccount,
|
||||
wasLockingChainSend,
|
||||
createCount,
|
||||
toCreate);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationCreateAccount::validAmounts() const
|
||||
{
|
||||
return isLegalNet(rewardAmount) && isLegalNet(sendingAmount);
|
||||
}
|
||||
|
||||
bool
|
||||
AttestationCreateAccount::sameEvent(AttestationCreateAccount const& rhs) const
|
||||
{
|
||||
return AttestationCreateAccount::sameEventHelper(*this, rhs) &&
|
||||
std::tie(createCount, toCreate, rewardAmount) ==
|
||||
std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount);
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(AttestationCreateAccount const& lhs, AttestationCreateAccount const& rhs)
|
||||
{
|
||||
return AttestationCreateAccount::equalHelper(lhs, rhs) &&
|
||||
std::tie(lhs.createCount, lhs.toCreate, lhs.rewardAmount) ==
|
||||
std::tie(rhs.createCount, rhs.toCreate, rhs.rewardAmount);
|
||||
}
|
||||
|
||||
} // namespace attestations
|
||||
|
||||
SField const& XChainClaimAttestation::arrayFieldName{sfXChainClaimAttestations};
|
||||
SField const& XChainCreateAccountAttestation::arrayFieldName{sfXChainCreateAccountAttestations};
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(
|
||||
AccountID const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::optional<AccountID> const& dst)
|
||||
: keyAccount(keyAccount)
|
||||
, publicKey(publicKey)
|
||||
, amount(sfAmount, amount)
|
||||
, rewardAccount(rewardAccount)
|
||||
, wasLockingChainSend(wasLockingChainSend)
|
||||
, dst(dst)
|
||||
{
|
||||
}
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(
|
||||
STAccount const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
STAccount const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
std::optional<STAccount> const& dst)
|
||||
: XChainClaimAttestation{
|
||||
keyAccount.value(),
|
||||
publicKey,
|
||||
amount,
|
||||
rewardAccount.value(),
|
||||
wasLockingChainSend,
|
||||
dst ? std::optional<AccountID>{dst->value()} : std::nullopt}
|
||||
{
|
||||
}
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(STObject const& o)
|
||||
: XChainClaimAttestation{
|
||||
o[sfAttestationSignerAccount],
|
||||
PublicKey{o[sfPublicKey]},
|
||||
o[sfAmount],
|
||||
o[sfAttestationRewardAccount],
|
||||
o[sfWasLockingChainSend] != 0,
|
||||
o[~sfDestination]} {};
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(json::Value const& v)
|
||||
: XChainClaimAttestation{
|
||||
json::getOrThrow<AccountID>(v, sfAttestationSignerAccount),
|
||||
json::getOrThrow<PublicKey>(v, sfPublicKey),
|
||||
json::getOrThrow<STAmount>(v, sfAmount),
|
||||
json::getOrThrow<AccountID>(v, sfAttestationRewardAccount),
|
||||
json::getOrThrow<bool>(v, sfWasLockingChainSend),
|
||||
std::nullopt}
|
||||
{
|
||||
if (v.isMember(sfDestination.getJsonName()))
|
||||
dst = json::getOrThrow<AccountID>(v, sfDestination);
|
||||
};
|
||||
|
||||
XChainClaimAttestation::XChainClaimAttestation(
|
||||
XChainClaimAttestation::TSignedAttestation const& claimAtt)
|
||||
: XChainClaimAttestation{
|
||||
claimAtt.attestationSignerAccount,
|
||||
claimAtt.publicKey,
|
||||
claimAtt.sendingAmount,
|
||||
claimAtt.rewardAccount,
|
||||
claimAtt.wasLockingChainSend,
|
||||
claimAtt.dst}
|
||||
{
|
||||
}
|
||||
|
||||
STObject
|
||||
XChainClaimAttestation::toSTObject() const
|
||||
{
|
||||
STObject o = STObject::makeInnerObject(sfXChainClaimProofSig);
|
||||
o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount};
|
||||
o[sfPublicKey] = publicKey;
|
||||
o[sfAmount] = STAmount{sfAmount, amount};
|
||||
o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount};
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend;
|
||||
if (dst)
|
||||
o[sfDestination] = STAccount{sfDestination, *dst};
|
||||
return o;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(XChainClaimAttestation const& lhs, XChainClaimAttestation const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.keyAccount,
|
||||
lhs.publicKey,
|
||||
lhs.amount,
|
||||
lhs.rewardAccount,
|
||||
lhs.wasLockingChainSend,
|
||||
lhs.dst) ==
|
||||
std::tie(
|
||||
rhs.keyAccount,
|
||||
rhs.publicKey,
|
||||
rhs.amount,
|
||||
rhs.rewardAccount,
|
||||
rhs.wasLockingChainSend,
|
||||
rhs.dst);
|
||||
}
|
||||
|
||||
XChainClaimAttestation::MatchFields::MatchFields(
|
||||
XChainClaimAttestation::TSignedAttestation const& att)
|
||||
: amount{att.sendingAmount}, wasLockingChainSend{att.wasLockingChainSend}, dst{att.dst}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationMatch
|
||||
XChainClaimAttestation::match(XChainClaimAttestation::MatchFields const& rhs) const
|
||||
{
|
||||
if (std::tie(amount, wasLockingChainSend) != std::tie(rhs.amount, rhs.wasLockingChainSend))
|
||||
return AttestationMatch::NonDstMismatch;
|
||||
if (dst != rhs.dst)
|
||||
return AttestationMatch::MatchExceptDst;
|
||||
return AttestationMatch::Match;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
XChainCreateAccountAttestation::XChainCreateAccountAttestation(
|
||||
AccountID const& keyAccount,
|
||||
PublicKey const& publicKey,
|
||||
STAmount const& amount,
|
||||
STAmount const& rewardAmount,
|
||||
AccountID const& rewardAccount,
|
||||
bool wasLockingChainSend,
|
||||
AccountID const& dst)
|
||||
: keyAccount(keyAccount)
|
||||
, publicKey(publicKey)
|
||||
, amount(sfAmount, amount)
|
||||
, rewardAmount(sfSignatureReward, rewardAmount)
|
||||
, rewardAccount(rewardAccount)
|
||||
, wasLockingChainSend(wasLockingChainSend)
|
||||
, dst(dst)
|
||||
{
|
||||
}
|
||||
|
||||
XChainCreateAccountAttestation::XChainCreateAccountAttestation(STObject const& o)
|
||||
: XChainCreateAccountAttestation{
|
||||
o[sfAttestationSignerAccount],
|
||||
PublicKey{o[sfPublicKey]},
|
||||
o[sfAmount],
|
||||
o[sfSignatureReward],
|
||||
o[sfAttestationRewardAccount],
|
||||
o[sfWasLockingChainSend] != 0,
|
||||
o[sfDestination]} {};
|
||||
|
||||
XChainCreateAccountAttestation::XChainCreateAccountAttestation(json::Value const& v)
|
||||
: XChainCreateAccountAttestation{
|
||||
json::getOrThrow<AccountID>(v, sfAttestationSignerAccount),
|
||||
json::getOrThrow<PublicKey>(v, sfPublicKey),
|
||||
json::getOrThrow<STAmount>(v, sfAmount),
|
||||
json::getOrThrow<STAmount>(v, sfSignatureReward),
|
||||
json::getOrThrow<AccountID>(v, sfAttestationRewardAccount),
|
||||
json::getOrThrow<bool>(v, sfWasLockingChainSend),
|
||||
json::getOrThrow<AccountID>(v, sfDestination)}
|
||||
{
|
||||
}
|
||||
|
||||
XChainCreateAccountAttestation::XChainCreateAccountAttestation(
|
||||
XChainCreateAccountAttestation::TSignedAttestation const& createAtt)
|
||||
: XChainCreateAccountAttestation{
|
||||
createAtt.attestationSignerAccount,
|
||||
createAtt.publicKey,
|
||||
createAtt.sendingAmount,
|
||||
createAtt.rewardAmount,
|
||||
createAtt.rewardAccount,
|
||||
createAtt.wasLockingChainSend,
|
||||
createAtt.toCreate}
|
||||
{
|
||||
}
|
||||
|
||||
STObject
|
||||
XChainCreateAccountAttestation::toSTObject() const
|
||||
{
|
||||
STObject o = STObject::makeInnerObject(sfXChainCreateAccountProofSig);
|
||||
|
||||
o[sfAttestationSignerAccount] = STAccount{sfAttestationSignerAccount, keyAccount};
|
||||
o[sfPublicKey] = publicKey;
|
||||
o[sfAmount] = STAmount{sfAmount, amount};
|
||||
o[sfSignatureReward] = STAmount{sfSignatureReward, rewardAmount};
|
||||
o[sfAttestationRewardAccount] = STAccount{sfAttestationRewardAccount, rewardAccount};
|
||||
o[sfWasLockingChainSend] = wasLockingChainSend;
|
||||
o[sfDestination] = STAccount{sfDestination, dst};
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
XChainCreateAccountAttestation::MatchFields::MatchFields(
|
||||
XChainCreateAccountAttestation::TSignedAttestation const& att)
|
||||
: amount{att.sendingAmount}
|
||||
, rewardAmount(att.rewardAmount)
|
||||
, wasLockingChainSend{att.wasLockingChainSend}
|
||||
, dst{att.toCreate}
|
||||
{
|
||||
}
|
||||
|
||||
AttestationMatch
|
||||
XChainCreateAccountAttestation::match(XChainCreateAccountAttestation::MatchFields const& rhs) const
|
||||
{
|
||||
if (std::tie(amount, rewardAmount, wasLockingChainSend) !=
|
||||
std::tie(rhs.amount, rhs.rewardAmount, rhs.wasLockingChainSend))
|
||||
return AttestationMatch::NonDstMismatch;
|
||||
if (dst != rhs.dst)
|
||||
return AttestationMatch::MatchExceptDst;
|
||||
return AttestationMatch::Match;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(XChainCreateAccountAttestation const& lhs, XChainCreateAccountAttestation const& rhs)
|
||||
{
|
||||
return std::tie(
|
||||
lhs.keyAccount,
|
||||
lhs.publicKey,
|
||||
lhs.amount,
|
||||
lhs.rewardAmount,
|
||||
lhs.rewardAccount,
|
||||
lhs.wasLockingChainSend,
|
||||
lhs.dst) ==
|
||||
std::tie(
|
||||
rhs.keyAccount,
|
||||
rhs.publicKey,
|
||||
rhs.amount,
|
||||
rhs.rewardAmount,
|
||||
rhs.rewardAccount,
|
||||
rhs.wasLockingChainSend,
|
||||
rhs.dst);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::XChainAttestationsBase(
|
||||
XChainAttestationsBase<TAttestation>::AttCollection&& atts)
|
||||
: attestations_{std::move(atts)}
|
||||
{
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::AttCollection::const_iterator
|
||||
XChainAttestationsBase<TAttestation>::begin() const
|
||||
{
|
||||
return attestations_.begin();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::AttCollection::const_iterator
|
||||
XChainAttestationsBase<TAttestation>::end() const
|
||||
{
|
||||
return attestations_.end();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::AttCollection::iterator
|
||||
XChainAttestationsBase<TAttestation>::begin()
|
||||
{
|
||||
return attestations_.begin();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::AttCollection::iterator
|
||||
XChainAttestationsBase<TAttestation>::end()
|
||||
{
|
||||
return attestations_.end();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::XChainAttestationsBase(json::Value const& v)
|
||||
{
|
||||
if (!v.isObject())
|
||||
{
|
||||
Throw<std::runtime_error>(
|
||||
"XChainAttestationsBase can only be specified with an 'object' "
|
||||
"Json value");
|
||||
}
|
||||
|
||||
attestations_ = [&] {
|
||||
auto const jAtts = v[jss::attestations];
|
||||
|
||||
if (jAtts.size() > kMaxAttestations)
|
||||
Throw<std::runtime_error>("XChainAttestationsBase exceeded max number of attestations");
|
||||
|
||||
std::vector<TAttestation> r;
|
||||
r.reserve(jAtts.size());
|
||||
for (auto const& a : jAtts)
|
||||
r.emplace_back(a);
|
||||
return r;
|
||||
}();
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
XChainAttestationsBase<TAttestation>::XChainAttestationsBase(STArray const& arr)
|
||||
{
|
||||
if (arr.size() > kMaxAttestations)
|
||||
Throw<std::runtime_error>("XChainAttestationsBase exceeded max number of attestations");
|
||||
|
||||
attestations_.reserve(arr.size());
|
||||
for (auto const& o : arr)
|
||||
attestations_.emplace_back(o);
|
||||
}
|
||||
|
||||
template <class TAttestation>
|
||||
STArray
|
||||
XChainAttestationsBase<TAttestation>::toSTArray() const
|
||||
{
|
||||
STArray r{TAttestation::arrayFieldName, attestations_.size()};
|
||||
for (auto const& e : attestations_)
|
||||
r.emplaceBack(e.toSTObject());
|
||||
return r;
|
||||
}
|
||||
|
||||
template class XChainAttestationsBase<XChainClaimAttestation>;
|
||||
template class XChainAttestationsBase<XChainCreateAccountAttestation>;
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
@@ -77,14 +78,23 @@ SHAMap::SHAMap(SHAMap const& other, bool isMutable)
|
||||
: f_(other.f_)
|
||||
, journal_(other.f_.journal())
|
||||
, cowid_(other.cowid_ + 1)
|
||||
, ledgerSeq_(other.ledgerSeq_)
|
||||
, ledgerSeq_(other.ledgerSeq())
|
||||
, root_(other.root_)
|
||||
, state_(isMutable ? SHAMapState::Modifying : SHAMapState::Immutable)
|
||||
, type_(other.type_)
|
||||
, backed_(other.backed_)
|
||||
{
|
||||
// A snapshot shares the source's root, so Invalid carries over. Read once into a local, since
|
||||
// the source's state can change while this runs.
|
||||
auto const otherState = other.state();
|
||||
auto const ownState = [&] {
|
||||
if (otherState == SHAMapState::Invalid)
|
||||
return SHAMapState::Invalid;
|
||||
return isMutable ? SHAMapState::Modifying : SHAMapState::Immutable;
|
||||
}();
|
||||
state_.store(ownState, std::memory_order_release);
|
||||
|
||||
// If either map may change, they cannot share nodes
|
||||
if ((state_ != SHAMapState::Immutable) || (other.state_ != SHAMapState::Immutable))
|
||||
if ((ownState != SHAMapState::Immutable) || (otherState != SHAMapState::Immutable))
|
||||
{
|
||||
unshare();
|
||||
}
|
||||
@@ -105,7 +115,7 @@ SHAMap::dirtyUp(NodePathStack& stack, UInt256 const& target, SHAMapTreeNodePtr c
|
||||
// child can be an inner node or a leaf
|
||||
|
||||
XRPL_ASSERT(
|
||||
(state_ != SHAMapState::Synching) && (state_ != SHAMapState::Immutable),
|
||||
(state() != SHAMapState::Synching) && (state() != SHAMapState::Immutable),
|
||||
"xrpl::SHAMap::dirtyUp : valid state");
|
||||
XRPL_ASSERT(child && (child->cowid() == cowid_), "xrpl::SHAMap::dirtyUp : valid child input");
|
||||
|
||||
@@ -170,7 +180,7 @@ SHAMapTreeNodePtr
|
||||
SHAMap::fetchNodeFromDB(SHAMapHash const& hash) const
|
||||
{
|
||||
XRPL_ASSERT(backed_, "xrpl::SHAMap::fetchNodeFromDB : is backed");
|
||||
auto const obj = f_.db().fetchNodeObject(hash.asUInt256(), ledgerSeq_);
|
||||
auto const obj = f_.db().fetchNodeObject(hash.asUInt256(), ledgerSeq());
|
||||
return finishFetch(hash, obj);
|
||||
}
|
||||
|
||||
@@ -183,10 +193,17 @@ SHAMap::finishFetch(SHAMapHash const& hash, std::shared_ptr<NodeObject> const& o
|
||||
{
|
||||
if (!object)
|
||||
{
|
||||
if (full_)
|
||||
// A missing node disproves full_, so withdraw it and report the gap. The exchange
|
||||
// makes exactly one reader report it, and its acquire pairs with the release store in
|
||||
// setFull(). It needs no release: the only other reader of full_ is this same path,
|
||||
// and a reader that loses the exchange does nothing with what the winner did. The load
|
||||
// ahead of it is relaxed, since all it decides is whether to try the exchange: a stale
|
||||
// true costs one exchange that loses, and a stale false means another reader won, or
|
||||
// setFull() is not visible yet and the gap goes unreported.
|
||||
if (full_.load(std::memory_order_relaxed) &&
|
||||
full_.exchange(false, std::memory_order_acquire))
|
||||
{
|
||||
full_ = false;
|
||||
f_.missingNodeAcquireBySeq(ledgerSeq_, hash.asUInt256());
|
||||
f_.missingNodeAcquireBySeq(ledgerSeq(), hash.asUInt256());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -219,7 +236,7 @@ SHAMap::checkFilter(SHAMapHash const& hash, SHAMapSyncFilter const* filter) cons
|
||||
auto node = SHAMapTreeNode::makeFromPrefix(makeSlice(*nodeData), hash);
|
||||
if (node)
|
||||
{
|
||||
filter->gotNode(true, hash, ledgerSeq_, std::move(*nodeData), node->getType());
|
||||
filter->gotNode(true, hash, ledgerSeq(), std::move(*nodeData), node->getType());
|
||||
if (backed_)
|
||||
canonicalize(hash, node);
|
||||
}
|
||||
@@ -399,7 +416,7 @@ SHAMap::descendAsync(
|
||||
{
|
||||
f_.db().asyncFetch(
|
||||
hash.asUInt256(),
|
||||
ledgerSeq_,
|
||||
ledgerSeq(),
|
||||
[this, hash, cb{std::move(callback)}](std::shared_ptr<NodeObject> const& object) {
|
||||
auto const node = finishFetch(hash, object);
|
||||
cb(node, hash);
|
||||
@@ -424,7 +441,7 @@ SHAMap::unshareNode(intr_ptr::SharedPtr<Node> node, SHAMapNodeID const& nodeID)
|
||||
if (node->cowid() != cowid_)
|
||||
{
|
||||
// have a CoW
|
||||
XRPL_ASSERT(state_ != SHAMapState::Immutable, "xrpl::SHAMap::unshareNode : not immutable");
|
||||
XRPL_ASSERT(state() != SHAMapState::Immutable, "xrpl::SHAMap::unshareNode : not immutable");
|
||||
node = intr_ptr::staticPointerCast<Node>(node->clone(cowid_));
|
||||
if (nodeID.isRoot())
|
||||
root_ = node;
|
||||
@@ -637,7 +654,7 @@ bool
|
||||
SHAMap::delItem(UInt256 const& id)
|
||||
{
|
||||
// delete the item with this ID
|
||||
XRPL_ASSERT(state_ != SHAMapState::Immutable, "xrpl::SHAMap::delItem : not immutable");
|
||||
XRPL_ASSERT(state() != SHAMapState::Immutable, "xrpl::SHAMap::delItem : not immutable");
|
||||
|
||||
NodePathStack stack;
|
||||
walkTowardsKey(id, &stack);
|
||||
@@ -719,7 +736,7 @@ SHAMap::delItem(UInt256 const& id)
|
||||
bool
|
||||
SHAMap::addGiveItem(SHAMapNodeType type, boost::intrusive_ptr<SHAMapItem const> item)
|
||||
{
|
||||
XRPL_ASSERT(state_ != SHAMapState::Immutable, "xrpl::SHAMap::addGiveItem : not immutable");
|
||||
XRPL_ASSERT(state() != SHAMapState::Immutable, "xrpl::SHAMap::addGiveItem : not immutable");
|
||||
XRPL_ASSERT(type != SHAMapNodeType::TnInner, "xrpl::SHAMap::addGiveItem : valid type input");
|
||||
|
||||
// add the specified item, does not update
|
||||
@@ -810,7 +827,7 @@ SHAMap::updateGiveItem(SHAMapNodeType type, boost::intrusive_ptr<SHAMapItem cons
|
||||
// can't change the tag but can change the hash
|
||||
UInt256 const tag = item->key();
|
||||
|
||||
XRPL_ASSERT(state_ != SHAMapState::Immutable, "xrpl::SHAMap::updateGiveItem : not immutable");
|
||||
XRPL_ASSERT(state() != SHAMapState::Immutable, "xrpl::SHAMap::updateGiveItem : not immutable");
|
||||
|
||||
NodePathStack stack;
|
||||
walkTowardsKey(tag, &stack);
|
||||
@@ -901,7 +918,7 @@ SHAMap::writeNode(NodeObjectType t, SHAMapTreeNodePtr node) const
|
||||
|
||||
Serializer s;
|
||||
node->serializeWithPrefix(s);
|
||||
f_.db().store(t, std::move(s.modData()), node->getHash().asUInt256(), ledgerSeq_);
|
||||
f_.db().store(t, std::move(s.modData()), node->getHash().asUInt256(), ledgerSeq());
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <xrpl/shamap/detail/TaggedPointer.h>
|
||||
#include <xrpl/shamap/detail/TaggedPointer.ipp>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
@@ -77,7 +78,9 @@ SHAMapInnerNode::clone(std::uint32_t cowid) const
|
||||
auto p = intr_ptr::makeShared<SHAMapInnerNode>(cowid, branchCount);
|
||||
p->hash_ = hash_;
|
||||
p->isBranch_ = isBranch_;
|
||||
p->fullBelowGen_ = fullBelowGen_;
|
||||
// Relaxed, as everywhere. p is not reachable by another thread until this returns.
|
||||
p->fullBelowGen_.store(
|
||||
fullBelowGen_.load(std::memory_order_relaxed), std::memory_order_relaxed);
|
||||
SHAMapHash* cloneHashes = nullptr;
|
||||
SHAMapHash* thisHashes = nullptr;
|
||||
SHAMapTreeNodePtr* cloneChildren = nullptr;
|
||||
|
||||
@@ -31,6 +31,25 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Whether a depth is at or past the deepest an inner node may occupy.
|
||||
*
|
||||
* Nibbles run out at SHAMap::kLeafDepth, so only a leaf may sit there. True for
|
||||
* every deeper position too, which lies past the end of a key.
|
||||
*
|
||||
* @param depth The depth to judge.
|
||||
* @return Whether an inner node at that depth makes the map impossible.
|
||||
*/
|
||||
[[nodiscard]] bool
|
||||
isLeafDepth(unsigned int depth)
|
||||
{
|
||||
return depth >= SHAMap::kLeafDepth;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void
|
||||
SHAMap::visitLeaves(
|
||||
std::function<void(boost::intrusive_ptr<SHAMapItem const> const& item)> const& leafFunction)
|
||||
@@ -143,13 +162,10 @@ SHAMap::visitDifferences(
|
||||
if (!function(*node))
|
||||
return;
|
||||
|
||||
// Nibbles run out at kLeafDepth, so only a leaf belongs there. A well-formed map never
|
||||
// holds an inner node at that depth: addKnownNode marks the map invalid rather than hooking
|
||||
// one in, and fetch-pack data is hash-verified against a validated root, so reaching this
|
||||
// means a defect or a corrupt store, not something a peer can provoke. Report the node
|
||||
// anyway - the wire form carries no depth, and the recipient hooks blobs in by hash - but
|
||||
// skip the children rather than letting getChildNodeID throw on them.
|
||||
if (nodeID.getDepth() >= kLeafDepth)
|
||||
// Only a leaf belongs at kLeafDepth. The node is still reported, since the wire form
|
||||
// carries no depth and the recipient hooks blobs by hash. Its children are skipped, since
|
||||
// getChildNodeID has no answer past kLeafDepth.
|
||||
if (isLeafDepth(nodeID.getDepth()))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::SHAMap::visitDifferences : inner node at leaf depth");
|
||||
@@ -207,7 +223,12 @@ SHAMap::gmnProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se)
|
||||
// we already know this child node is missing
|
||||
fullBelow = false;
|
||||
}
|
||||
else if (!backed_ || !f_.getFullBelowCache()->touchIfExists(childHash.asUInt256()))
|
||||
// The depth test precedes the cache lookup for the same reason it does in addKnownNode():
|
||||
// the cache is keyed by node hash and shared across maps, and a hash covers a node's
|
||||
// children but not its depth. Skipping the shortcut forgoes an optimization only.
|
||||
else if (
|
||||
!backed_ || isLeafDepth(nodeID.getDepth() + 1) ||
|
||||
!f_.getFullBelowCache()->touchIfExists(childHash.asUInt256()))
|
||||
{
|
||||
bool pending = false;
|
||||
auto d = descendAsync(
|
||||
@@ -238,6 +259,17 @@ SHAMap::gmnProcessNodes(MissingNodes& mn, MissingNodes::StackEntry& se)
|
||||
if (--mn.max <= 0)
|
||||
return;
|
||||
}
|
||||
else if (d->isInner() && isLeafDepth(nodeID.getDepth() + 1))
|
||||
{
|
||||
// Only a leaf belongs that deep (see isLeafDepth and SHAMap::addKnownNode). A node
|
||||
// resolved locally reaches the walk without passing through addKnownNode(), so the
|
||||
// walk reaches this verdict itself. Ordered ahead of the full-below test below,
|
||||
// which canonicalization shares across maps.
|
||||
JLOG(journal_.warn()) << "Inner node at branch " << branch << " below " << nodeID
|
||||
<< " makes the map invalid";
|
||||
setInvalid();
|
||||
return;
|
||||
}
|
||||
else if (d->isInner() && !safeDowncast<SHAMapInnerNode*>(d)->isFullBelow(mn.generation))
|
||||
{
|
||||
mn.stack.push(se);
|
||||
@@ -301,6 +333,8 @@ SHAMap::gmnProcessDeferredReads(MissingNodes& mn)
|
||||
}
|
||||
else if ((mn.max > 0) && mn.missingHashes.insert(nodeHash).second)
|
||||
{
|
||||
// getChildNodeID() is safe here: gmnProcessNodes refuses to descend into an inner node
|
||||
// at kLeafDepth, so a deferred parent sits at most one level above it.
|
||||
mn.missingNodes.emplace_back(parentID.getChildNodeID(branch), nodeHash.asUInt256());
|
||||
--mn.max;
|
||||
}
|
||||
@@ -311,17 +345,20 @@ SHAMap::gmnProcessDeferredReads(MissingNodes& mn)
|
||||
mn.deferred = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of node IDs and hashes for nodes that are part of this SHAMap
|
||||
* but not available locally. The filter can hold alternate sources of
|
||||
* nodes that are not permanently stored locally
|
||||
*/
|
||||
std::vector<std::pair<SHAMapNodeID, UInt256>>
|
||||
SHAMap::getMissingNodes(int max, SHAMapSyncFilter const* filter)
|
||||
{
|
||||
XRPL_ASSERT(root_->getHash().isNonZero(), "xrpl::SHAMap::getMissingNodes : nonzero root hash");
|
||||
XRPL_ASSERT(max > 0, "xrpl::SHAMap::getMissingNodes : valid max input");
|
||||
|
||||
if (!isValid())
|
||||
{
|
||||
// The root node's own hash, since getHash() unshares the tree on a zero hash.
|
||||
JLOG(journal_.warn()) << "getMissingNodes called on an invalid map, root hash "
|
||||
<< root_->getHash() << " seq " << ledgerSeq();
|
||||
return {};
|
||||
}
|
||||
|
||||
MissingNodes mn(
|
||||
max,
|
||||
filter,
|
||||
@@ -354,6 +391,11 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter const* filter)
|
||||
{
|
||||
gmnProcessNodes(mn, pos);
|
||||
|
||||
// The walk just invalidated the map. The loop stops descending here but falls through
|
||||
// to the drain below, since every posted read must be drained while `mn` is alive.
|
||||
if (!isValid())
|
||||
break;
|
||||
|
||||
if (mn.max <= 0)
|
||||
break;
|
||||
|
||||
@@ -383,6 +425,11 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter const* filter)
|
||||
if (mn.deferred != 0)
|
||||
gmnProcessDeferredReads(mn);
|
||||
|
||||
// Reads are drained, so the map can be abandoned. What was collected belongs to a tree
|
||||
// that cannot exist.
|
||||
if (!isValid())
|
||||
return {};
|
||||
|
||||
if (mn.max <= 0)
|
||||
return std::move(mn.missingNodes);
|
||||
|
||||
@@ -416,6 +463,11 @@ SHAMap::getMissingNodes(int max, SHAMapSyncFilter const* filter)
|
||||
|
||||
} while (node != nullptr);
|
||||
|
||||
// addKnownNode() on another thread can write the verdict after the loop's own test, so the map
|
||||
// is judged once more before the result is returned.
|
||||
if (!isValid())
|
||||
return {}; // LCOV_EXCL_LINE: only that other thread reaches this, so no test does
|
||||
|
||||
if (mn.missingNodes.empty())
|
||||
clearSynching();
|
||||
|
||||
@@ -527,11 +579,19 @@ SHAMap::addRootNode(
|
||||
XRPL_ASSERT(cowid_ >= 1, "xrpl::SHAMap::addRootNode : valid cowid");
|
||||
XRPL_ASSERT(rootNode, "xrpl::SHAMap::addRootNode : non-null root node");
|
||||
|
||||
// we already have a root_ node
|
||||
// A map syncs against one hash and installs a root once, so a root already held is a duplicate
|
||||
// only once it hashes to the hash asked for.
|
||||
if (root_->getHash().isNonZero())
|
||||
{
|
||||
JLOG(journal_.trace()) << "Got root node, already have one";
|
||||
XRPL_ASSERT(root_->getHash() == hash, "xrpl::SHAMap::addRootNode : valid hash");
|
||||
|
||||
if (root_->getHash() != hash)
|
||||
{
|
||||
JLOG(journal_.warn()) << "Root node offered under hash " << hash
|
||||
<< ", but the map holds " << root_->getHash();
|
||||
return SHAMapAddNode::invalid();
|
||||
}
|
||||
|
||||
return SHAMapAddNode::duplicate();
|
||||
}
|
||||
|
||||
@@ -555,7 +615,7 @@ SHAMap::addRootNode(
|
||||
Serializer s;
|
||||
root_->serializeWithPrefix(s);
|
||||
filter->gotNode(
|
||||
false, root_->getHash(), ledgerSeq_, std::move(s.modData()), root_->getType());
|
||||
false, root_->getHash(), ledgerSeq(), std::move(s.modData()), root_->getType());
|
||||
}
|
||||
|
||||
return SHAMapAddNode::useful();
|
||||
@@ -598,7 +658,13 @@ SHAMap::addKnownNode(
|
||||
}
|
||||
|
||||
auto childHash = inner->getChildHash(branch);
|
||||
if (f_.getFullBelowCache()->touchIfExists(childHash.asUInt256()))
|
||||
|
||||
// Depth before the cache: the cache is keyed by node hash and shared across the family, and
|
||||
// a hash covers a node's children but not its depth, so the same subtree can be cached as
|
||||
// complete at one depth and reached at another. Skipping the shortcut only forgoes an
|
||||
// optimization.
|
||||
if (!isLeafDepth(currNodeID.getDepth() + 1) &&
|
||||
f_.getFullBelowCache()->touchIfExists(childHash.asUInt256()))
|
||||
{
|
||||
return SHAMapAddNode::duplicate();
|
||||
}
|
||||
@@ -616,25 +682,32 @@ SHAMap::addKnownNode(
|
||||
return SHAMapAddNode::invalid();
|
||||
}
|
||||
|
||||
// Inner nodes must be at a level strictly less than 64
|
||||
// but leaf nodes (while notionally at level 64) can be
|
||||
// at any depth up to and including 64:
|
||||
if ((currNodeID.getDepth() > kLeafDepth) ||
|
||||
(treeNode->isInner() && currNodeID.getDepth() == kLeafDepth))
|
||||
// Only leaves may sit at kLeafDepth (see isLeafDepth), so an inner node there makes the map
|
||||
// impossible. The node is reported as bad data.
|
||||
//
|
||||
// Every node from the root down hash-verified to get here, so it is the requested root hash
|
||||
// itself that commits to a shape no valid tree can have. The verdict belongs to that hash
|
||||
// rather than to our copy of the tree.
|
||||
bool const badDepth = treeNode->isInner() && isLeafDepth(currNodeID.getDepth());
|
||||
SOMETIMES(badDepth, "xrpl::SHAMap::addKnownNode : map is invalid");
|
||||
if (badDepth)
|
||||
{
|
||||
// Map is provably invalid
|
||||
state_ = SHAMapState::Invalid;
|
||||
return SHAMapAddNode::useful();
|
||||
JLOG(journal_.warn()) << "Node " << nodeID << " makes the map invalid at "
|
||||
<< currNodeID;
|
||||
setInvalid();
|
||||
return SHAMapAddNode::invalid();
|
||||
}
|
||||
|
||||
if (currNodeID != nodeID)
|
||||
// The data hashes to the child at currNodeID but claims to belong at nodeID, so it is not
|
||||
// the node that was asked for. Only the label is wrong, so the map stays sound and the node
|
||||
// is still obtainable from another sender.
|
||||
bool const badPosition = (currNodeID != nodeID);
|
||||
SOMETIMES(badPosition, "xrpl::SHAMap::addKnownNode : node ID does not match its position");
|
||||
if (badPosition)
|
||||
{
|
||||
// Either this node is broken or we didn't request it (yet)
|
||||
JLOG(journal_.warn()) << "unable to hook node " << nodeID;
|
||||
JLOG(journal_.info()) << " stuck at " << currNodeID;
|
||||
JLOG(journal_.info()) << "got depth=" << nodeID.getDepth()
|
||||
<< ", walked to= " << currNodeID.getDepth();
|
||||
return SHAMapAddNode::useful();
|
||||
JLOG(journal_.warn()) << "Unable to hook node " << nodeID << ", stuck at "
|
||||
<< currNodeID;
|
||||
return SHAMapAddNode::invalid();
|
||||
}
|
||||
|
||||
if (backed_)
|
||||
@@ -647,7 +720,7 @@ SHAMap::addKnownNode(
|
||||
Serializer s;
|
||||
treeNode->serializeWithPrefix(s);
|
||||
filter->gotNode(
|
||||
false, childHash, ledgerSeq_, std::move(s.modData()), treeNode->getType());
|
||||
false, childHash, ledgerSeq(), std::move(s.modData()), treeNode->getType());
|
||||
}
|
||||
|
||||
return SHAMapAddNode::useful();
|
||||
@@ -766,7 +839,7 @@ SHAMap::hasLeafNode(UInt256 const& tag, SHAMapHash const& targetNodeHash) const
|
||||
// Same kLeafDepth hazard as in visitDifferences above. That guard bounds the caller's own
|
||||
// traversal, not the map queried here, and the loop below descends from this map's root
|
||||
// independently, so this check is what keeps a malformed map from reaching getChildNodeID.
|
||||
if (nodeID.getDepth() >= kLeafDepth)
|
||||
if (isLeafDepth(nodeID.getDepth()))
|
||||
{
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE("xrpl::SHAMap::hasLeafNode : inner node at leaf depth");
|
||||
@@ -849,8 +922,8 @@ SHAMap::verifyProofPath(UInt256 const& rootHash, UInt256 const& key, std::vector
|
||||
// there. These nodes come off the wire, so a peer can still claim an inner one;
|
||||
// reject it rather than passing this depth to selectBranch.
|
||||
SOMETIMES(
|
||||
depth >= kLeafDepth, "xrpl::SHAMap::verifyProofPath : inner at leaf depth");
|
||||
if (depth >= kLeafDepth)
|
||||
isLeafDepth(depth), "xrpl::SHAMap::verifyProofPath : inner at leaf depth");
|
||||
if (isLeafDepth(depth))
|
||||
return false;
|
||||
|
||||
auto const nodeId = SHAMapNodeID::createID(depth, key);
|
||||
@@ -859,10 +932,9 @@ SHAMap::verifyProofPath(UInt256 const& rootHash, UInt256 const& key, std::vector
|
||||
}
|
||||
else
|
||||
{
|
||||
// The hash chain up to rootHash only proves this leaf sits where the path claims,
|
||||
// not that it is the leaf for `key`: a peer could substitute any other leaf whose
|
||||
// subtree hashes to the same value at every level above it. Checking the terminal
|
||||
// leaf's own key is what ties the proof to `key` specifically.
|
||||
// The hash chain up to rootHash proves this leaf sits where the path claims. Any
|
||||
// leaf whose subtree hashes the same at every level above satisfies that chain, so
|
||||
// the terminal leaf's own key is what ties the proof to `key`.
|
||||
if (leafKey(*node) != key)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <xrpl/protocol/detail/transactions.macro>
|
||||
|
||||
#undef TRANSACTION
|
||||
#undef TRANSACTION_INCLUDE
|
||||
|
||||
#pragma pop_macro("TRANSACTION")
|
||||
|
||||
// DO NOT INCLUDE TRANSACTOR HEADER FILES HERE.
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
#include <xrpl/tx/invariants/CosignerInvariant.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/Protocol.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STArray.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STObject.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/SeqProxy.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
#include <xrpl/protocol/XRPAmount.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
validSignerArray(STArray const& signers, std::size_t limit, SField const& elementName)
|
||||
{
|
||||
if (signers.size() > limit)
|
||||
return false;
|
||||
|
||||
std::optional<AccountID> previous;
|
||||
for (auto const& signer : signers)
|
||||
{
|
||||
if (signer.getFName() != elementName || !signer.isFieldPresent(sfAccount))
|
||||
return false;
|
||||
|
||||
auto const account = signer.getAccountID(sfAccount);
|
||||
if (previous && account <= *previous)
|
||||
return false;
|
||||
previous = account;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
validNestedSigners(STObject const& signature)
|
||||
{
|
||||
return !signature.isFieldPresent(sfSigners) ||
|
||||
validSignerArray(signature.getFieldArray(sfSigners), STTx::kMaxMultiSigners, sfSigner);
|
||||
}
|
||||
|
||||
bool
|
||||
validSignerArrays(STObject const& proposedTx)
|
||||
{
|
||||
if (!validNestedSigners(proposedTx))
|
||||
return false;
|
||||
|
||||
for (auto const* field :
|
||||
std::array<SField const*, 2>{&sfCounterpartySignature, &sfSponsorSignature})
|
||||
{
|
||||
if (proposedTx.isFieldPresent(*field) &&
|
||||
!validNestedSigners(proposedTx.getFieldObject(*field)))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!proposedTx.isFieldPresent(sfBatchSigners))
|
||||
return true;
|
||||
|
||||
auto const& batchSigners = proposedTx.getFieldArray(sfBatchSigners);
|
||||
if (!validSignerArray(batchSigners, kMaxBatchSigners, sfBatchSigner))
|
||||
return false;
|
||||
|
||||
return std::ranges::all_of(
|
||||
batchSigners, [](auto const& batchSigner) { return validNestedSigners(batchSigner); });
|
||||
}
|
||||
|
||||
// The Ticket a proposal is keyed to: the one its proposed transaction spends.
|
||||
uint256
|
||||
proposalTicketKey(SLE const& proposal)
|
||||
{
|
||||
auto const& proposedTx = proposal.getFieldObject(sfProposedTransaction);
|
||||
return keylet::ticket(
|
||||
proposedTx.getAccountID(sfAccount),
|
||||
SeqProxy::rawTicket(proposedTx.getFieldU32(sfTicketSequence)))
|
||||
.key;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void
|
||||
ValidTransactionProposal::visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after)
|
||||
{
|
||||
// `after` is always present (on deletion it holds the final state), so it
|
||||
// alone determines the entry type. LedgerEntryTypesMatch owns malformed
|
||||
// type transitions; skip them rather than read one side with the other's
|
||||
// schema.
|
||||
if (!after || (before && before->getType() != after->getType()))
|
||||
return;
|
||||
|
||||
auto const type = after->getType();
|
||||
|
||||
// Consuming a Ticket deletes the proposal keyed to it (XLS-0103 §4.5).
|
||||
// Remember each Ticket that went, so finalize can tell a proposal deleted
|
||||
// with its Ticket from one that simply vanished, and the proposal each
|
||||
// Ticket was keyed to, so finalize can check that none stayed behind.
|
||||
if (type == ltTICKET)
|
||||
{
|
||||
if (isDelete)
|
||||
{
|
||||
deletedTickets_.insert(after->key());
|
||||
proposalsOfDeletedTickets_.push_back(
|
||||
keylet::txProposal(
|
||||
after->getAccountID(sfAccount), after->getFieldU32(sfTicketSequence)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != ltTRANSACTION_PROPOSAL)
|
||||
return;
|
||||
|
||||
if (!before)
|
||||
{
|
||||
++created_;
|
||||
}
|
||||
else if (isDelete)
|
||||
{
|
||||
++deleted_;
|
||||
ticketsOfDeletedProposals_.push_back(proposalTicketKey(*before));
|
||||
}
|
||||
else
|
||||
{
|
||||
++modified_;
|
||||
}
|
||||
|
||||
// A live proposal's signer lists must stay submittable: within size
|
||||
// limits, sorted by account, and free of duplicates.
|
||||
if (!isDelete && !validSignerArrays(after->getFieldObject(sfProposedTransaction)))
|
||||
invalidSignerArrays_ = true;
|
||||
}
|
||||
|
||||
bool
|
||||
ValidTransactionProposal::finalize(
|
||||
STTx const& tx,
|
||||
TER result,
|
||||
XRPAmount,
|
||||
ReadView const& view,
|
||||
beast::Journal const& j) const
|
||||
{
|
||||
if (!view.rules().enabled(featureCosign))
|
||||
return true;
|
||||
|
||||
if (invalidSignerArrays_)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: TransactionProposal signer arrays are not canonical.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// A proposal leaves the ledger in two ways (XLS-0103 §4.5): a
|
||||
// TransactionProposalCancel deletes the proposal it names, and consuming
|
||||
// the Ticket a proposal is keyed to deletes the proposal with it, whether
|
||||
// the proposed transaction executed (or failed with a claimed-fee tec) or
|
||||
// AccountDelete swept the target's Tickets.
|
||||
std::uint32_t deletedWithTicket = 0;
|
||||
for (auto const& ticketKey : ticketsOfDeletedProposals_)
|
||||
{
|
||||
if (deletedTickets_.contains(ticketKey))
|
||||
++deletedWithTicket;
|
||||
}
|
||||
|
||||
bool const succeeded = isTesSuccess(result);
|
||||
bool effectsMatch = false;
|
||||
if (tx.getTxnType() == ttTRANSACTION_PROPOSAL_CREATE)
|
||||
{
|
||||
effectsMatch = created_ == (succeeded ? 1u : 0u) && modified_ == 0 && deleted_ == 0;
|
||||
}
|
||||
else if (tx.getTxnType() == ttTRANSACTION_PROPOSAL_CANCEL)
|
||||
{
|
||||
// A Cancel deletes one proposal and nothing else. It cannot
|
||||
// spend a reserved Ticket, so no proposal goes with its Ticket here.
|
||||
effectsMatch = created_ == 0 && modified_ == 0 && deletedWithTicket == 0 &&
|
||||
deleted_ == (succeeded ? 1u : 0u);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Any other transaction deletes a proposal only together with its
|
||||
// Ticket, and modifies at most one, only as a successful
|
||||
// SponsorshipTransfer.
|
||||
// TODO: extend this when TransactionProposalSign is implemented.
|
||||
std::uint32_t const modifiable =
|
||||
tx.getTxnType() == ttSPONSORSHIP_TRANSFER && succeeded ? 1 : 0;
|
||||
effectsMatch = created_ == 0 && modified_ <= modifiable && deleted_ == deletedWithTicket;
|
||||
}
|
||||
|
||||
if (!effectsMatch)
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Invariant failed: TransactionProposal changes do not match transaction result.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// The other direction of the deletion rule: ticketDelete deletes the
|
||||
// proposal keyed to a Ticket along with it (XLS-0103 §4.5), so no
|
||||
// proposal may outlive its Ticket, orphaned on a key that can no longer
|
||||
// be spent.
|
||||
bool const orphaned = std::ranges::any_of(
|
||||
proposalsOfDeletedTickets_, [&view](Keylet const& keylet) { return view.exists(keylet); });
|
||||
if (orphaned)
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Invariant failed: TransactionProposal outlived the Ticket it is keyed to.";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Issue.h>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/STVector256.h>
|
||||
#include <xrpl/protocol/SystemParameters.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
#include <xrpl/protocol/TxFormats.h>
|
||||
@@ -933,8 +935,12 @@ ValidClawback::finalize(
|
||||
return !mptV2Enabled;
|
||||
}
|
||||
|
||||
// IOU balances keep 16 significant digits, so a clawback
|
||||
// much smaller than the balance changes it by a rounded
|
||||
// amount, possibly zero. Compare with the same rounded
|
||||
// subtraction the balance update performs.
|
||||
if (*afterBalance > *beforeBalance ||
|
||||
(*beforeBalance - *afterBalance) != std::min(*beforeBalance, clawAmount))
|
||||
*afterBalance != *beforeBalance - std::min(*beforeBalance, clawAmount))
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
<< "Invariant failed: trustline clawback balance change is invalid";
|
||||
@@ -1010,6 +1016,78 @@ ValidClawback::finalize(
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Whether `entry` is the trust line or MPToken through which `account` holds
|
||||
// `asset`. XRP has no such entry.
|
||||
static bool
|
||||
isHolding(SLE const& entry, Asset const& asset, AccountID const& account)
|
||||
{
|
||||
return asset.visit(
|
||||
[&](Issue const& issue) {
|
||||
return !isXRP(issue) && keylet::trustLine(account, issue).check(entry);
|
||||
},
|
||||
[&](MPTIssue const& issue) {
|
||||
return keylet::mptoken(issue.getMptID(), account).check(entry);
|
||||
});
|
||||
}
|
||||
|
||||
// Whether `entry`, linked into the owner directory of `pseudo`, belongs to the
|
||||
// AMM, Vault or LoanBroker that the pseudo-account was created for.
|
||||
static bool
|
||||
isOwnedByPseudoAccount(ReadView const& view, SLE const& pseudo, SLE const& entry)
|
||||
{
|
||||
auto const pseudoAcctID = pseudo[sfAccount];
|
||||
|
||||
if (pseudo.isFieldPresent(sfAMMID))
|
||||
{
|
||||
if (entry.getType() == ltAMM)
|
||||
return entry.key() == pseudo[sfAMMID];
|
||||
|
||||
auto const amm = view.read(keylet::amm(pseudo[sfAMMID]));
|
||||
if (!amm)
|
||||
return false; // LCOV_EXCL_LINE
|
||||
if (isHolding(entry, (*amm)[sfAsset], pseudoAcctID) ||
|
||||
isHolding(entry, (*amm)[sfAsset2], pseudoAcctID))
|
||||
return true;
|
||||
|
||||
// The AMM issues LP tokens, so each liquidity provider's trust line
|
||||
// links into its directory.
|
||||
if (entry.getType() != ltRIPPLE_STATE)
|
||||
return false;
|
||||
auto const low = entry[sfLowLimit].getIssuer();
|
||||
auto const high = entry[sfHighLimit].getIssuer();
|
||||
auto const lpCurrency = (*amm)[sfLPTokenBalance].get<Issue>().currency;
|
||||
return (low == pseudoAcctID || high == pseudoAcctID) &&
|
||||
entry.key() == keylet::trustLine(low, high, lpCurrency).key;
|
||||
}
|
||||
|
||||
if (pseudo.isFieldPresent(sfVaultID))
|
||||
{
|
||||
if (entry.getType() == ltLOAN_BROKER)
|
||||
return entry[sfVaultID] == pseudo[sfVaultID];
|
||||
|
||||
auto const vault = view.read(keylet::vault(pseudo[sfVaultID]));
|
||||
if (!vault)
|
||||
return false; // LCOV_EXCL_LINE
|
||||
return keylet::mptokenIssuance((*vault)[sfShareMPTID]).check(entry) ||
|
||||
isHolding(entry, (*vault)[sfAsset], pseudoAcctID);
|
||||
}
|
||||
|
||||
if (pseudo.isFieldPresent(sfLoanBrokerID))
|
||||
{
|
||||
if (entry.getType() == ltLOAN)
|
||||
return entry[sfLoanBrokerID] == pseudo[sfLoanBrokerID];
|
||||
|
||||
auto const broker = view.read(keylet::loanBroker(pseudo[sfLoanBrokerID]));
|
||||
if (!broker)
|
||||
return false; // LCOV_EXCL_LINE
|
||||
auto const vault = view.read(keylet::vault((*broker)[sfVaultID]));
|
||||
return vault && isHolding(entry, (*vault)[sfAsset], pseudoAcctID);
|
||||
}
|
||||
|
||||
// A new pseudo-account kind must say what it owns.
|
||||
return false; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
void
|
||||
ValidPseudoAccounts::visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after)
|
||||
{
|
||||
@@ -1019,6 +1097,33 @@ ValidPseudoAccounts::visitEntry(bool isDelete, SLE::ConstRef before, SLE::ConstR
|
||||
return;
|
||||
}
|
||||
|
||||
// Only owner directory pages carry sfOwner; book directories don't.
|
||||
if (after && after->getType() == ltDIR_NODE && after->isFieldPresent(sfOwner))
|
||||
{
|
||||
auto const& afterIndexes = after->getFieldV256(sfIndexes);
|
||||
std::vector<uint256> added;
|
||||
if (!before)
|
||||
{
|
||||
added.assign(afterIndexes.begin(), afterIndexes.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const& beforeIndexes = before->getFieldV256(sfIndexes);
|
||||
for (auto const& index : afterIndexes)
|
||||
{
|
||||
if (!std::ranges::contains(beforeIndexes, index))
|
||||
added.push_back(index);
|
||||
}
|
||||
}
|
||||
|
||||
if (!added.empty())
|
||||
{
|
||||
auto& owned = ownerDirAdditions_[after->getAccountID(sfOwner)];
|
||||
owned.insert(owned.end(), added.begin(), added.end());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (after && after->getType() == ltACCOUNT_ROOT)
|
||||
{
|
||||
bool const isPseudo = [&] {
|
||||
@@ -1100,6 +1205,39 @@ ValidPseudoAccounts::finalize(
|
||||
if (enforce)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pre-fixCleanup3_5_0: what a pseudo-account owns is not checked.
|
||||
// Post-fixCleanup3_5_0: it may own only what belongs to its AMM, Vault or
|
||||
// LoanBroker.
|
||||
if (!view.rules().enabled(fixCleanup3_5_0))
|
||||
return true;
|
||||
|
||||
for (auto const& [owner, indexes] : ownerDirAdditions_)
|
||||
{
|
||||
auto const root = view.read(keylet::account(owner));
|
||||
if (!root || !isPseudoAccount(root))
|
||||
continue;
|
||||
|
||||
for (auto const& index : indexes)
|
||||
{
|
||||
auto const sle = view.read(keylet::unchecked(index));
|
||||
if (!sle)
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: pseudo-account " << toBase58(owner)
|
||||
<< " owner directory links a missing object " << to_string(index);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isOwnedByPseudoAccount(view, *root, *sle))
|
||||
{
|
||||
JLOG(j.fatal()) << "Invariant failed: pseudo-account " << toBase58(owner)
|
||||
<< " may not own " << ledgerEntryTypeName(*sle) << " "
|
||||
<< to_string(index);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/ledger/helpers/VaultHelpers.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
@@ -160,7 +160,7 @@ ValidLoanBroker::finalize(
|
||||
roundToAsset(
|
||||
Asset{vault->at(sfAsset)},
|
||||
debtTotal,
|
||||
getAssetsTotalScale(vault),
|
||||
getVaultScale(vault),
|
||||
Number::RoundingMode::TowardsZero) != beast::kZero)
|
||||
{
|
||||
JLOG(j.fatal())
|
||||
|
||||
Loaded 100 of 311 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user