Compare commits

...

34 Commits

Author SHA1 Message Date
Mayukha Vadari
e270a68e3d fix: Remove the XChainBridge ledger entry wrappers
develop added a typed wrapper per ledger entry after this branch was
last updated, including BridgeEntry, XChainOwnedClaimIDEntry and
XChainOwnedCreateAccountClaimIDEntry, whose headers include the deleted
STXChainBridge.h. Delete those three wrappers and their tests, and drop
them from the SLEBase test's include list.
2026-09-22 23:39:16 +05:30
Mayukha Vadari
20ce5e50ca Merge remote-tracking branch 'upstream/develop' into mvadari/remove-xcb 2026-09-22 23:07:49 +05:30
Mayukha Vadari
3797b917ec fix: Correct includes flagged by clang-tidy
Removing XChainBridge changed which headers are reachable transitively,
so misc-include-cleaner failed on the PR.

STXChainBridge.h used to pull in STObject.h and Serializer.h, so
STParsedJSON.cpp, LedgerEntry.cpp and LedgerEntry_test.cpp now include
them directly. LedgerEntry_test.cpp also needs PublicKey.h.

Indexes.cpp no longer uses SField.h, and the tests no longer use
envconfig.h or multisign.h, so those includes are dropped.

STObject.h needs the complete STAccount type for its Proxy templates,
but include-cleaner does not see a direct use, so its STAccount.h
include carries an IWYU keep pragma. ApplyStateTable.cpp gets the type
from STObject.h and does not need its own include.
2026-09-22 22:14:36 +05:30
Bart
00606bec1a fix: Derive traversal node IDs from the branch actually descended (#7942)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-22 14:02:11 +00:00
Mayukha Vadari
2bc17c3e73 refactor: Add initial wrapper classes for all SLEs (#7886) 2026-09-21 19:47:23 +00:00
Mayukha Vadari
b6cda0e1bd feat: Remove XChainBridge 2026-09-21 23:32:00 +05:30
dependabot[bot]
0229c294a9 ci: [DEPENDABOT] bump codecov/codecov-action from 7.0.0 to 7.1.1 in the github-actions group across 1 directory (#8251)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-21 12:09:57 +00:00
Bart
184fe173fb refactor: Remove a dead unwrap from the WebSocket success path (#8252)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-21 11:23:31 +00:00
Bart
16f7b263fd docs: Correct three comments about null-terminated views (#8253)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-21 11:12:09 +00:00
Bart
f6b51f0b8b ci: Say when a package publish is a dry run (#8247)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-18 18:31:07 +00:00
Denis Angell
07b36871c7 ci: Publish packages through packages-upload.xrplf.org (#8241) 2026-09-17 18:05:51 +00:00
Bart
638ae08eeb chore: Bump version to 3.5.0-b0 2026-09-17 13:33:08 +02:00
yinyiqian1
24be48ee84 fix: Reject PaymentBurn payments that cross zero balance 2026-09-17 13:33:08 +02:00
Pratik Mankawde
e20f448a71 fix: Reject variable-length prefixes the encoder cannot write 2026-09-17 13:33:07 +02:00
Vito Tumas
f6c80fef68 fix: Relax MPT authorize cap for LoanSet and VaultWithdraw 2026-09-17 13:33:07 +02:00
Gregory Tsipenyuk
a0c12420b5 fix: Skip CheckCash limit waiver for the issuer 2026-09-17 13:33:06 +02:00
Ayaz Salikhov
1245254cac build: Add missing script to conan package 2026-09-17 13:33:06 +02:00
Jingchen
b60636169a fix: Make calculateBaseFee exception-safe 2026-09-17 13:33:06 +02:00
Ayaz Salikhov
d6022fbc4d build: Fix test installation on debian:11 due to EOL 2026-09-17 13:33:06 +02:00
Ayaz Salikhov
295b74da1c build: Add assert-enabled builds and packages 2026-09-17 13:33:05 +02:00
Timothy Banks
faa2bf583f fix: Cap TMTransactions list size and charge fee for undeserializable transactions 2026-09-17 13:33:04 +02:00
Vito Tumas
da260fa42b fix: Relax Loan Invariants to allow zero-principal LoanPay transaction 2026-09-17 13:33:04 +02:00
Timothy Banks
53788b193d test: Add ProtocolMessage harness for testing TMPing 2026-09-17 13:33:03 +02:00
Timothy Banks
227f1b4d9c fix: Unbounded Database Seek via TMGetLedger 2026-09-17 13:33:03 +02:00
Ed Hennis
26b66957ec fix: Trim unknown fields when parsing incoming peer protobuf messages 2026-09-17 13:33:02 +02:00
Mayukha Vadari
54e62a621f fix: Prevent simulate from updating the orderbook db 2026-09-17 13:33:02 +02:00
Timothy Banks
53628b70c0 fix: Use a hardened hash on the STPathElement 2026-09-17 13:33:01 +02:00
Vito Tumas
6fec2c11bf refactor: Rename vault accrual accounting to instant interest recognition (#8237) 2026-09-17 10:27:44 +00:00
Bart
04108a030c refactor: Build the RPC dispatch and command-line tables at compile time (#8006)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 10:01:28 +00:00
Bart
551a19b10d refactor: Add Cluster::isMember, a membership query that copies nothing (#8221)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-09-15 20:40:29 +00:00
Peter Chen
b0a940a383 refactor: Extract common tx-building helpers for ConfidentialMPT in MPTTester (#8135) 2026-09-15 17:13:44 +00:00
Bart
e302e4eeed fix: Set the peer limit total when per-direction limits are configured (#8220)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
2026-09-15 13:14:12 +00:00
Mayukha Vadari
1a4a40ebb8 fix: Update noripple_check to exclude transactions field on error responses (#6303)
Co-authored-by: Timur Yalymov <36795566+tyalymov@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
Co-authored-by: Ayaz Salikhov <mathbunnyru@users.noreply.github.com>
2026-09-15 00:21:57 +00:00
yinyiqian1
7f55dd390c feat: Support mirror key epochs in confidential MPT transactions for Key Rotation amendment (#8210) 2026-09-14 18:23:38 +00:00
248 changed files with 10323 additions and 19276 deletions

View File

@@ -64,6 +64,7 @@ words:
- blindings
- bookdir
- Bougalis
- bthomee
- Britto
- Btrfs
- Buildx
@@ -141,6 +142,7 @@ words:
- hwrap
- ifndef
- inequation
- Injectivity
- insuf
- insuff
- invasively
@@ -314,7 +316,6 @@ words:
- sttx
- stvar
- stvector
- stxchainattestations
- summands
- superpeer
- superpeers
@@ -372,7 +373,6 @@ words:
- writeme
- wsrch
- wthread
- xbridge
- xchain
- xcrun
- ximinez

View File

@@ -82,7 +82,6 @@ test.app > xrpl.tx
test.basics > test.jtx
test.basics > xrpl.basics
test.basics > xrpl.core
test.basics > xrpld.rpc
test.basics > xrpl.json
test.basics > xrpl.protocol
test.beast > xrpl.basics
@@ -286,10 +285,10 @@ xrpld.perflog > xrpl.basics
xrpld.perflog > xrpl.config
xrpld.perflog > xrpl.core
xrpld.perflog > xrpld.app
xrpld.perflog > xrpld.rpc
xrpld.perflog > xrpl.json
xrpld.perflog > xrpl.nodestore
xrpld.perflog > xrpl.protocol
xrpld.perflog > xrpl.server
xrpld.rpc > xrpl.basics
xrpld.rpc > xrpl.config
xrpld.rpc > xrpl.core

View File

@@ -15,6 +15,14 @@ _BASE_CMAKE_ARGS = [
"-Drust=ON",
]
# The package formats a config can be packaged as, each with its own
# install-test job in reusable-package.yml.
PACKAGE_TYPES = ("deb", "rpm")
# The package name a variant suffixes, as build_pkg.py's BASE_NAME spells it:
# the two have to agree, or the artifact globs miss what was built.
BASE_NAME = "xrpld"
# Maps sanitizer names (as used in cmake) to short config-name suffixes.
_SANITIZER_SUFFIX: dict[str, str] = {
"address": "asan",
@@ -62,10 +70,20 @@ def get_cmake_args(build_type: str, extra_args: str) -> str:
class PackageConfig:
"""The 'package' map of a config whose binaries are also packaged."""
type: str # "deb" or "rpm"; has to match what the image provides
type: str # has to match what the image provides
# The packaging container image: a vanilla distro image, not the nix image
# the config itself builds in.
image: str
# A flavour of the package, named xrpld-<variant>, for a config whose
# binaries are not the plain release build. A variant needs no counterpart
# in the other format.
variant: str = ""
def __post_init__(self) -> None:
assert self.type in PACKAGE_TYPES, (
f"unsupported package type {self.type!r}: "
f"use one of {', '.join(PACKAGE_TYPES)}."
)
@dataclasses.dataclass
@@ -178,6 +196,8 @@ class PackagingEntry:
validator_keys_artifact_name: str
image: str
package_type: str # "deb" or "rpm"; drives the format-specific steps
package_variant: str # passed to build_pkg.py --variant; empty for xrpld
package_name: str # the name it builds under, which the artifact globs use
# ---------------------------------------------------------------------------
@@ -267,12 +287,32 @@ def expand_linux_packaging(linux: LinuxFile) -> list[PackagingEntry]:
validator_keys_artifact_name=f"validator-keys-{name}",
image=cfg.package.image,
package_type=cfg.package.type,
package_variant=cfg.package.variant,
package_name=(
f"{BASE_NAME}-{cfg.package.variant}"
if cfg.package.variant
else BASE_NAME
),
)
)
return entries
def package_names_by_type(entries: list[PackagingEntry]) -> dict[str, list[str]]:
"""The names of the packages in 'entries', keyed by format.
Derived from the packaging matrix rather than listed again, so the packages
the install-test jobs look for are the packages that were built.
"""
return {
package_type: sorted(
{e.package_name for e in entries if e.package_type == package_type}
)
for package_type in PACKAGE_TYPES
}
def expand_platform_matrix(pf: PlatformFile, minimal: bool) -> list[MatrixEntry]:
"""Expand a PlatformFile (macOS or Windows) into matrix entries.
@@ -341,6 +381,10 @@ if __name__ == "__main__":
if args.packaging:
matrix = expand_linux_packaging(LinuxFile.load(THIS_DIR / "linux.json"))
# One list per format, so each install-test job installs the packages its
# own format produced.
for package_type, names in package_names_by_type(matrix).items():
print(f"{package_type}_package_names={json.dumps(names)}")
else:
if args.config in ("linux", None):
matrix += expand_linux_matrix(

View File

@@ -76,6 +76,19 @@
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-49cdc10"
}
},
{
"compiler": ["gcc"],
"build_type": ["Release"],
"arch": ["amd64"],
"minimal": false,
"suffix": "assert",
"extra_cmake_args": "-Dvalidator_keys=ON -Dassert=ON",
"package": {
"type": "deb",
"image": "ghcr.io/xrplf/xrpld/packaging-debian:sha-49cdc10",
"variant": "assert"
}
}
],

View File

@@ -85,6 +85,7 @@ jobs:
.github/workflows/reusable-build-test.yml
.github/workflows/reusable-check-autogen.yml
.github/workflows/reusable-clang-tidy.yml
.github/workflows/reusable-package-test-install.yml
.github/workflows/reusable-package.yml
.github/workflows/reusable-rust.yml
.github/workflows/reusable-strategy-matrix.yml
@@ -189,6 +190,12 @@ jobs:
# matrix (i.e. not yet labeled "Ready to merge" or "Full CI build").
if: ${{ needs.should-run.outputs.go == 'true' && (github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'Ready to merge') || contains(github.event.pull_request.labels.*.name, 'Full CI build')) }}
uses: ./.github/workflows/reusable-package.yml
with:
# A pull request builds packages to prove they still build, and publishes
# nothing. Stated rather than left to the input's default, so that changing
# that default cannot start publishing from pull requests. No secrets are
# passed either, which is the second reason a publish here cannot succeed.
publish: false
upload-recipe:
needs:

View File

@@ -23,6 +23,7 @@ on:
- ".github/workflows/reusable-build-test.yml"
- ".github/workflows/reusable-check-autogen.yml"
- ".github/workflows/reusable-clang-tidy.yml"
- ".github/workflows/reusable-package-test-install.yml"
- ".github/workflows/reusable-package.yml"
- ".github/workflows/reusable-rust.yml"
- ".github/workflows/reusable-strategy-matrix.yml"

View File

@@ -439,7 +439,7 @@ jobs:
- name: Upload coverage report
if: ${{ github.repository_owner == 'XRPLF' && !inputs.build_only && env.COVERAGE_ENABLED == 'true' }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
disable_search: true
disable_telem: true

View File

@@ -0,0 +1,120 @@
# Install one package format on every distro family it targets, one job per
# package name and image, and run the binaries there. Called once per format by
# reusable-package.yml, which owns the names and the image lists.
name: Install packages
on:
workflow_call:
inputs:
package_type:
description: 'The package format to install ("deb" or "rpm").'
required: true
type: string
package_names:
description: "JSON array of package names built for this format."
required: true
type: string
images:
description: "JSON array of container images to install in."
required: true
type: string
defaults:
run:
shell: bash
env:
PACKAGE_DIR: packages
jobs:
install:
strategy:
fail-fast: false
matrix:
package_name: ${{ fromJson(inputs.package_names) }}
image: ${{ fromJson(inputs.images) }}
name: "${{ matrix.package_name }} on ${{ matrix.image }}"
permissions:
contents: read
runs-on: ubuntu-latest
container: ${{ matrix.image }}
timeout-minutes: 5
steps:
# Every package lands in one directory; the step below picks its own,
# which keeps this independent of the artifact names.
- name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-pkg"
merge-multiple: true
path: ${{ env.PACKAGE_DIR }}
- name: Find the package
id: find
env:
PACKAGE_NAME: ${{ matrix.package_name }}
PACKAGE_TYPE: ${{ inputs.package_type }}
run: |
# The version follows the name, separated by '_' in a DEB and '-' in an
# RPM. Requiring a digit after it is what keeps 'xrpld' from picking up
# another package, such as 'xrpld-assert'.
pattern="${PACKAGE_NAME}[_-][0-9]*.${PACKAGE_TYPE}"
package="$(find "${PACKAGE_DIR}" -type f -name "${pattern}" -print -quit)"
test -n "${package}" || {
echo "no ${pattern} found in ${PACKAGE_DIR}" >&2
exit 1
}
echo "package=${package}" >>"${GITHUB_OUTPUT}"
# Debian 11 went end-of-life on 2026-08-31
# (https://www.debian.org/News/2026/20260831) and its packages are
# already partly gone from deb.debian.org, so switch to the
# snapshot.debian.org entries the image ships commented out in its
# sources.list: they are pinned to the snapshot the image was built
# from, so they serve every version it needs and never go away.
# Snapshots keep their original, long-passed Valid-Until, hence the
# disabled check; the retries absorb snapshot.debian.org's throttling.
- name: Switch Debian 11 to snapshot.debian.org
if: ${{ matrix.image == 'debian:11' }}
run: |
sed -i 's|^deb |# deb |; s|^# deb http://snapshot|deb http://snapshot|' /etc/apt/sources.list
printf '%s\n' \
'Acquire::Check-Valid-Until "false";' \
'Acquire::Retries "3";' \
>/etc/apt/apt.conf.d/99snapshot
- name: Install the DEB
if: ${{ inputs.package_type == 'deb' }}
env:
DEBIAN_FRONTEND: noninteractive
PACKAGE: ${{ steps.find.outputs.package }}
run: |
# Stock Debian and Ubuntu images carry no package lists, so apt has
# nothing to resolve the systemd dependency from until it fetches them.
apt-get update -qq
apt-get install -y "./${PACKAGE}"
- name: Install the RPM
if: ${{ inputs.package_type == 'rpm' }}
env:
PACKAGE: ${{ steps.find.outputs.package }}
run: dnf install -y "./${PACKAGE}"
- name: Run xrpld
run: xrpld --version
- name: Run validator-keys
run: validator-keys --version
- name: Run rippled, the legacy compatibility symlink
run: rippled --version
- name: Check the service account
run: id xrpld
- name: Check the state directory
run: test -d /var/lib/xrpld
- name: Check the log directory
run: test -d /var/log/xrpld

View File

@@ -3,8 +3,10 @@
#
# - 'package' builds and signs one format per config that carries a "package"
# map in linux.json; that map names the container image and the format
# - 'test-install' installs what was built on a range of distros and runs the
# binaries there, so a package that cannot be installed never reaches Nexus
# - 'test-install-deb' and 'test-install-rpm' call
# reusable-package-test-install.yml to install what was built on a range of
# distros and run the binaries there, so a package that cannot be installed
# never reaches Nexus
# - 'publish' uploads with the image's publish_pkg.py, doing a --dry-run
# unless 'publish: true'
#
@@ -23,7 +25,7 @@ on:
description: "The base URL of the Nexus instance hosting the deb and rpm repositories."
required: false
type: string
default: https://packages.xrplf.org
default: https://packages-upload.xrplf.org
secrets:
remote_username:
@@ -49,6 +51,8 @@ jobs:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
deb_package_names: ${{ steps.generate.outputs.deb_package_names }}
rpm_package_names: ${{ steps.generate.outputs.rpm_package_names }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -107,6 +111,7 @@ jobs:
- name: Build package
env:
PACKAGE_TYPE: ${{ matrix.package_type }}
PACKAGE_VARIANT: ${{ matrix.package_variant }}
PKG_RELEASE: ${{ steps.release_info.outputs.pkg_release }}
CHANNEL: ${{ steps.release_info.outputs.channel }}
run: |
@@ -114,6 +119,7 @@ jobs:
--package-type "${PACKAGE_TYPE}" \
--build-dir "${BUILD_DIR}" \
--pkg-release "${PKG_RELEASE}" \
--variant "${PACKAGE_VARIANT}" \
--channel "${CHANNEL}"
# Before the upload, so the artifact, the tested package and the published
@@ -125,14 +131,17 @@ jobs:
run: ./package/sign_rpm.py --package-dir "${BUILD_DIR}"
# Split from the debug symbols, which are an order of magnitude larger, so
# that test-install downloads only what it installs.
# that test-install downloads only what it installs. In the globs below the
# version follows the name, separated by '_' in a DEB and '-' in an RPM. A
# version starts with a digit and a longer name does not, so that one digit
# is what tells 'xrpld-3.4.1-...' from 'xrpld-assert-3.4.1-...'.
- name: Upload package artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.xrpld_artifact_name }}-pkg
path: |
${{ env.BUILD_DIR }}/debbuild/xrpld_*.deb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/xrpld-[0-9]*.rpm
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}_[0-9]*.deb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/${{ matrix.package_name }}-[0-9]*.rpm
if-no-files-found: error
- name: Upload debug symbol artifact
@@ -140,133 +149,59 @@ jobs:
with:
name: ${{ matrix.xrpld_artifact_name }}-pkg-debug
path: |
${{ env.BUILD_DIR }}/debbuild/xrpld-dbgsym_*.deb
${{ env.BUILD_DIR }}/debbuild/xrpld-dbgsym_*.ddeb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/xrpld-debuginfo-*.rpm
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}-dbgsym_[0-9]*.deb
${{ env.BUILD_DIR }}/debbuild/${{ matrix.package_name }}-dbgsym_[0-9]*.ddeb
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/${{ matrix.package_name }}-debuginfo-[0-9]*.rpm
if-no-files-found: error
# Every distro family the packages target, oldest release first, so both ends
# of the dependency range they declare are exercised.
test-install:
needs: [package]
strategy:
fail-fast: false
matrix:
include:
- package_type: deb
image: debian:11
- package_type: deb
image: debian:12
- package_type: deb
image: debian:13
- package_type: deb
image: ubuntu:20.04
- package_type: deb
image: ubuntu:22.04
- package_type: deb
image: ubuntu:24.04
- package_type: deb
image: ubuntu:26.04
# One call per format, so a variant packaged for one format is installed for
# that format alone. The images are every distro family that format targets,
# oldest release first, so both ends of the dependency range the packages
# declare are exercised.
test-install-deb:
needs: [generate-matrix, package]
name: install deb
uses: ./.github/workflows/reusable-package-test-install.yml
with:
package_type: deb
package_names: ${{ needs.generate-matrix.outputs.deb_package_names }}
images: |
[
"debian:11",
"debian:12",
"debian:13",
"ubuntu:20.04",
"ubuntu:22.04",
"ubuntu:24.04",
"ubuntu:26.04"
]
- package_type: rpm
image: almalinux:9
- package_type: rpm
image: almalinux:10
- package_type: rpm
image: rockylinux/rockylinux:9
- package_type: rpm
image: rockylinux/rockylinux:10
- package_type: rpm
image: registry.access.redhat.com/ubi9/ubi
- package_type: rpm
image: registry.access.redhat.com/ubi10/ubi
name: "install ${{ matrix.package_type }} on ${{ matrix.image }}"
permissions:
contents: read
runs-on: ubuntu-latest
container: ${{ matrix.image }}
timeout-minutes: 5
steps:
# Both formats land in one directory; the step below picks its own by
# extension, so this stays independent of the artifact names.
- name: Download package artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: "*-pkg"
merge-multiple: true
path: ${{ env.PACKAGE_DIR }}
- name: Find the package
id: find
env:
PACKAGE_TYPE: ${{ matrix.package_type }}
run: |
package="$(find "${PACKAGE_DIR}" -type f -name "*.${PACKAGE_TYPE}" -print -quit)"
test -n "${package}" || {
echo "no .${PACKAGE_TYPE} found in ${PACKAGE_DIR}" >&2
exit 1
}
echo "package=${package}" >>"${GITHUB_OUTPUT}"
# Debian 11 went end-of-life on 2026-08-31
# (https://www.debian.org/News/2026/20260831) and its packages are
# already partly gone from deb.debian.org, so switch to the
# snapshot.debian.org entries the image ships commented out in its
# sources.list: they are pinned to the snapshot the image was built
# from, so they serve every version it needs and never go away.
# Snapshots keep their original, long-passed Valid-Until, hence the
# disabled check; the retries absorb snapshot.debian.org's throttling.
- name: Switch Debian 11 to snapshot.debian.org
if: ${{ matrix.image == 'debian:11' }}
run: |
sed -i 's|^deb |# deb |; s|^# deb http://snapshot|deb http://snapshot|' /etc/apt/sources.list
printf '%s\n' \
'Acquire::Check-Valid-Until "false";' \
'Acquire::Retries "3";' \
>/etc/apt/apt.conf.d/99snapshot
- name: Install the DEB
if: ${{ matrix.package_type == 'deb' }}
env:
DEBIAN_FRONTEND: noninteractive
PACKAGE: ${{ steps.find.outputs.package }}
run: |
# Stock Debian and Ubuntu images carry no package lists, so apt has
# nothing to resolve the systemd dependency from until it fetches them.
apt-get update -qq
apt-get install -y "./${PACKAGE}"
- name: Install the RPM
if: ${{ matrix.package_type == 'rpm' }}
env:
PACKAGE: ${{ steps.find.outputs.package }}
run: dnf install -y "./${PACKAGE}"
- name: Run xrpld
run: xrpld --version
- name: Run validator-keys
run: validator-keys --version
- name: Run rippled, the legacy compatibility symlink
run: rippled --version
- name: Check the service account
run: id xrpld
- name: Check the state directory
run: test -d /var/lib/xrpld
- name: Check the log directory
run: test -d /var/log/xrpld
test-install-rpm:
needs: [generate-matrix, package]
name: install rpm
uses: ./.github/workflows/reusable-package-test-install.yml
with:
package_type: rpm
package_names: ${{ needs.generate-matrix.outputs.rpm_package_names }}
images: |
[
"almalinux:9",
"almalinux:10",
"rockylinux/rockylinux:9",
"rockylinux/rockylinux:10",
"registry.access.redhat.com/ubi9/ubi",
"registry.access.redhat.com/ubi10/ubi"
]
publish:
needs: [generate-matrix, package, test-install]
needs: [generate-matrix, package, test-install-deb, test-install-rpm]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
name: "publish ${{ matrix.xrpld_artifact_name }}"
# The name says which of the two this is, because the job runs either way:
# with publish false it passes --dry-run and uploads nothing, and a job
# called "publish ..." succeeding on a pull request reads like a release.
name: "publish ${{ matrix.xrpld_artifact_name }}${{ !inputs.publish && ' (dry run)' || '' }}"
permissions:
contents: read
runs-on: ["self-hosted", "Linux", "X64", "heavy"]

View File

@@ -57,7 +57,7 @@ jobs:
- name: Upload coverage report
if: ${{ github.repository == 'XRPLF/rippled' }}
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
with:
disable_search: true
disable_telem: true

View File

@@ -22,6 +22,14 @@ API version 2 is available in `xrpld` version 2.0.0 and later. See [API-VERSION-
This version is supported by all `xrpld` versions. For WebSocket and HTTP JSON-RPC requests, it is currently the default API version used when no `api_version` is specified.
## XRP Ledger server version 3.5.0
Version 3.5.0 is not yet released. These changes are available in the 3.5.0 beta releases.
### 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.
## XRP Ledger server version 3.4.0
Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta releases.
@@ -41,6 +49,7 @@ Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta
- `gateway_balances`: The `account` and `ident` fields now return an `invalidParams` error if the value is not a string, instead of an `internal` error. [#7655](https://github.com/XRPLF/rippled/pull/7655)
- `account_lines`: The `peer` field now returns an error if the value is not a string. [#7728](https://github.com/XRPLF/rippled/pull/7728)
- `ledger`: `delivered_amount` is now included in the metadata of successful `AccountDelete` transactions when transactions are expanded (`expand`, or admin-only `full`). Previously it was only added for `Payment` and `CheckCash`, which made `ledger` inconsistent with `tx` and `account_tx`. [#5706](https://github.com/XRPLF/rippled/pull/5706)
- `noripple_check`: The `transactions` field is no longer included in error responses; it is still returned (possibly as an empty array) whenever `transactions` is `true` and the request succeeds. A malformed `account` is now rejected before the ledger is looked up, so that error response no longer carries the `ledger_hash`, `ledger_index`, and `validated` fields ([#6303](https://github.com/XRPLF/rippled/pull/6303)).
## XRP Ledger server version 3.3.0

View File

@@ -44,12 +44,18 @@ else()
set(pkg_type rpm)
endif()
# Unquoted below, so an empty value adds no argument at all.
set(pkg_variant_option "")
if(assert)
set(pkg_variant_option --variant=assert)
endif()
add_custom_target(
package
COMMAND
${CMAKE_SOURCE_DIR}/package/build_pkg.py --package-type=${pkg_type}
--build-dir=${CMAKE_BINARY_DIR} --pkg-release=${pkg_release}
--channel=UNRELEASED
${pkg_variant_option} --channel=UNRELEASED
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS xrpld validator-keys
COMMENT "Building Linux ${pkg_type} package"

View File

@@ -149,6 +149,7 @@ class Xrpl(ConanFile):
self.requires("xxhash/0.8.3", transitive_headers=True)
exports_sources = (
"bin/default-loader-path.sh",
"CMakeLists.txt",
"cfg/*",
"cmake/*",

View File

@@ -6,7 +6,8 @@
`xrpld` is published as DEB and RPM packages for 64-bit x86 Linux.
Use APT on Debian-based distributions such as Debian and Ubuntu,
and YUM on Red Hat-based distributions such as RHEL, AlmaLinux, and Rocky Linux.
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).
## Release channels
@@ -81,7 +82,7 @@ wherever it appears in the repository configuration.
sudo apt -y install xrpld
```
### With the YUM package manager
### With the DNF package manager
1. Add the XRPL Foundation package-signing key:
@@ -109,9 +110,23 @@ wherever it appears in the repository configuration.
3. Install the `xrpld` package:
```bash
sudo yum install -y xrpld
sudo dnf install -y xrpld
```
### Optional: the assert-enabled build
Every channel also carries `xrpld-assert` as a DEB, the same build with assertions
enabled, for diagnosing a problem on a non-production server.
It installs the same files as `xrpld` and replaces it, so install one or the other:
```bash
sudo apt -y install xrpld-assert # APT removes xrpld itself
```
Switching stops the service, since it is a removal and an installation rather than an upgrade,
and APT starts it again.
Install `xrpld` the same way to switch back.
## The xrpld service
Both package managers install a systemd unit and enable it, so `xrpld` starts on boot.
@@ -121,7 +136,7 @@ Check whether it is already running:
systemctl status xrpld.service
```
The APT packages start it immediately as well; the YUM packages do not, so start it yourself:
The DEB packages start it immediately as well; the RPM packages do not, so start it yourself:
```bash
sudo systemctl start xrpld.service

View File

@@ -162,4 +162,89 @@ toUInt64(std::string const& s);
bool
isProperlyFormedTomlDomain(std::string_view domain);
/**
* Whether a view can be passed on as a C string.
*
* A reader given only data() stops at the first null, so the view must reach the
* terminating null. The test rebuilds the view from data() and compares: a view
* that stops earlier rebuilds longer, and so compares unequal.
*
* consteval because reading the byte after the view is only defined when @p str
* points into storage holding a null at or after its end, such as a string
* literal. An unterminated view is then a compile error, not an out-of-bounds
* read.
*
* @param str The view to test.
* @return Whether @p str is null-terminated. A view with no data is not.
*/
consteval bool
isNullTerminated(std::string_view str)
{
if (str.data() == nullptr)
return false;
// Reading past the view is the point, so the usual data() warning does not
// apply.
// NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
return std::string_view{str.data()} == str;
}
/**
* A string that is known to reach its terminating null.
*
* Converts to std::string_view, so it compares and hashes as one. Unlike a
* view, asCString() may be handed to a reader that expects a C string, such
* as json::StaticString.
*
* The only constructor is consteval and rejects a view that stops before the
* null, so the property holds by construction and no caller asserts it.
*/
class NullTerminatedView
{
public:
/**
* Build a view from one that reaches its terminating null.
*
* Explicit, so that a plain view cannot become a proof of termination by
* accident. The conversion the other way stays implicit.
*
* @param view The string to hold. Rejected at compile time if it stops
* before its terminating null, or has no data.
*/
explicit consteval NullTerminatedView(std::string_view view)
: data_(view.data()), size_(view.size())
{
if (!isNullTerminated(view))
throw "xrpl::NullTerminatedView : view does not reach a null";
}
constexpr
operator std::string_view() const noexcept
{
return view();
}
/**
* @return The string as a view.
*/
[[nodiscard]] constexpr std::string_view
view() const noexcept
{
return {data_, size_};
}
/**
* @return The string as a C string. Never null.
*/
[[nodiscard]] constexpr char const*
asCString() const noexcept
{
return data_;
}
private:
char const* data_;
std::size_t size_;
};
} // namespace xrpl

View File

@@ -518,7 +518,7 @@ public:
* The input must be precisely `2 * bytes` hexadecimal characters
* long, with one exception: the value '0'.
*
* @param sv A null-terminated string of hexadecimal characters
* @param sv A string of hexadecimal characters
* @return true if the input was parsed properly; false otherwise.
*/
[[nodiscard]] constexpr bool

View File

@@ -1,6 +1,7 @@
#pragma once
#include <xrpl/basics/Log.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/core/Job.h>
#include <xrpl/json/json_value.h>
@@ -9,7 +10,8 @@
#include <filesystem>
#include <functional>
#include <memory>
#include <string>
#include <span>
#include <string_view>
namespace beast {
class Journal;
@@ -67,7 +69,7 @@ public:
* @param requestId Unique identifier to track command
*/
virtual void
rpcStart(std::string const& method, std::uint64_t requestId) = 0;
rpcStart(std::string_view method, std::uint64_t requestId) = 0;
/**
* Log successful finish of RPC call
@@ -76,7 +78,7 @@ public:
* @param requestId Unique identifier to track command
*/
virtual void
rpcFinish(std::string const& method, std::uint64_t requestId) = 0;
rpcFinish(std::string_view method, std::uint64_t requestId) = 0;
/**
* Log errored RPC call
@@ -85,7 +87,7 @@ public:
* @param requestId Unique identifier to track command
*/
virtual void
rpcError(std::string const& method, std::uint64_t requestId) = 0;
rpcError(std::string_view method, std::uint64_t requestId) = 0;
/**
* Log queued job
@@ -150,10 +152,20 @@ public:
PerfLog::Setup
setupPerfLog(Section const& section, std::filesystem::path const& configDir);
/**
* @param methodNames The RPC methods to count, one counter per name. Reported
* as JSON keys that borrow each name and read it as a C string, which is
* why the parameter type requires one that reaches its terminating null.
* The names must outlive the returned object, which holds views of them.
* The range itself need not: it is copied.
* Passed in rather than looked up here, so that this layer needs no
* knowledge of the dispatch table.
*/
std::unique_ptr<PerfLog>
makePerfLog(
PerfLog::Setup const& setup,
Application& app,
std::span<NullTerminatedView const> methodNames,
beast::Journal journal,
std::function<void()>&& signalStop);
@@ -161,7 +173,7 @@ template <typename Func, class Rep, class Period>
auto
measureDurationAndLog(
Func&& func,
std::string const& actionDescription,
std::string_view actionDescription,
std::chrono::duration<Rep, Period> maxDelay,
beast::Journal const& journal)
{

View File

@@ -0,0 +1,45 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class AMMEntry : public SLEBase<ViewT, ltAMM>
{
public:
using Base = SLEBase<ViewT, ltAMM>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit AMMEntry(
Asset const& issue1,
Asset const& issue2,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::amm(issue1, issue2), view, j)
{
}
explicit AMMEntry(
uint256 const& ammID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::amm(ammID), view, j)
{
}
};
using AMMEntryR = AMMEntry<ReadView>;
using AMMEntryW = AMMEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,35 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class AccountRootEntry : public SLEBase<ViewT, ltACCOUNT_ROOT>
{
public:
using Base = SLEBase<ViewT, ltACCOUNT_ROOT>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit AccountRootEntry(
AccountID const& id,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::account(id), view, j)
{
}
};
using AccountRootEntryR = AccountRootEntry<ReadView>;
using AccountRootEntryW = AccountRootEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,33 @@
#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>
namespace xrpl {
template <typename ViewT>
class AmendmentsEntry : public SLEBase<ViewT, ltAMENDMENTS>
{
public:
using Base = SLEBase<ViewT, ltAMENDMENTS>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit AmendmentsEntry(
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::amendments(), view, j)
{
}
};
using AmendmentsEntryR = AmendmentsEntry<ReadView>;
using AmendmentsEntryW = AmendmentsEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class CheckEntry : public SLEBase<ViewT, ltCHECK>
{
public:
using Base = SLEBase<ViewT, ltCHECK>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit CheckEntry(
AccountID const& id,
SeqProxy const& seq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::check(id, seq), view, j)
{
}
explicit CheckEntry(
uint256 const& checkID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::check(checkID), view, j)
{
}
};
using CheckEntryR = CheckEntry<ReadView>;
using CheckEntryW = CheckEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,47 @@
#pragma once
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class CredentialEntry : public SLEBase<ViewT, ltCREDENTIAL>
{
public:
using Base = SLEBase<ViewT, ltCREDENTIAL>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit CredentialEntry(
AccountID const& subject,
AccountID const& issuer,
Slice const& credType,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::credential(subject, issuer, credType), view, j)
{
}
explicit CredentialEntry(
uint256 const& credentialID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::credential(credentialID), view, j)
{
}
};
using CredentialEntryR = CredentialEntry<ReadView>;
using CredentialEntryW = CredentialEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,35 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class DIDEntry : public SLEBase<ViewT, ltDID>
{
public:
using Base = SLEBase<ViewT, ltDID>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit DIDEntry(
AccountID const& account,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::did(account), view, j)
{
}
};
using DIDEntryR = DIDEntry<ReadView>;
using DIDEntryW = DIDEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,36 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class DelegateEntry : public SLEBase<ViewT, ltDELEGATE>
{
public:
using Base = SLEBase<ViewT, ltDELEGATE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit DelegateEntry(
AccountID const& account,
AccountID const& authorizedAccount,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::delegate(account, authorizedAccount), view, j)
{
}
};
using DelegateEntryR = DelegateEntry<ReadView>;
using DelegateEntryW = DelegateEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,58 @@
#pragma once
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <set>
#include <utility>
namespace xrpl {
template <typename ViewT>
class DepositPreauthEntry : public SLEBase<ViewT, ltDEPOSIT_PREAUTH>
{
public:
using Base = SLEBase<ViewT, ltDEPOSIT_PREAUTH>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit DepositPreauthEntry(
AccountID const& owner,
AccountID const& preauthorized,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::depositPreauth(owner, preauthorized), view, j)
{
}
explicit DepositPreauthEntry(
AccountID const& owner,
std::set<std::pair<AccountID, Slice>> const& authCreds,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::depositPreauth(owner, authCreds), view, j)
{
}
explicit DepositPreauthEntry(
uint256 const& preauthID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::depositPreauth(preauthID), view, j)
{
}
};
using DepositPreauthEntryR = DepositPreauthEntry<ReadView>;
using DepositPreauthEntryW = DepositPreauthEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,50 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
class DirectoryNodeEntry : public SLEBase<ViewT, ltDIR_NODE>
{
public:
using Base = SLEBase<ViewT, ltDIR_NODE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit DirectoryNodeEntry(
AccountID const& id,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::ownerDir(id), view, j)
{
}
/**
* Resolve a specific page of the directory rooted at @p root.
*/
explicit DirectoryNodeEntry(
uint256 const& root,
std::uint64_t index,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::page(root, index), view, j)
{
}
};
using DirectoryNodeEntryR = DirectoryNodeEntry<ReadView>;
using DirectoryNodeEntryW = DirectoryNodeEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,37 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class EscrowEntry : public SLEBase<ViewT, ltESCROW>
{
public:
using Base = SLEBase<ViewT, ltESCROW>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit EscrowEntry(
AccountID const& src,
SeqProxy const& seq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::escrow(src, seq), view, j)
{
}
};
using EscrowEntryR = EscrowEntry<ReadView>;
using EscrowEntryW = EscrowEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,33 @@
#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>
namespace xrpl {
template <typename ViewT>
class FeeSettingsEntry : public SLEBase<ViewT, ltFEE_SETTINGS>
{
public:
using Base = SLEBase<ViewT, ltFEE_SETTINGS>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit FeeSettingsEntry(
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::feeSettings(), view, j)
{
}
};
using FeeSettingsEntryR = FeeSettingsEntry<ReadView>;
using FeeSettingsEntryW = FeeSettingsEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,33 @@
#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>
namespace xrpl {
template <typename ViewT>
class LedgerHashesEntry : public SLEBase<ViewT, ltLEDGER_HASHES>
{
public:
using Base = SLEBase<ViewT, ltLEDGER_HASHES>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit LedgerHashesEntry(
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::skip(), view, j)
{
}
};
using LedgerHashesEntryR = LedgerHashesEntry<ReadView>;
using LedgerHashesEntryW = LedgerHashesEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class LoanBrokerEntry : public SLEBase<ViewT, ltLOAN_BROKER>
{
public:
using Base = SLEBase<ViewT, ltLOAN_BROKER>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit LoanBrokerEntry(
AccountID const& owner,
SeqProxy const& seq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::loanBroker(owner, seq), view, j)
{
}
explicit LoanBrokerEntry(
uint256 const& loanBrokerID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::loanBroker(loanBrokerID), view, j)
{
}
};
using LoanBrokerEntryR = LoanBrokerEntry<ReadView>;
using LoanBrokerEntryW = LoanBrokerEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,45 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class LoanEntry : public SLEBase<ViewT, ltLOAN>
{
public:
using Base = SLEBase<ViewT, ltLOAN>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit LoanEntry(
uint256 const& loanBrokerID,
SeqProxy const& loanSeq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::loan(loanBrokerID, loanSeq), view, j)
{
}
explicit LoanEntry(
uint256 const& loanID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::loan(loanID), view, j)
{
}
};
using LoanEntryR = LoanEntry<ReadView>;
using LoanEntryW = LoanEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,55 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/UintTypes.h>
namespace xrpl {
template <typename ViewT>
class MPTokenEntry : public SLEBase<ViewT, ltMPTOKEN>
{
public:
using Base = SLEBase<ViewT, ltMPTOKEN>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit MPTokenEntry(
MPTID const& issuanceID,
AccountID const& holder,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptoken(issuanceID, holder), view, j)
{
}
explicit MPTokenEntry(
uint256 const& issuanceKey,
AccountID const& holder,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptoken(issuanceKey, holder), view, j)
{
}
explicit MPTokenEntry(
uint256 const& mptokenKey,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptoken(mptokenKey), view, j)
{
}
};
using MPTokenEntryR = MPTokenEntry<ReadView>;
using MPTokenEntryW = MPTokenEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,56 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/UintTypes.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
class MPTokenIssuanceEntry : public SLEBase<ViewT, ltMPTOKEN_ISSUANCE>
{
public:
using Base = SLEBase<ViewT, ltMPTOKEN_ISSUANCE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit MPTokenIssuanceEntry(
std::uint32_t seq,
AccountID const& issuer,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptokenIssuance(makeMptID(seq, issuer)), view, j)
{
}
explicit MPTokenIssuanceEntry(
MPTID const& issuanceID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptokenIssuance(issuanceID), view, j)
{
}
explicit MPTokenIssuanceEntry(
uint256 const& issuanceKey,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::mptokenIssuance(issuanceKey), view, j)
{
}
};
using MPTokenIssuanceEntryR = MPTokenIssuanceEntry<ReadView>;
using MPTokenIssuanceEntryW = MPTokenIssuanceEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class NFTokenOfferEntry : public SLEBase<ViewT, ltNFTOKEN_OFFER>
{
public:
using Base = SLEBase<ViewT, ltNFTOKEN_OFFER>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit NFTokenOfferEntry(
AccountID const& owner,
SeqProxy const& seq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::nftokenOffer(owner, seq), view, j)
{
}
explicit NFTokenOfferEntry(
uint256 const& offerID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::nftokenOffer(offerID), view, j)
{
}
};
using NFTokenOfferEntryR = NFTokenOfferEntry<ReadView>;
using NFTokenOfferEntryW = NFTokenOfferEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,37 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class NFTokenPageEntry : public SLEBase<ViewT, ltNFTOKEN_PAGE>
{
public:
using Base = SLEBase<ViewT, ltNFTOKEN_PAGE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit NFTokenPageEntry(
Keylet const& page,
uint256 const& token,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::nftokenPage(page, token), view, j)
{
}
};
using NFTokenPageEntryR = NFTokenPageEntry<ReadView>;
using NFTokenPageEntryW = NFTokenPageEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,33 @@
#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>
namespace xrpl {
template <typename ViewT>
class NegativeUNLEntry : public SLEBase<ViewT, ltNEGATIVE_UNL>
{
public:
using Base = SLEBase<ViewT, ltNEGATIVE_UNL>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit NegativeUNLEntry(
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::negativeUNL(), view, j)
{
}
};
using NegativeUNLEntryR = NegativeUNLEntry<ReadView>;
using NegativeUNLEntryW = NegativeUNLEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class OfferEntry : public SLEBase<ViewT, ltOFFER>
{
public:
using Base = SLEBase<ViewT, ltOFFER>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit OfferEntry(
AccountID const& id,
SeqProxy const& seq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::offer(id, seq), view, j)
{
}
explicit OfferEntry(
uint256 const& offerID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::offer(offerID), view, j)
{
}
};
using OfferEntryR = OfferEntry<ReadView>;
using OfferEntryW = OfferEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,38 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
class OracleEntry : public SLEBase<ViewT, ltORACLE>
{
public:
using Base = SLEBase<ViewT, ltORACLE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit OracleEntry(
AccountID const& account,
std::uint32_t documentID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::oracle(account, documentID), view, j)
{
}
};
using OracleEntryR = OracleEntry<ReadView>;
using OracleEntryW = OracleEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,38 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class PayChannelEntry : public SLEBase<ViewT, ltPAYCHAN>
{
public:
using Base = SLEBase<ViewT, ltPAYCHAN>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit PayChannelEntry(
AccountID const& src,
AccountID const& dst,
SeqProxy const& seq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::payChannel(src, dst, seq), view, j)
{
}
};
using PayChannelEntryR = PayChannelEntry<ReadView>;
using PayChannelEntryW = PayChannelEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class PermissionedDomainEntry : public SLEBase<ViewT, ltPERMISSIONED_DOMAIN>
{
public:
using Base = SLEBase<ViewT, ltPERMISSIONED_DOMAIN>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit PermissionedDomainEntry(
AccountID const& account,
SeqProxy const& seq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::permissionedDomain(account, seq), view, j)
{
}
explicit PermissionedDomainEntry(
uint256 const& domainID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::permissionedDomain(domainID), view, j)
{
}
};
using PermissionedDomainEntryR = PermissionedDomainEntry<ReadView>;
using PermissionedDomainEntryW = PermissionedDomainEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,48 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/UintTypes.h>
namespace xrpl {
template <typename ViewT>
class RippleStateEntry : public SLEBase<ViewT, ltRIPPLE_STATE>
{
public:
using Base = SLEBase<ViewT, ltRIPPLE_STATE>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit RippleStateEntry(
AccountID const& id0,
AccountID const& id1,
Currency const& currency,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::trustLine(id0, id1, currency), view, j)
{
}
explicit RippleStateEntry(
AccountID const& id,
Issue const& issue,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::trustLine(id, issue), view, j)
{
}
};
using RippleStateEntryR = RippleStateEntry<ReadView>;
using RippleStateEntryW = RippleStateEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,503 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <concepts>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace xrpl {
// Concept to distinguish read-only vs writable view types
template <typename V>
concept IsWritableView = std::derived_from<V, ApplyView>;
namespace detail {
/**
* Resolves a keylet for a read-only entry.
*
* ReadView::read() on an ApplyView returns the underlying ledger's entry
* whenever the view is not already tracking one, while peek() installs the
* view's own copy and returns that. A read-only entry built with read()
* would therefore hold an SLE that goes stale the moment anything peeks the
* same key and modifies it. Resolve through peek() whenever the view really is
* an ApplyView, so every entry over that view shares one SLE.
*
* @note The const_cast is what makes reaching ApplyView::peek() possible, and
* it is defined behavior only when the view really is a non-const
* object that the caller merely observes through a const reference.
* That holds for every production view today, but it is not a
* guarantee the codebase makes: the unit tests already build
* genuinely const ApplyView-derived objects (`Sandbox const` in
* Directory_test.cpp and View_test.cpp, `PaymentSandbox const` in
* TheoreticalQuality_test.cpp and View_test.cpp). Constructing a
* read-only entry over one of those would be undefined behavior, so
* do not, until #8069 removes the cast -- by giving ApplyView a
* const-qualified peek(), which needs no amendment because
* Action::Cache is invisible to apply(), visit() and metadata.
*
* @note Consequently a "read-only" entry over an ApplyView is not free of
* side effects: peek() installs an Action::Cache entry in the apply
* state table. That is benign for transaction metadata -- Cache entries
* are skipped in ApplyStateTable::apply(), ::visit() and in metadata
* generation -- but it does cost one deep SLE copy on first touch.
*/
inline SLE::const_pointer
resolveEntry(ReadView const& view, Keylet const& key)
{
// Safe only for a view that is not itself a const object -- see the
// note above. The entry holds a const reference because it does not
// modify the view, not because the view is const.
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
if (auto const applyView = dynamic_cast<ApplyView*>(const_cast<ReadView*>(&view)))
return applyView->peek(key);
return view.read(key);
}
} // namespace detail
/**
* View-parameterized base class for all ledger entries.
*
* SLEBase<ReadView> — read-only: holds shared_ptr<SLE const> + ReadView const&
* SLEBase<ApplyView> — writable: holds shared_ptr<SLE> + ApplyView& + Keylet,
* plus insert/update/erase operations
*
* Write-only members are gated by `requires` clauses, providing compile-time
* guarantees that read-only entries cannot mutate state.
*
* @tparam EntryType the ledger entry type this entry is statically bound to.
* Derived per-type entries pass their own type (e.g. ltACCOUNT_ROOT); the
* generic ReadOnlySLE / WritableSLE aliases leave it at ltANY, which opts out
* of the static type check. Binding the type here is what keeps an entry for
* one entry type from being constructed or converted from another -- see the
* converting constructor below.
*
* Derived classes should provide domain-specific accessors that hide
* implementation details of the underlying ledger entry format.
*/
template <typename ViewT, LedgerEntryType EntryType = ltANY>
class SLEBase
{
public:
static constexpr bool kIsWritable = IsWritableView<ViewT>;
// The ledger entry type this entry is bound to, and whether that binding
// is meaningful (ltANY means "any type", i.e. no static check).
static constexpr LedgerEntryType kEntryType = EntryType;
static constexpr bool kIsTyped = (EntryType != ltANY);
// SLE pointer type: mutable for writable views, const for read-only
using SlePtrType = std::conditional_t<kIsWritable, SLE::pointer, SLE::const_pointer>;
// View reference type: ApplyView& for writable, ReadView const& for
// read-only
using ViewRefType = std::conditional_t<kIsWritable, ApplyView&, ReadView const&>;
// Non-virtual by design: these entries are parameterized on the view and
// entry type, never used polymorphically through a base pointer. A vptr
// would be 8 bytes of pure overhead on a type meant to be as cheap as the
// shared_ptr it wraps. See the static_assert below the class.
//
// The destructor is public because the ReadOnlySLE / WritableSLE aliases
// name this class directly and are used as value types. Since it is not
// virtual, never delete a derived entry through an SLEBase*.
~SLEBase() = default;
SLEBase(SLEBase const&)
requires(!kIsWritable)
= default;
SLEBase(SLEBase&&) = default;
SLEBase&
operator=(SLEBase const&) = delete;
SLEBase&
operator=(SLEBase&&) = delete;
SLEBase() = delete;
// --- Constructors that adopt/resolve an SLE (public so the ReadOnlySLE /
// WritableSLE aliases and the per-type entries can be built directly
// from a keylet, or -- read-only only -- from an already-fetched
// SLE). ---
/**
* Constructor for read-only context (adopt an already-fetched SLE).
*
* There is deliberately no writable equivalent: a writable entry needs
* a Keylet so that newSLE() can still build an entry when none exists,
* and that cannot be recovered from a null SLE.
*/
explicit SLEBase(
SLE::const_pointer sle,
ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
requires(!kIsWritable)
: view_(view), sle_(std::move(sle)), j_(j)
{
XRPL_ASSERT(
!kIsTyped || !sle_ || sle_->getType() == kEntryType,
"xrpl::SLEBase::SLEBase : adopted SLE matches bound entry type");
}
/**
* Constructor for read-only context (read from view by keylet)
*/
explicit SLEBase(
Keylet const& key,
ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
requires(!kIsWritable)
: view_(view), sle_(detail::resolveEntry(view, key)), j_(j)
{
XRPL_ASSERT(
!kIsTyped || key.type == kEntryType,
"xrpl::SLEBase::SLEBase : keylet matches bound entry type");
}
/**
* Converting constructor: writable → read-only.
*
* Enables implicit conversion from SLEBase<ApplyView> to
* SLEBase<ReadView>, so functions taking ReadOnlySLE const& can accept
* WritableSLE.
*
* Constrained to the same entry type (or to a ltANY target, i.e. widening
* a typed entry to a generic ReadOnlySLE). The constraint is load-bearing:
* this constructor is inherited into every per-type entry, and unconstrained
* it would bind any writable entry that slices to SLEBase, so an OfferEntryW
* would convert to an AccountRootEntryR with no cast at the call site.
*/
template <typename OtherViewT, LedgerEntryType OtherType>
SLEBase(SLEBase<OtherViewT, OtherType> const& other)
requires(!kIsWritable && IsWritableView<OtherViewT> &&
(OtherType == EntryType || EntryType == ltANY))
: view_(other.readView()), sle_(other.rawSle()), j_(other.journal())
{
}
/**
* Constructor for writable context (peek from view by keylet)
*/
explicit SLEBase(
Keylet const& key,
ApplyView& view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
requires kIsWritable
: view_(view), key_(key), sle_(view_.peek(key)), j_(j)
{
XRPL_ASSERT(
!kIsTyped || key.type == kEntryType,
"xrpl::SLEBase::SLEBase : keylet matches bound entry type");
}
/**
* Constructor for writable context, for call sites that hold an
* ApplyViewContext (peek from ctx.view by keylet).
*
* ctx.tx is not retained: this exists purely so transactors can pass the
* context they already have instead of spelling out ctx.view. If an entry
* ever needs the applying transaction, store it here rather than adding
* another overload.
*/
explicit SLEBase(
Keylet const& key,
ApplyViewContext const& ctx,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
requires kIsWritable
: SLEBase(key, ctx.view, j)
{
}
// --- Common interface (always available) ---
/**
* Returns true if the ledger entry exists
*/
[[nodiscard]] bool
exists() const
{
return sle_ != nullptr;
}
/**
* Explicit conversion to bool for convenient existence checking
*/
explicit
operator bool() const
{
return exists();
}
/**
* Returns the underlying SLE for read access.
*
* Prefer operator-> / operator* for field access; this is for the call
* sites that need the shared_ptr itself.
*/
[[nodiscard]] SLE::const_pointer
rawSle() const
{
return sle_;
}
/**
* Returns the ledger entry type of this entry.
*
* For a per-type entry this is kEntryType, known at compile time and
* valid whether or not the entry exists. Only the generic ReadOnlySLE /
* WritableSLE aliases have to read it back out of the SLE.
*
* @throws std::logic_error for a generic (ltANY) entry if exists() is
* false.
*/
[[nodiscard]] LedgerEntryType
type() const
{
if constexpr (kIsTyped)
{
return kEntryType;
}
else
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::type : entry does not exist");
return sle_->getType();
}
}
/**
* Returns the keylet identifying this entry.
*
* Writable entries keep the keylet they were built from, so it is valid
* even before newSLE(). Read-only entries derive it from the SLE, which
* must therefore exist.
*
* @throws std::logic_error for a read-only entry if exists() is false.
*/
[[nodiscard]] Keylet
keylet() const
{
if constexpr (kIsWritable)
{
return key_;
}
else
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::keylet : entry does not exist");
// Take the type from the SLE, not from kEntryType: the adopt-SLE
// constructor's type check is assert-only, so a Release build can
// be holding an SLE whose type disagrees with the binding, and the
// SLE is the one telling the truth.
return Keylet(sle_->getType(), sle_->key());
}
}
/**
* Returns the ledger key of this entry.
*
* @throws std::logic_error same as keylet(): for read-only entries,
* if exists() is false.
*/
[[nodiscard]] uint256
key() const
{
return keylet().key;
}
/**
* Returns the read view (always available; ApplyView inherits ReadView)
*/
[[nodiscard]] ReadView const&
readView() const
{
return view_;
}
/**
* Const dereference operators (always available)
*
* @throws std::logic_error if exists() is false.
*/
STLedgerEntry const*
operator->() const
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::operator-> : entry does not exist");
return sle_.get();
}
STLedgerEntry const&
operator*() const
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::operator* : entry does not exist");
return *sle_;
}
// --- Writable interface (compile-time gated) ---
//
// Everything that hands out mutable access (or mutates) is non-const, so
// that a `FooEntryW const&` is as inert as a `FooEntryR`. Use readView()
// when a const entry only needs to inspect the view.
/**
* Returns the underlying SLE for write access.
*
* Prefer operator-> / operator* for field access; this is for the call
* sites that need the shared_ptr itself.
*/
[[nodiscard]] SlePtrType const&
mutableRawSle()
requires kIsWritable
{
return sle_;
}
/**
* Returns the apply view for write operations
*/
[[nodiscard]] ApplyView&
applyView()
requires kIsWritable
{
return view_;
}
/**
* Mutable dereference operators
*
* @throws std::logic_error if exists() is false.
*/
STLedgerEntry*
operator->()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::operator-> : entry does not exist");
return sle_.get();
}
STLedgerEntry&
operator*()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::operator* : entry does not exist");
return *sle_;
}
/**
* Inserts the entry into the view.
*
* @throws std::logic_error if exists() is false.
*/
void
insert()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::insert : entry does not exist");
view_.insert(sle_);
}
/**
* Erases the entry from the view.
*
* Drops the SLE afterwards, so the entry reports !exists() and any
* further use throws here rather than either throwing from deep inside
* ApplyStateTable or -- worse -- silently succeeding. For an
* entry that already existed, ApplyStateTable::erase keeps holding this
* exact SLE and builds the DeletedNode's FinalFields from it, so a write
* through the entry after erase() would land in transaction metadata
* with no diagnostic at all.
*
* @throws std::logic_error if exists() is false.
*/
void
erase()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::erase : entry does not exist");
view_.erase(sle_);
sle_ = nullptr;
}
/**
* @throws std::logic_error if exists() is false.
*/
void
update()
requires kIsWritable
{
if (!exists())
Throw<std::logic_error>("xrpl::SLEBase::update : entry does not exist");
view_.update(sle_);
}
/**
* @throws std::logic_error if exists() is true: newSLE() would otherwise
* silently discard the SLE already held.
*/
void
newSLE()
requires kIsWritable
{
if (exists())
Throw<std::logic_error>("xrpl::SLEBase::newSLE : entry already exists");
sle_ = std::make_shared<SLE>(key_);
}
[[nodiscard]] beast::Journal
journal() const
{
return j_;
}
protected:
ViewRefType view_;
// Keylet is only meaningful for writable views, which need it to build an
// SLE that does not exist yet; read-only entries derive it from the SLE.
struct Empty
{
};
// No default member initializer: Keylet is not default-constructible, so
// every writable constructor must initialize key_ explicitly.
[[no_unique_address]]
std::conditional_t<kIsWritable, Keylet, Empty> key_;
SlePtrType sle_{};
beast::Journal j_;
};
/**
* Generic (any-entry-type) SLE entries.
*
* Use these when the concrete ledger entry type is not known at a given site;
* otherwise prefer the per-type entries (e.g. AccountRootEntry.h), which
* additionally enforce the entry type at compile time.
*
* SLE::const_pointer / SLE::const_ref -> ReadOnlySLE
* SLE::pointer / SLE::ref -> WritableSLE
*/
using ReadOnlySLE = SLEBase<ReadView>;
using WritableSLE = SLEBase<ApplyView>;
static_assert(
!std::is_polymorphic_v<ReadOnlySLE> && !std::is_polymorphic_v<WritableSLE>,
"SLEBase must stay a thin value type; it must not acquire a vtable");
} // namespace xrpl

View File

@@ -0,0 +1,35 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class SignerListEntry : public SLEBase<ViewT, ltSIGNER_LIST>
{
public:
using Base = SLEBase<ViewT, ltSIGNER_LIST>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit SignerListEntry(
AccountID const& account,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::signerList(account), view, j)
{
}
};
using SignerListEntryR = SignerListEntry<ReadView>;
using SignerListEntryW = SignerListEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,36 @@
#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/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
namespace xrpl {
template <typename ViewT>
class SponsorshipEntry : public SLEBase<ViewT, ltSPONSORSHIP>
{
public:
using Base = SLEBase<ViewT, ltSPONSORSHIP>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit SponsorshipEntry(
AccountID const& sponsor,
AccountID const& sponsee,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::sponsorship(sponsor, sponsee), view, j)
{
}
};
using SponsorshipEntryR = SponsorshipEntry<ReadView>;
using SponsorshipEntryW = SponsorshipEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class TicketEntry : public SLEBase<ViewT, ltTICKET>
{
public:
using Base = SLEBase<ViewT, ltTICKET>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit TicketEntry(
AccountID const& id,
SeqProxy const& ticketSeq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::ticket(id, ticketSeq), view, j)
{
}
explicit TicketEntry(
uint256 const& ticketID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::ticket(ticketID), view, j)
{
}
};
using TicketEntryR = TicketEntry<ReadView>;
using TicketEntryW = TicketEntry<ApplyView>;
} // namespace xrpl

View File

@@ -0,0 +1,46 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
template <typename ViewT>
class VaultEntry : public SLEBase<ViewT, ltVAULT>
{
public:
using Base = SLEBase<ViewT, ltVAULT>;
// Inherit base constructors: adopt an existing SLE, or resolve one from a
// Keylet against the view.
using Base::Base;
explicit VaultEntry(
AccountID const& owner,
SeqProxy const& seq,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::vault(owner, seq), view, j)
{
}
explicit VaultEntry(
uint256 const& vaultID,
Base::ViewRefType view,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: Base(keylet::vault(vaultID), view, j)
{
}
};
using VaultEntryR = VaultEntry<ReadView>;
using VaultEntryW = VaultEntry<ApplyView>;
} // namespace xrpl

View File

@@ -338,9 +338,9 @@ struct AccountingDeltas
Number debtTotalDelta;
};
// Whole-life (pre-LendingProtocolV1_1) recognition model: interest is
// recognized into AssetsTotal/DebtTotal up front, at origination.
namespace accrual {
// Instant interest recognition (pre-LendingProtocolV1_1): interest is
// recognized into AssetsTotal/DebtTotal immediately, at origination.
namespace instant_recognition {
// LoanSet origination: what's added to Vault.AssetsTotal and LoanBroker.DebtTotal
AccountingDeltas
@@ -362,7 +362,7 @@ loanVaultExposure(SLE::const_ref loanSle);
AccountingDeltas
loanPaymentDeltas(LoanPaymentParts const& parts);
} // namespace accrual
} // namespace instant_recognition
// Cash-basis (LendingProtocolV1_1) recognition model: AssetsTotal/DebtTotal
// are principal-only, interest is recognized only as it's actually paid.
@@ -381,7 +381,7 @@ loanPaymentDeltas(LoanPaymentParts const& parts);
// Public dispatchers: pick cash_basis:: if featureLendingProtocolV1_1 is
// enabled AND the Vault's LEVersion (VaultHelpers::getVaultVersion) is
// VaultVersion::CashBasis, else accrual::. These are the only entry points
// VaultVersion::CashBasis, else instant_recognition::. These are the only entry points
// transactors call.
AccountingDeltas
loanOriginationDeltas(

View File

@@ -172,8 +172,8 @@ isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref
/**
* Resolves a Vault's LEVersion, the single point every accounting touch
* point should call to determine which recognition model (accrual vs.
* cash-basis) a Vault uses. Vaults created before featureLendingProtocolV1_1
* point should call to determine which recognition model (instant interest
* recognition vs. cash-basis) a Vault uses. Vaults created before featureLendingProtocolV1_1
* activated never have sfLEVersion set, which resolves here to
* VaultVersion::Legacy.
*

View File

@@ -92,7 +92,7 @@ public:
void
importDatabase(Database& source) override
{
importInternal(*backend_.get(), source);
importInternal(*backend_, source);
}
void

View File

@@ -26,7 +26,8 @@ struct Config
/**
* The largest number of public peer slots to allow.
* This includes both inbound and outbound, but does not include
* fixed peers.
* fixed peers. A configuration built by `makeConfig` always holds
* `maxPeers == inPeers + outPeers`.
*/
std::size_t maxPeers{tuning::kDefaultMaxPeers};

View File

@@ -6,6 +6,7 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STInteger.h> // IWYU pragma: keep
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/UintTypes.h>
@@ -301,6 +302,63 @@ verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 co
NotTEC
checkEncryptedAmountFormat(STObject const& object);
/**
* @brief Checks whether a holder's issuer mirror is encrypted under the
* issuance's currently registered issuer key.
*
* Verifies that the holder's issuer mirror epoch matches the active issuer key
* epoch on the issuance. An absent mirror epoch defaults to epoch 0. A holder without an issuer
* mirror is considered stale, as there is no key anchor for future re-encryptions.
*
* @param issuance The MPTokenIssuance ledger object.
* @param mptoken The holder's MPToken ledger object.
* @return true if the MPToken's issuer mirror is current. false if stale.
*/
[[nodiscard]] bool
isIssuerMirrorCurrent(SLE const& issuance, SLE const& mptoken);
/**
* @brief Checks whether a holder's auditor mirror is encrypted under the
* issuance's currently registered auditor key.
*
* Verifies that the holder's auditor mirror epoch matches the active auditor key
* epoch on the issuance. An absent mirror epoch defaults to epoch 0. An issuance
* without an auditor key requires no auditor mirror and is considered current.
*
* @param issuance The MPTokenIssuance ledger object.
* @param mptoken The holder's MPToken ledger object.
* @return true if the auditor mirror is current or not required.
*/
[[nodiscard]] bool
isAuditorMirrorCurrent(SLE const& issuance, SLE const& mptoken);
/**
* @brief Checks whether each mirror a holder is required to have is encrypted
* under the issuance's currently registered ElGamal keys.
*
* Verifies that both the issuer mirror and the auditor mirror (if required)
* are current. This serves as a combined check, ensuring all necessary
* holder mirror epochs match the active key epochs on the issuance.
*
* @param issuance The MPTokenIssuance ledger object.
* @param mptoken The holder's MPToken ledger object.
* @return true if the required mirrors are current.
*/
[[nodiscard]] bool
areMirrorsCurrent(SLE const& issuance, SLE const& mptoken);
/**
* @brief Set the holder's MPToken mirror epochs to match the issuance's current key epochs.
*
* Call this after writing mirror ciphertexts under the issuance's currently
* registered keys, so that the mirrors read as current afterwards.
*
* @param issuance The MPTokenIssuance ledger object.
* @param mptoken The holder's MPToken ledger entry to update.
*/
void
setMirrorEpochs(SLE const& issuance, SLE& mptoken);
/**
* @brief Verifies revealed amount encryptions for all recipients.
*

View File

@@ -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>
@@ -307,17 +306,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;

View File

@@ -5,9 +5,11 @@
#include <xrpl/protocol/Concepts.h>
#include <xrpl/protocol/UintTypes.h>
#include <cstdint>
#include <ostream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <variant>
namespace xrpl {
@@ -121,9 +123,32 @@ operator==(PathAsset const& lhs, PathAsset const& rhs)
template <typename Hasher>
void
hash_append(Hasher& h, PathAsset const& pathAsset)
hash_append(Hasher& h, PathAsset const& pathAsset) noexcept
{
std::visit([&]<ValidPathAsset T>(T const& e) { hash_append(h, e); }, pathAsset.value());
using beast::hash_append;
using Variant = std::remove_cvref_t<decltype(pathAsset.value())>;
static_assert(
std::variant_size_v<Variant> < 0xFFu,
"PathAsset's discriminant must fit in a byte, leaving 0xFF reserved.");
// std::visit is not noexcept: it throws bad_variant_access when the variant
// is valueless_by_exception.
if (pathAsset.value().valueless_by_exception()) [[unlikely]]
{
hash_append(h, static_cast<std::uint8_t>(0xFFu));
return;
}
hash_append(h, static_cast<std::uint8_t>(pathAsset.value().index()));
std::visit(
[&]<ValidPathAsset T>(T const& e) noexcept {
static_assert(
noexcept(hash_append(h, e)),
"Every PathAsset alternative must be nothrow-hashable.");
hash_append(h, e);
},
pathAsset.value());
}
inline bool

View File

@@ -322,7 +322,7 @@ constexpr std::uint8_t kVaultMaximumIouScale = 18;
* Vault ledger-entry schema versions. Assigned to newly created
* Vaults once featureLendingProtocolV1_1 is enabled. Vaults created before
* activation are left without LEVersion (implicit legacy version 0,
* accrual-basis accounting).
* instant interest recognition).
*/
enum class VaultVersion : uint8_t {
Legacy = 0,

View File

@@ -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 unused */ \
STYPE(STI_CURRENCY, 26) \
\
/* high-level types */ \
@@ -358,7 +357,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>;
//------------------------------------------------------------------------------

View File

@@ -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>

View File

@@ -12,6 +12,8 @@
#include <xrpl/protocol/UintTypes.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <utility>
#include <vector>
@@ -65,7 +67,7 @@ public:
PathAsset const& asset,
AccountID const& issuer);
[[nodiscard]] auto
[[nodiscard]] std::uint32_t
getNodeType() const;
[[nodiscard]] bool
@@ -109,9 +111,6 @@ public:
[[nodiscard]] bool
isType(Type const& pe) const;
[[nodiscard]] size_t
getHash() const;
bool
operator==(STPathElement const& t) const;
@@ -120,6 +119,17 @@ private:
getHash(STPathElement const& element);
};
template <class Hasher>
void
hash_append(Hasher& h, STPathElement const& e) noexcept
{
using beast::hash_append;
hash_append(h, (e.getNodeType() & STPathElement::TypeAccount) != 0u);
hash_append(h, e.getAccountID());
hash_append(h, e.getPathAsset());
hash_append(h, e.getIssuerID());
}
class STPath final : public CountedObject<STPath>
{
std::vector<STPathElement> path_;
@@ -176,9 +186,10 @@ template <class Hasher>
void
hash_append(Hasher& h, STPath const& p) noexcept
{
using beast::hash_append;
for (auto const& e : p)
{
beast::hash_append(h, e.getHash());
hash_append(h, e);
}
}
@@ -188,13 +199,39 @@ hash_append(Hasher& h, STPath const& p) noexcept
class STPathSet final : public STBase, public CountedObject<STPathSet>
{
std::vector<STPath> value_;
xrpl::hardened_hash_set<STPath> seenHashes_;
/**
* Deduplication index over `value_`, for pathfinding.
* The use of a std::unique_ptr is intentional as it
* only requires 8 additional bytes of storage for the pointer
* as opposed to 64 bytes with an optional. This keeps the size
* of the STPathSet to within the `STVar::kMaxSize` limit of 72 bytes.
*/
std::unique_ptr<hardened_hash_set<STPath>> seen_;
public:
struct DeduplicationTag
{
};
STPathSet() = default;
/**
* Deduplication tagged constructor.
* Use when you want to ensure that the STPathSet does not contain duplicate paths.
*/
explicit STPathSet(DeduplicationTag);
STPathSet(SField const& n);
STPathSet(SerialIter& sit, SField const& name);
STPathSet(STPathSet const& other);
STPathSet(STPathSet&&) = default;
STPathSet&
operator=(STPathSet const& other);
STPathSet&
operator=(STPathSet&&) = default;
~STPathSet() override = default;
void
add(Serializer& s) const override;
@@ -204,6 +241,16 @@ public:
[[nodiscard]] SerializedTypeID
getSType() const override;
/**
* @brief assembleAdd adds a path to the set by combining a base path and a tail element.
*
* @param base The base path.
* @param tail The tail element.
* @return true if the path was added, false if it was a duplicate and not added.
* @remarks Requires the STPathSet to be constructed with the DeduplicationTag. The return value
* indicates whether the combined path was inserted (true) or rejected as a duplicate (false).
* It is fine for callers to ignore the return value.
*/
bool
assembleAdd(STPath const& base, STPathElement const& tail);
@@ -229,22 +276,61 @@ public:
[[nodiscard]] bool
empty() const;
void
/**
* @brief pushBack adds a path to the set.
*
* @param e The path to add.
* @return true if the path was added, false if it was a duplicate and not added.
* @remarks If the STPathSet was constructed with the DeduplicationTag, then this method will
* check for duplicates and only add the path if it is not already present in the
* set. If the STPathSet was constructed without the DeduplicationTag,
* then this method will always add the path to the set, regardless of duplicates.
* It is fine for callers to ignore the return value.
*/
bool
pushBack(STPath const& e);
/**
* @brief emplaceBack adds a path to the set.
*
* @param args The arguments to construct the path with.
* @return true if the path was added, false if it was a duplicate and not added.
* @remarks If the STPathSet was constructed with the DeduplicationTag, then this method will
* check for duplicates and only add the path if it is not already present in the
* set. If the STPathSet was constructed without the DeduplicationTag,
* then this method will always add the path to the set, regardless of duplicates.
* It is fine for callers to ignore the return value.
* @note The path is constructed before the duplicate check, so on a false
* return the constructed path is discarded and any argument
* forwarded as an rvalue is left in a moved-from state. Use
* pushBack when the caller needs to keep its path on rejection.
*/
template <typename... Args>
void
bool
emplaceBack(Args&&... args);
[[nodiscard]] bool
contains(STPath const& path) const;
private:
STBase*
copy(std::size_t n, void* buf) const override;
STBase*
move(std::size_t n, void* buf) override;
/**
* @brief Append a path via `append`, then register it in the deduplication index.
*
* @param append Invoked with `value_`; must append exactly one path to it.
* @return true if the path was kept, false if it was a duplicate and was rolled back.
* @remarks Appends to the vector before touching the index, so that a failed allocation
* there leaves both containers untouched rather than leaving the index holding
* a path the vector does not. If the index insert reports a duplicate, or
* throws, the append is rolled back so the two containers stay consistent; in
* the throwing case the exception propagates. With no index (constructed
* without the DeduplicationTag) the append is unconditional.
*/
template <typename Append>
bool
appendUnique(Append&& append);
friend class detail::STVar;
};
@@ -336,7 +422,7 @@ inline STPathElement::STPathElement(
hashValue_ = getHash(*this);
}
inline auto
inline std::uint32_t
STPathElement::getNodeType() const
{
return type_;
@@ -545,25 +631,50 @@ STPathSet::empty() const
return value_.empty();
}
inline void
STPathSet::pushBack(STPath const& e)
template <typename Append>
inline bool
STPathSet::appendUnique(Append&& append)
{
value_.push_back(e);
seenHashes_.emplace(value_.back());
}
// Append to the vector first, so that a failed allocation there leaves both
// containers untouched rather than leaving the index holding a path the
// vector does not.
append(value_);
template <typename... Args>
inline void
STPathSet::emplaceBack(Args&&... args)
{
value_.emplace_back(std::forward<Args>(args)...);
seenHashes_.emplace(value_.back());
if (seen_ == nullptr)
{
return true;
}
try
{
if (!seen_->insert(value_.back()).second)
{
// Already present: roll back the append.
value_.pop_back();
return false;
}
}
catch (...)
{
// The index insert failed, so roll back the append to keep the vector
// and the index consistent.
value_.pop_back();
throw;
}
return true;
}
inline bool
STPathSet::contains(STPath const& path) const
STPathSet::pushBack(STPath const& e)
{
return seenHashes_.contains(path);
return appendUnique([&](auto& value) { value.push_back(e); });
}
template <typename... Args>
inline bool
STPathSet::emplaceBack(Args&&... args)
{
return appendUnique([&](auto& value) { value.emplace_back(std::forward<Args>(args)...); });
}
} // namespace xrpl

View File

@@ -124,6 +124,13 @@ public:
[[nodiscard]] NodeID const&
getNodeID() const noexcept;
/**
* Whether this validation carries a good signature.
*
* Reports false if the signature cannot be checked at all, so a caller
* cannot tell that apart from a bad signature. Either way the validation is
* unusable, and the reason is logged. Only a computed answer is remembered.
*/
[[nodiscard]] bool
isValid() const noexcept;

View File

@@ -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

View File

@@ -10,6 +10,7 @@
#include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/SField.h>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <stdexcept>
@@ -25,6 +26,101 @@ private:
Blob data_;
public:
/**
* A header is never longer than this. The encoder fills a buffer of this
* size and writes only the bytes it used.
*/
static constexpr int kMaxNumberOfBytesInHeader = 3;
// A field whose size varies is stored as a header holding its length, then
// the field data. The header is 1, 2 or 3 bytes long. Nothing outside it says
// which, so the decoder reads the first byte and its value says how long the
// header is:
//
// 0 ... 192 kMin/kMaxValueOfFirstByteFor1ByteHeader
// 193 ... 240 kMin/kMaxValueOfFirstByteFor2ByteHeader
// 241 ... 254 kMin/kMaxValueOfFirstByteFor3ByteHeader
// 255 belongs to no header
//
// Each range starts one past the end of the range before it.
static constexpr int kMinValueOfFirstByteFor1ByteHeader = 0;
static constexpr int kMaxValueOfFirstByteFor1ByteHeader = 192;
static constexpr int kMinValueOfFirstByteFor2ByteHeader =
kMaxValueOfFirstByteFor1ByteHeader + 1;
static constexpr int kMaxValueOfFirstByteFor2ByteHeader = 240;
static constexpr int kMinValueOfFirstByteFor3ByteHeader =
kMaxValueOfFirstByteFor2ByteHeader + 1;
static constexpr int kMaxValueOfFirstByteFor3ByteHeader = 254;
// A length x too big for one byte is split across the header. For 2 bytes:
//
// first byte = 193 + (x - 193) / 256
// second byte = (x - 193) % 256
//
// so 300 is stored as 193, 107. For 3 bytes it is the same, from 241, with
// the remainder split across two bytes: 20,000 is stored as 241, 29, 95.
static constexpr int kNumberOfValuesInOneByte = 256;
static constexpr int kNumberOfValuesInTwoBytes =
kNumberOfValuesInOneByte * kNumberOfValuesInOneByte;
// Each header length therefore covers a range of field lengths:
//
// 0 ... 192 kMin/kMaxValueOfLengthFor1ByteHeader
// 193 ... 12,480 kMin/kMaxValueOfLengthFor2ByteHeader
// 12,481 ... 918,744 kMin/kMaxValueOfLengthFor3ByteHeader
//
// The encoder always uses the shortest header that fits.
/**
* A 1 byte header holds the length in the byte itself, so both ends of
* this range are the same numbers as the first byte's own range.
*/
static constexpr int kMinValueOfLengthFor1ByteHeader = kMinValueOfFirstByteFor1ByteHeader;
static constexpr int kMaxValueOfLengthFor1ByteHeader = kMaxValueOfFirstByteFor1ByteHeader;
static constexpr int kMinValueOfLengthFor2ByteHeader = kMaxValueOfLengthFor1ByteHeader + 1;
/**
* 48 values of the first byte mean a 2 byte header, and each of them covers
* 256 lengths. The 48 is worked out from the two range ends above, so it
* stays right if either of them changes.
*/
static constexpr int kMaxValueOfLengthFor2ByteHeader = kMinValueOfLengthFor2ByteHeader +
((kMaxValueOfFirstByteFor2ByteHeader - kMaxValueOfFirstByteFor1ByteHeader) *
kNumberOfValuesInOneByte) -
1;
static constexpr int kMinValueOfLengthFor3ByteHeader = kMaxValueOfLengthFor2ByteHeader + 1;
/**
* 14 values of the first byte mean a 3 byte header, and each of them covers
* 65,536 lengths. Counted the same way, that gives the largest length any
* header can state.
*
* Nothing is accepted or rejected against this. The assertion below uses it
* to check that every length the encoder writes is one a header can state.
*/
static constexpr int kMaxRepresentableLength = kMinValueOfLengthFor3ByteHeader +
((kMaxValueOfFirstByteFor3ByteHeader - kMaxValueOfFirstByteFor2ByteHeader) *
kNumberOfValuesInTwoBytes) -
1;
/**
* The largest length the encoder will write. This is the one number here
* that is picked rather than worked out. The decoder accepts nothing above
* it, so both sides agree on the same set of lengths.
*/
static constexpr int kMaxValueOfLengthFor3ByteHeader = 918744;
static_assert(
kMaxValueOfLengthFor3ByteHeader <= kMaxRepresentableLength,
"a length the encoder writes must be one a header can state");
explicit Serializer(int n = 256)
{
data_.reserve(n);
@@ -61,7 +157,7 @@ public:
// assemble functions
int
add8(unsigned char i);
add8(unsigned char byteValue);
int
add16(std::uint16_t i);
@@ -270,18 +366,90 @@ public:
return v.data_ == data_;
}
/**
* Works out how long a header is, from its first byte.
*
* Each overload of decodeVLLength below reads one header length, so call
* this first to learn which of them to call.
*
* @param firstByte First byte of the header, as read from the stream.
* @return How many bytes the whole header takes, counting firstByte: 1, 2
* or 3.
* @throws std::overflow_error if firstByte is the one value that starts no
* header.
*/
static int
decodeLengthLength(int b1);
decodeLengthLength(std::byte firstByte);
/**
* Reads the field length out of a 1 byte header.
*
* @param firstByte The single header byte, which is the length itself.
* @return Field length in bytes, from kMinValueOfLengthFor1ByteHeader to
* kMaxValueOfLengthFor1ByteHeader.
* @throws std::overflow_error if firstByte is big enough to mean a longer
* header, in which case it is not a length by itself.
*/
static int
decodeVLLength(int b1);
decodeVLLength(std::byte firstByte);
/**
* Reads the field length out of a 2 byte header.
*
* @param firstByte First header byte. Its value means a 2 byte header, and
* how far it sits into that range gives the top part of the length.
* @param secondByte Second header byte, holding the rest of the length.
* @return Field length in bytes, from kMinValueOfLengthFor2ByteHeader to
* kMaxValueOfLengthFor2ByteHeader.
* @throws std::overflow_error if firstByte is outside the range that means
* a 2 byte header.
*/
static int
decodeVLLength(int b1, int b2);
decodeVLLength(std::byte firstByte, std::byte secondByte);
/**
* Reads the field length out of a 3 byte header.
*
* @param firstByte First header byte. Its value means a 3 byte header, and
* how far it sits into that range gives the top part of the length.
* @param secondByte Second header byte, holding the middle part of the
* length.
* @param thirdByte Third header byte, holding the low part.
* @return Field length in bytes, from kMinValueOfLengthFor3ByteHeader to
* kMaxValueOfLengthFor3ByteHeader.
* @throws std::overflow_error if firstByte is outside the range that means
* a 3 byte header, or if the three bytes together state a length above
* kMaxValueOfLengthFor3ByteHeader, which the encoder would not write back.
*/
static int
decodeVLLength(int b1, int b2, int b3);
decodeVLLength(std::byte firstByte, std::byte secondByte, std::byte thirdByte);
private:
/**
* Works out how many bytes the header needs for the given length.
*
* This deliberately repeats the width choice addEncoded makes, so that
* addVL's assertion can compare the two. It has no other caller; do not
* reach for it as a utility.
*
* @param length Field length in bytes.
* @return How many header bytes it needs: 1, 2 or 3.
* @throws std::overflow_error if length is negative, or above
* kMaxValueOfLengthFor3ByteHeader.
*/
static int
encodeLengthLength(int length); // length to encode length
encodeLengthLength(int length);
/**
* Appends the length header for a field of the given length.
*
* The field's own data is not written; the caller appends it next.
*
* @param length Field length in bytes.
* @return Offset within this Serializer at which the header was written.
* @throws std::overflow_error if length is negative, or above
* kMaxValueOfLengthFor3ByteHeader.
*/
int
addEncoded(int length);
};
@@ -390,9 +558,15 @@ public:
void
getFieldID(int& type, int& name);
// Returns the size of the VL if the
// next object is a VL. Advances the iterator
// to the beginning of the VL.
/**
* Reads the length header at the read position and steps past it.
*
* @return Field length in bytes. The iterator is left on the first byte of
* the field data.
* @throws std::overflow_error if the header states a length the encoder could
* not have written.
* @throws std::runtime_error if the data runs out before the header does.
*/
int
getVLDataLength();

View File

@@ -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), \

View File

@@ -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

View File

@@ -34,10 +34,11 @@ concept ValidConstructSTArgs =
// and includes a small-object allocation optimization.
class STVar
{
private:
public:
// The largest "small object" we can accommodate
static constexpr std::size_t kMaxSize = 72;
private:
alignas(std::max_align_t) std::byte d_[kMaxSize] = {};
STBase* p_ = nullptr;

View File

@@ -60,12 +60,12 @@ XRPL_FIX (ReducedOffersV2, Supported::Yes, VoteBehavior::DefaultNo
XRPL_FEATURE(NFTokenMintOffer, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (AMMv1_1, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (PreviousTxnID, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (XChainRewardRounding, Supported::Yes, VoteBehavior::Obsolete)
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(XChainBridge, Supported::Yes, VoteBehavior::Obsolete)
XRPL_FEATURE(AMM, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(XRPFees, Supported::Yes, VoteBehavior::DefaultNo)
XRPL_FIX (RemoveNFTokenAutoTrustLine, Supported::Yes, VoteBehavior::DefaultYes)

View File

@@ -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
@@ -436,6 +389,8 @@ LEDGER_ENTRY(ltMPTOKEN, 0x007f, MPToken, mptoken, ({
{sfConfidentialBalanceVersion, SoeDefault},
{sfIssuerEncryptedBalance, SoeOptional},
{sfAuditorEncryptedBalance, SoeOptional},
{sfIssuerKeyMirrorEpoch, SoeOptional},
{sfAuditorKeyMirrorEpoch, SoeOptional},
{sfHolderEncryptionKey, SoeOptional},
}))

View File

@@ -23,8 +23,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 unused
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
TYPED_SFIELD(sfContractResult, UINT8, 21)
TYPED_SFIELD(sfVaultKind, UINT8, 22)
@@ -147,9 +146,7 @@ TYPED_SFIELD(sfEmitBurden, UINT64, 13)
// 64-bit integers (uncommon)
// 16 to 18 unused
TYPED_SFIELD(sfReferenceCount, UINT64, 19)
TYPED_SFIELD(sfXChainClaimID, UINT64, 20)
TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21)
TYPED_SFIELD(sfXChainAccountClaimCount, UINT64, 22)
// 20-22 unused
TYPED_SFIELD(sfAssetPrice, UINT64, 23)
TYPED_SFIELD(sfMaximumAmount, UINT64, 24, SField::kSmdBaseTen|SField::kSmdDefault)
TYPED_SFIELD(sfOutstandingAmount, UINT64, 25, SField::kSmdBaseTen|SField::kSmdDefault)
@@ -345,13 +342,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 unused
TYPED_SFIELD(sfSubject, ACCOUNT, 24)
TYPED_SFIELD(sfBorrower, ACCOUNT, 25)
TYPED_SFIELD(sfCounterparty, ACCOUNT, 26)
@@ -376,14 +367,10 @@ TYPED_SFIELD(sfBaseAsset, CURRENCY, 1)
TYPED_SFIELD(sfQuoteAsset, CURRENCY, 2)
// issue
TYPED_SFIELD(sfLockingChainIssue, ISSUE, 1)
TYPED_SFIELD(sfIssuingChainIssue, ISSUE, 2)
// 1 and 2 are unused
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)
@@ -410,10 +397,7 @@ UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19)
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 unused
UNTYPED_SFIELD(sfPriceData, OBJECT, 32)
UNTYPED_SFIELD(sfCredential, OBJECT, 33)
UNTYPED_SFIELD(sfRawTransaction, OBJECT, 34)
@@ -441,10 +425,7 @@ 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 unused
UNTYPED_SFIELD(sfPriceDataSeries, ARRAY, 24)
UNTYPED_SFIELD(sfAuthAccounts, ARRAY, 25)
UNTYPED_SFIELD(sfAuthorizeCredentials, ARRAY, 26)

View File

@@ -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 are unused
/** This transaction type creates or updates a DID */
#if TRANSACTION_INCLUDE

View File

@@ -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
@@ -278,6 +277,7 @@ JSS(frozen_balances); // out: GatewayBalances
JSS(full); // in: LedgerClearer, handlers/Ledger
JSS(full_reply); // out: PathFind
JSS(fullbelow_size); // out: GetCounts
JSS(gateway); // in: noripple_check
JSS(git); // out: server_info
JSS(good); // out: RPCVersion
JSS(hash); // out: NetworkOPs, InboundLedger, LedgerToJson, STTx; field
@@ -481,6 +481,7 @@ JSS(ports); // out: NetworkOPs
JSS(previous); // out: Reservations
JSS(previous_ledger); // out: LedgerPropose
JSS(price); // out: amm_info, AuctionSlot
JSS(problems); // out: noripple_check
JSS(proof); // in: BookOffers
JSS(propose_seq); // out: LedgerPropose
JSS(proposers); // out: NetworkOPs, LedgerConsensus
@@ -660,6 +661,7 @@ JSS(url); // in/out: Subscribe, Unsubscribe
JSS(url_password); // in: Subscribe
JSS(url_username); // in: Subscribe
JSS(urlgravatar); //
JSS(user); // in: noripple_check
JSS(username); // in: Subscribe
JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx*, Tx
JSS(validator_list_expires); // out: NetworkOps, ValidatorList

View File

@@ -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>

View File

@@ -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

View File

@@ -268,6 +268,54 @@ public:
return this->sle_->isFieldPresent(sfAuditorEncryptedBalance);
}
/**
* @brief Get sfIssuerKeyMirrorEpoch (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getIssuerKeyMirrorEpoch() const
{
if (hasIssuerKeyMirrorEpoch())
return this->sle_->at(sfIssuerKeyMirrorEpoch);
return std::nullopt;
}
/**
* @brief Check if sfIssuerKeyMirrorEpoch is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasIssuerKeyMirrorEpoch() const
{
return this->sle_->isFieldPresent(sfIssuerKeyMirrorEpoch);
}
/**
* @brief Get sfAuditorKeyMirrorEpoch (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getAuditorKeyMirrorEpoch() const
{
if (hasAuditorKeyMirrorEpoch())
return this->sle_->at(sfAuditorKeyMirrorEpoch);
return std::nullopt;
}
/**
* @brief Check if sfAuditorKeyMirrorEpoch is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasAuditorKeyMirrorEpoch() const
{
return this->sle_->isFieldPresent(sfAuditorKeyMirrorEpoch);
}
/**
* @brief Get sfHolderEncryptionKey (SoeOptional)
* @return The field value, or std::nullopt if not present.
@@ -471,6 +519,28 @@ public:
return *this;
}
/**
* @brief Set sfIssuerKeyMirrorEpoch (SoeOptional)
* @return Reference to this builder for method chaining.
*/
MPTokenBuilder&
setIssuerKeyMirrorEpoch(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfIssuerKeyMirrorEpoch] = value;
return *this;
}
/**
* @brief Set sfAuditorKeyMirrorEpoch (SoeOptional)
* @return Reference to this builder for method chaining.
*/
MPTokenBuilder&
setAuditorKeyMirrorEpoch(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfAuditorKeyMirrorEpoch] = value;
return *this;
}
/**
* @brief Set sfHolderEncryptionKey (SoeOptional)
* @return Reference to this builder for method chaining.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -14,6 +14,7 @@
#include <xrpl/shamap/SHAMapItem.h>
#include <xrpl/shamap/SHAMapLeafNode.h>
#include <xrpl/shamap/SHAMapMissingNode.h>
#include <xrpl/shamap/SHAMapNodeID.h>
#include <xrpl/shamap/SHAMapTreeNode.h>
#include <condition_variable>
@@ -34,7 +35,6 @@
namespace xrpl {
class SHAMapNodeID;
class SHAMapSyncFilter;
/**
@@ -420,7 +420,107 @@ public:
invariants() const;
private:
using SharedPtrNodeStack = std::stack<std::pair<SHAMapTreeNodePtr, SHAMapNodeID>>;
/**
* A path from the root of the map down to some node, pairing each node with the ID naming its
* position.
*
* The two halves of an entry must agree, and the only way to get that wrong is to compute an ID
* from the wrong branch. So this type does not accept an ID at all: every push takes the branch
* being descended and derives the ID itself, so a node and its ID cannot disagree. Reads are
* exposed through the same accessors a std::stack would offer.
*/
class NodePathStack
{
public:
[[nodiscard]] bool
empty() const
{
return stack_.empty();
}
[[nodiscard]] std::size_t
size() const
{
return stack_.size();
}
[[nodiscard]] std::pair<SHAMapTreeNodePtr, SHAMapNodeID> const&
top() const
{
XRPL_ASSERT(!stack_.empty(), "xrpl::SHAMap::NodePathStack::top : non-empty stack");
return stack_.top();
}
void
pop()
{
XRPL_ASSERT(!stack_.empty(), "xrpl::SHAMap::NodePathStack::pop : non-empty stack");
stack_.pop();
}
void
clear()
{
stack_ = {};
}
/**
* Start a path at the root of the map, whose ID is the zero-depth ID by definition.
*/
void
pushRoot(SHAMapTreeNodePtr node)
{
XRPL_ASSERT(stack_.empty(), "xrpl::SHAMap::NodePathStack::pushRoot : empty stack");
stack_.emplace(std::move(node), SHAMapNodeID{});
}
/**
* Extend the path to the child of the current node reached by `branch`.
*
* A node keeps the depth it was reached at, never a normalized kLeafDepth. Only a leaf may
* sit at kLeafDepth, since an inner node there would have no branch left to select.
*/
void
pushChild(SHAMapTreeNodePtr node, unsigned int branch)
{
XRPL_ASSERT(node, "xrpl::SHAMap::NodePathStack::pushChild : non-null node input");
XRPL_ASSERT(
!stack_.empty(), "xrpl::SHAMap::NodePathStack::pushChild : non-empty stack");
auto childID = stack_.top().second.getChildNodeID(branch);
XRPL_ASSERT_IF(
node->isInner(),
childID.getDepth() < kLeafDepth,
"xrpl::SHAMap::NodePathStack::pushChild : inner node above leaf depth");
XRPL_ASSERT_IF(
node->isLeaf(),
childID.isPrefixOf(leafKey(*node)),
"xrpl::SHAMap::NodePathStack::pushChild : leaf key below branch");
stack_.emplace(std::move(node), std::move(childID));
}
/**
* Extend the path to a node lying on the path to `target`.
*
* For nodes not reached by descending a known branch: the walk tracks only the key it is
* heading for, or the node is newly created. Either way `target` selects the branch.
*/
void
pushNode(SHAMapTreeNodePtr node, uint256 const& target)
{
if (stack_.empty())
{
pushRoot(std::move(node));
}
else
{
pushChild(std::move(node), selectBranch(stack_.top().second, target));
}
}
private:
std::stack<std::pair<SHAMapTreeNodePtr, SHAMapNodeID>> stack_;
};
using DeltaRef =
std::pair<boost::intrusive_ptr<SHAMapItem const>, boost::intrusive_ptr<SHAMapItem const>>;
@@ -447,7 +547,7 @@ private:
* Update hashes up to the root
*/
void
dirtyUp(SharedPtrNodeStack& stack, uint256 const& target, SHAMapTreeNodePtr terminal);
dirtyUp(NodePathStack& stack, uint256 const& target, SHAMapTreeNodePtr terminal);
/**
* Walk towards the specified id, returning the node. Caller must check
@@ -455,7 +555,7 @@ private:
* id
*/
SHAMapLeafNode*
walkTowardsKey(uint256 const& id, SharedPtrNodeStack* stack = nullptr) const;
walkTowardsKey(uint256 const& id, NodePathStack* stack = nullptr) const;
/**
* Return nullptr if key not found
*/
@@ -482,27 +582,15 @@ private:
SHAMapTreeNodePtr
writeNode(NodeObjectType t, SHAMapTreeNodePtr node) const;
// returns the first item at or below this node
SHAMapLeafNode*
firstBelow(SHAMapTreeNodePtr node, SharedPtrNodeStack& stack, unsigned int branch = 0u) const;
// returns the last item at or below this node
SHAMapLeafNode*
lastBelow(
SHAMapTreeNodePtr node,
SharedPtrNodeStack& stack,
unsigned int branch = kBranchFactor) const;
// direction in which belowHelper scans an inner node's branches
// direction in which a scan walks an inner node's branches
enum class BelowDirection { First, Last };
// helper function for firstBelow and lastBelow
/**
* Returns the first or last item at or below the node already on top of `stack`, extending
* `stack` with the path walked to reach it.
*/
SHAMapLeafNode*
belowHelper(
SHAMapTreeNodePtr node,
SharedPtrNodeStack& stack,
unsigned int branch,
BelowDirection direction) const;
belowHelper(NodePathStack& stack, BelowDirection direction) const;
// Simple descent
// Get a child of the specified node
@@ -550,9 +638,9 @@ private:
hasLeafNode(uint256 const& tag, SHAMapHash const& hash) const;
SHAMapLeafNode const*
peekFirstItem(SharedPtrNodeStack& stack) const;
peekFirstItem(NodePathStack& stack) const;
SHAMapLeafNode const*
peekNextItem(uint256 const& id, SharedPtrNodeStack& stack) const;
peekNextItem(uint256 const& id, NodePathStack& stack) const;
bool
walkBranch(
SHAMapTreeNode* node,
@@ -697,7 +785,7 @@ public:
using pointer = value_type const*;
private:
SharedPtrNodeStack stack_;
NodePathStack stack_;
SHAMap const* map_ = nullptr;
pointer item_ = nullptr;
@@ -723,7 +811,7 @@ public:
private:
explicit ConstIterator(SHAMap const* map);
ConstIterator(SHAMap const* map, std::nullptr_t);
ConstIterator(SHAMap const* map, pointer item, SharedPtrNodeStack&& stack);
ConstIterator(SHAMap const* map, pointer item, NodePathStack&& stack);
friend bool
operator==(ConstIterator const& x, ConstIterator const& y);
@@ -742,10 +830,7 @@ inline SHAMap::ConstIterator::ConstIterator(SHAMap const* map, std::nullptr_t) :
{
}
inline SHAMap::ConstIterator::ConstIterator(
SHAMap const* map,
pointer item,
SharedPtrNodeStack&& stack)
inline SHAMap::ConstIterator::ConstIterator(SHAMap const* map, pointer item, NodePathStack&& stack)
: stack_(std::move(stack)), map_(map), item_(item)
{
}

View File

@@ -8,6 +8,7 @@
#include <xrpl/ledger/ApplyViewImpl.h>
#include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/RawView.h>
#include <xrpl/protocol/Book.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STTx.h>
#include <xrpl/protocol/TER.h>
@@ -129,6 +130,14 @@ public:
view_->rawDestroyXRP(fee);
}
/**
* Registers a newly-created order book directory with the shared,
* process-wide OrderBookDB, unless this transaction is being applied
* under TapDryRun.
*/
void
addOrderBook(Book const& book);
ApplyViewContext
getApplyViewContext()
{

View File

@@ -12,6 +12,7 @@
#include <xrpl/protocol/XRPAmount.h>
#include <cstdint>
#include <expected>
#include <optional>
#include <utility>
@@ -393,16 +394,21 @@ preclaim(PreflightResult const& preflightResult, ServiceRegistry& registry, Open
*
* No validation is done or implied by this function.
*
* Caller is responsible for handling any exceptions.
* Since none should be thrown, that will usually
* mean terminating.
*
* Callers do not expect this function to throw; exceptions from a transactor's
* `calculateBaseFee` are caught and reported as an error instead.
* @param view The current open ledger.
* @param tx The transaction to be checked.
*
* @return The base fee.
* @return The base fee on success. Returns `std::unexpected(temUNKNOWN)` if the transaction
* type is not recognized, and `std::unexpected(tefEXCEPTION)` if the transactor's
* `calculateBaseFee` threw.
*
* @note Failure is reported as an error rather than a fee of zero because a
* zero (or default) fee would pass checkFee and let the transaction be
* applied for less than it owes. Callers that only need a fee hint may fall
* back to a default; callers deciding whether to apply should reject.
*/
XRPAmount
[[nodiscard]] std::expected<XRPAmount, TER>
calculateBaseFee(ReadView const& view, STTx const& tx);
/**

View File

@@ -38,9 +38,11 @@ namespace xrpl {
* f. A Loan must reference a live `ltLOAN_BROKER`, and that broker must
* reference a live `ltVAULT`.
* g. Post-conditions for the Loan paid down by a successful `ttLOAN_PAY`:
* `PaymentRemaining > 0` after: `PrincipalOutstanding` and
* `PaymentRemaining` strictly decrease; `NextPaymentDueDate`
* advances by N * `PaymentInterval`, N > 0.
* `PaymentRemaining > 0` after: neither `PrincipalOutstanding` nor
* `TotalValueOutstanding` increases, and at least one of them
* strictly decreases;
* `PaymentRemaining` strictly decreases;
* `NextPaymentDueDate` advances by N * `PaymentInterval`, N > 0.
* `PaymentRemaining == 0` after: pinned by checks 1 and 5b.
*
*/

View File

@@ -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::const_ref before, SLE::const_ref 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::const_ref before, SLE::const_ref 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::const_ref before, SLE::const_ref 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::const_ref before, SLE::const_ref 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::const_ref before, SLE::const_ref 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::const_ref before, SLE::const_ref 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::const_ref before, SLE::const_ref 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::const_ref before, SLE::const_ref 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

View File

@@ -15,7 +15,8 @@ package/
publish_pkg.py Uploads built packages to the XRPLF Nexus repositories (called by CI, and shipped in that image)
rpm/
xrpld.spec RPM spec
debian/ Debian control files (control, rules, copyright, xrpld.docs, xrpld.links, xrpld.lintian-overrides, source/format)
debian/ Debian control files (control.in, lintian-overrides.in, rules, copyright, docs, links, source/format).
The `.in` files are templates rendered by `build_pkg.py`; `docs` and `links` are staged under the package name
shared/
xrpld.service systemd unit file (used by both RPM and DEB)
xrpld.sysusers sysusers.d config (used by both RPM and DEB)
@@ -32,20 +33,74 @@ packaging job cannot drift apart. Today only `linux/amd64` is emitted. The map
pins the full container image in `image` — edit that field to move to a new
image and both CI and local builds pick it up — and names the format that image
builds in `type`, which CI passes to `build_pkg.py` as `--package-type`; the two
have to stay in step.
have to stay in step. An optional `variant` names a flavour of the package (see
[Package variants](#package-variants)), and CI passes it as `--variant`.
| Package type | Image (`configs.<distro>[].package.image` in `linux.json`) | Tools required |
| ------------ | ---------------------------------------------------------- | -------------------------------------------------------------- |
| RPM | `ghcr.io/xrplf/xrpld/packaging-rhel:sha-<sha>` | `rpmbuild`, `rpmsign` |
| DEB | `ghcr.io/xrplf/xrpld/packaging-debian:sha-<sha>` | `dpkg-buildpackage`, debhelper with compat level 13, `lintian` |
To print the full packaging matrix (artifact names and images) for the current
`linux.json`:
To print the full packaging matrix (artifact names, images and package names)
for the current `linux.json`:
```bash
./.github/scripts/strategy-matrix/generate.py --packaging
```
## Package variants
A config whose binaries are not the plain release build cannot be packaged as
`xrpld`: both would carry the same name and version, so whichever published last
would win. It is packaged as a **variant** instead — `variant: "assert"` in its
`package` map, which CI passes to `build_pkg.py` as `--variant assert`,
producing `xrpld-assert`. What the build option itself does is a build concern,
not a packaging one; see the options table in [`BUILD.md`](../BUILD.md).
A variant ships the same paths as `xrpld` — `/usr/bin/xrpld`, `/etc/xrpld`,
`xrpld.service`, `/etc/logrotate.d/xrpld` — differing only in the per-package
documentation directory, so it declares itself a stand-in for the plain package
rather than something installable next to it: `Conflicts`, `Replaces` and a
versioned `Provides: xrpld` on Debian, `Conflicts` and `Provides` on RPM.
Neither format declares `Obsoletes`, so `apt upgrade` and `dnf upgrade` keep an
installed flavour on its own flavour, and switching is always explicit:
```bash
apt-get install xrpld-assert # apt removes the plain package itself
dnf swap xrpld xrpld-VARIANT # 'dnf install' alone stops at the conflict
```
Only the DEB packages carry a variant today — `xrpld-assert` comes from the
`debian` config alone, there being no call for an assert build on RHEL-based
distributions — but the RPM side works the same way if one is added.
A switch is a removal plus an installation rather than an upgrade, so unlike a
version upgrade it stops the service: Debian's scriptlets start it again, while
on RPM the operator runs `systemctl start xrpld`. Configuration survives either
way, being conffiles on Debian and `%config(noreplace)` on RPM.
`dnf` installs the replacement before erasing the old flavour, whose `%preun`
would leave `xrpld.service` disabled, so `%postun` re-applies the preset when
the unit file outlives the erase — which, since rpm keeps a file another
installed package owns, happens only during a swap. The cost is that a
deliberate `systemctl disable` is not carried across an RPM switch.
The alternative is an `xrpld-common` package owning the unit, the sysusers and
tmpfiles snippets and the configuration, required by both flavours at an exact
version: nothing is erased mid-swap, so no scriptlet has to detect one. It is
not worth it for a single variant — it moves files out of the production
package, and a sanitizer flavour would likely need its own unit anyway, putting
the lifecycle back where it is now.
Adding a variant is the flavour in `VARIANTS` in `build_pkg.py`, which is the
list `--variant` accepts, plus a config in `linux.json` with the CMake arguments
and a `package` map naming it, for one format or for both: `generate.py
--packaging` emits the package names per format, and the `test-install-deb` and
`test-install-rpm` jobs install what their own format produced.
Operators switch between the flavours as described in
[`docs/install.md`](../docs/install.md#optional-the-assert-enabled-build).
## Building packages
### Via CI
@@ -56,9 +111,11 @@ Caller workflows (`on-pr.yml`, `on-tag.yml`, `on-trigger.yml`) call
1. `package` fans out one job per config carrying a `package` map, building and
signing in that config's container, and uploading `<config>-pkg` alongside
`<config>-pkg-debug` for the much larger debug symbols.
2. `test-install` installs `<config>-pkg` in the container of every distro the
packages target and runs the binaries there, so one that cannot be installed
never reaches Nexus.
2. `test-install-deb` and `test-install-rpm` call
[`reusable-package-test-install.yml`](../.github/workflows/reusable-package-test-install.yml)
with their format's package names and distro images, installing each package
in the container of every distro that format targets and running the binaries
there, so one that cannot be installed never reaches Nexus.
3. `publish` uploads both artifacts, or lists what it would upload.
The packaging script derives the package version from the downloaded binary's
@@ -104,6 +161,9 @@ docker run --rm \
# build/rpmbuild/RPMS/x86_64/*.rpm
```
Add `--variant assert` to package binaries built with `-Dassert=ON`; the package
is then named `xrpld-assert`.
### Via CMake (host-side target)
If you run CMake configure on a host that has `rpmbuild` or `dpkg-buildpackage`
@@ -133,11 +193,17 @@ The package version is not a CMake input on this path: `build_pkg.py` derives it
from the just-built `xrpld` binary's `xrpld --version` output. The package
release defaults to 1 and is overridable with `-Dpkg_release=N`.
`-Dassert=ON` passes `--variant assert`, so such a build packages as
`xrpld-assert` without anything else being asked for.
## Publishing packages
Packages are published to the XRPLF repositories on Sonatype Nexus at
`https://packages.xrplf.org`. The `release-info` action decides the channel from
the event, and `publish_pkg.py` maps that channel to its repositories:
Packages are published to the XRPLF repositories on Sonatype Nexus through
`https://packages-upload.xrplf.org`. Reads go through
`https://packages.xrplf.org`, which Cloudflare proxies to cache them and which
rejects request bodies over 100 MB, so uploads use the DNS-only host instead.
The `release-info` action decides the channel from the event, and
`publish_pkg.py` maps that channel to its repositories:
| Event | Version | Channel | DEB repository | RPM upload repository |
| ------------------------ | ----------------- | --------- | -------------- | --------------------- |
@@ -147,6 +213,9 @@ the event, and `publish_pkg.py` maps that channel to its repositories:
| push to `develop` | `xrpld --version` | `develop` | `deb-develop` | `rpm-develop-hosted` |
| tag, non-public codebase | _any_ | `private` | `deb-private` | `rpm-private-hosted` |
A variant is published to the same channel under its own name, so
`xrpld-assert` never overwrites `xrpld`.
Only a tag names a channel — do not extend that to `develop`, where
`BuildInfo.cpp`'s `versionString` moves through `-bN`, `-rcN` and even the final
version during a release cycle, which would send develop builds into `stable`.
@@ -160,7 +229,7 @@ the last, and the date and hash say which commit a package on
`packages.xrplf.org` came from. Both reach the packaging scripts as arguments,
so neither script derives anything itself.
Publishing is its own job, gated behind `test-install`, uploading from the same
Publishing is its own job, gated behind the install tests, uploading from the same
image that built the packages with the `publish_pkg.py` shipped in it — the
same copy other repositories run. Without `publish: true` the job is a
`--dry-run`, listing the uploads it would make without needing credentials, so
@@ -175,7 +244,7 @@ Nexus owns the repository metadata; nothing here indexes anything. Worth knowing
- Each apt-hosted repository needs a distribution (ours use `any`) and a PGP
signing keypair configured in Nexus, which rejects one created without a
keypair. Nexus signs the apt metadata with it, never the packages.
- Hosted yum repositories cannot be signed by Nexus, so each `rpm-<channel>-hosted`
- yum-hosted repositories cannot be signed by Nexus, so each `rpm-<channel>-hosted`
repository sits behind a `rpm-<channel>` yum group repository whose metadata
Nexus signs. Uploads go to the hosted repository; clients point at the group
and verify the metadata with `repo_gpgcheck=1`. Nexus never signs the RPMs
@@ -244,6 +313,19 @@ pre-release ordering convention, so RPM filenames/NVRs begin with forms like
`xrpld-3.2.0~b1-...` and `xrpld-3.2.0~rc1-...` instead of encoding
pre-releases with an older `0.<release>.<suffix>` RPM `Release` value.
`--variant` is the flavour of the package, empty by default and accepting only
the flavours in `VARIANTS`; see [Package variants](#package-variants). The RPM
path passes it to the spec as the `pkg_variant` macro, which suffixes `Name` and
adds the `Conflicts`/`Provides` pair. Debian control files have no conditionals, so the DEB path renders
`debian/control.in` and `debian/lintian-overrides.in` instead, substituting
`@PKG@` with the package name and `@VARIANT_FIELDS@` with the
`Conflicts`/`Replaces`/`Provides` block, empty for the plain package; a token
with no value fails the build rather than reaching dpkg. The files debhelper
keys by package name (`docs`, `links`, and the units) are staged under that same
name. The paths inside the package are unchanged either way, so `debian/rules`
reads its package name from `dh_listpackages` and names the unit, sysusers,
tmpfiles and logrotate files with `--name xrpld`.
The package format is `--package-type`, either `deb` or `rpm`. It is required,
so a job never silently builds the wrong format for the image it runs in; the
matching build tool still has to be on PATH.
@@ -286,8 +368,13 @@ service restart.
1. Creates a staging source tree at `debbuild/source/` inside the build directory.
2. Stages the binaries, configs, `README.md`, `LICENSE.md`, and
`validator-keys-LICENSE`.
3. Copies `package/debian/` control files into `debbuild/source/debian/`.
4. Copies shared service/sysusers/tmpfiles/logrotate into `debian/` where `dh_installsystemd`, `dh_installsysusers`, `dh_installtmpfiles` and `dh_installlogrotate` pick them up automatically.
3. Stages `package/debian/` into `debbuild/source/debian/`: the `.in` templates
are rendered, and the files debhelper keys by package name (`docs`, `links`,
`lintian-overrides`) are staged under the name being built.
4. Copies shared service/sysusers/tmpfiles/logrotate into `debian/` as
`<package>.xrpld.*`, which `dh_installsystemd`, `dh_installsysusers`,
`dh_installtmpfiles` and `dh_installlogrotate` read because `debian/rules`
passes them `--name xrpld`.
5. Generates a minimal `debian/changelog` using `${pkg_version}-${PKG_RELEASE}`,
where `pkg_version` is derived from the binary-reported `xrpld` version.
6. Runs `dpkg-buildpackage -b --no-sign -d` (`-d` skips the build-dependency check, since the binary is already built). `debian/rules` uses manual `install` commands.

View File

@@ -21,6 +21,14 @@ SRC_DIR = Path(__file__).resolve().parents[1]
PRE_RELEASE = re.compile(r"^(b|rc)(0|[1-9][0-9]*)(\+.*)?$")
# The package name a variant suffixes, and the name every variant keeps for its
# on-disk paths (/usr/bin/xrpld, /etc/xrpld, xrpld.service).
BASE_NAME = "xrpld"
# The flavours that can be built, '' being the plain xrpld package. A variant
# needs a config in linux.json to be built by CI; see package/README.md.
VARIANTS = ("", "assert")
# Files both packaging systems consume, staged under the same names.
STAGED_FROM_BUILD = ("xrpld", "validator-keys", "validator-keys-LICENSE")
STAGED_FROM_SRC = {
@@ -31,6 +39,18 @@ STAGED_FROM_SRC = {
}
STAGED_UNITS = ("xrpld.service", "xrpld.sysusers", "xrpld.tmpfiles", "xrpld.logrotate")
# debian/ files debhelper keys by package name, staged as '<package>.<name>'.
DEBIAN_PKG_FILES = ("docs", "links")
# Debian control files have no conditionals, so what makes a variant replace the
# plain package is rendered into control.in rather than written there.
DEB_VARIANT_FIELDS = """\
Conflicts: xrpld
Replaces: xrpld
Provides: xrpld (= ${binary:Version})"""
TOKEN = re.compile(r"@[A-Z_]+@")
def run(*command: object, cwd: Path | None = None) -> None:
"""Echo a command and run it."""
@@ -75,6 +95,28 @@ def package_version(reported: str) -> str:
return version
def render(template: Path, dest: Path, values: dict[str, str]) -> None:
"""Write template to dest with its @TOKEN@ placeholders substituted.
A token left without a value fails the build rather than reaching dpkg.
"""
text = template.read_text()
for token, value in values.items():
text = text.replace(f"@{token}@", value)
missing = sorted(set(TOKEN.findall(text)))
assert not missing, f"{template}: no value for {', '.join(missing)}"
# An empty value at the end of a stanza would otherwise leave a blank line,
# which is what ends a stanza.
dest.write_text(text.rstrip("\n") + "\n")
def package_name(variant: str) -> str:
"""The binary package name for a variant: '' -> xrpld, 'assert' -> xrpld-assert."""
return f"{BASE_NAME}-{variant}" if variant else BASE_NAME
def read_version(xrpld: Path) -> str:
"""Read the version from the binary that is about to be packaged."""
fields = capture(xrpld, "--version").partition("\n")[0].split()
@@ -135,17 +177,18 @@ def stage_common(build_dir: Path, dest: Path) -> None:
shutil.copy2(SRC_DIR / source, dest / name)
def stage_units(dest: Path) -> None:
def stage_units(dest: Path, *, prefix: str = "") -> None:
"""Copy the systemd, sysusers, tmpfiles and logrotate files into dest.
Each format wants them somewhere else: rpmbuild reads them from SOURCES,
debhelper from debian/.
Each format wants them somewhere else: rpmbuild reads them from SOURCES by
path, debhelper from debian/ by package name -- hence 'prefix', which makes
the copies 'xrpld-assert.xrpld.service' and so on.
"""
for name in STAGED_UNITS:
shutil.copy2(SRC_DIR / "package" / "shared" / name, dest / name)
shutil.copy2(SRC_DIR / "package" / "shared" / name, dest / f"{prefix}{name}")
def build_rpm(build_dir: Path, *, version: str, pkg_release: str) -> None:
def build_rpm(build_dir: Path, *, version: str, pkg_release: str, variant: str) -> None:
"""Stage the spec and its sources, then build the binary RPMs."""
topdir = build_dir / "rpmbuild"
for name in ("BUILD", "BUILDROOT", "RPMS", "SOURCES", "SPECS", "SRPMS"):
@@ -156,6 +199,9 @@ def build_rpm(build_dir: Path, *, version: str, pkg_release: str) -> None:
stage_common(build_dir, topdir / "SOURCES")
stage_units(topdir / "SOURCES")
# The spec defaults it to nothing, so a plain build is unchanged.
variant_defines = ["--define", f"pkg_variant {variant}"] if variant else []
run(
"rpmbuild",
"-bb",
@@ -168,10 +214,29 @@ def build_rpm(build_dir: Path, *, version: str, pkg_release: str) -> None:
# The image tracks the newest distro, but the packages target el9.
"--define",
"dist .el9",
*variant_defines,
spec,
)
def stage_debian(dest: Path, name: str) -> None:
"""Stage the debian directory for the package name being built."""
source = SRC_DIR / "package" / "debian"
shutil.copytree(
source, dest, ignore=shutil.ignore_patterns("*.in", *DEBIAN_PKG_FILES)
)
values = {
"PKG": name,
"VARIANT_FIELDS": "" if name == BASE_NAME else DEB_VARIANT_FIELDS,
}
render(source / "control.in", dest / "control", values)
render(source / "lintian-overrides.in", dest / f"{name}.lintian-overrides", values)
for suffix in DEBIAN_PKG_FILES:
shutil.copy2(source / suffix, dest / f"{name}.{suffix}")
def build_deb(
build_dir: Path,
*,
@@ -180,21 +245,23 @@ def build_deb(
pkg_release: str,
channel: str,
epoch: int,
name: str,
) -> None:
"""Stage the debian directory and its sources, then build the binary DEBs."""
staging = build_dir / "debbuild" / "source"
stage_common(build_dir, staging)
shutil.copytree(SRC_DIR / "package" / "debian", staging / "debian")
stage_debian(staging / "debian", name)
# debhelper picks these up from debian/ automatically.
stage_units(staging / "debian")
# Prefixed whether it is a variant's name or not: debian/rules names them
# explicitly either way.
stage_units(staging / "debian", prefix=f"{name}.")
date = datetime.fromtimestamp(epoch, timezone.utc).strftime(
"%a, %d %b %Y %H:%M:%S %z"
)
# The leading spaces are significant to dpkg.
changelog = textwrap.dedent(f"""\
xrpld ({version}-{pkg_release}) {channel}; urgency=medium
{name} ({version}-{pkg_release}) {channel}; urgency=medium
* Release {reported}.
-- XRPL Foundation <contact@xrplf.org> {date}
@@ -223,6 +290,14 @@ def main() -> None:
default="1",
help="package release iteration (default: %(default)s)",
)
parser.add_argument(
"--variant",
default="",
choices=VARIANTS,
help="the flavour of the package to build: 'assert' produces "
"xrpld-assert, which ships the same paths as xrpld and replaces it "
"(default: the plain xrpld package)",
)
parser.add_argument(
"--channel",
required=True,
@@ -234,6 +309,8 @@ def main() -> None:
build_dir: Path = args.build_dir.resolve()
pkg_release: str = args.pkg_release
channel: str = args.channel
variant: str = args.variant
name = package_name(variant)
assert build_dir.is_dir(), (
f"build directory not found: {build_dir}. Build the binaries before "
@@ -253,6 +330,8 @@ def main() -> None:
for tree in ("debbuild", "rpmbuild"):
shutil.rmtree(build_dir / tree, ignore_errors=True)
print(f"Building {package_type} {name} {version}-{pkg_release}", flush=True)
if package_type == "deb":
build_deb(
build_dir,
@@ -261,9 +340,10 @@ def main() -> None:
pkg_release=pkg_release,
channel=channel,
epoch=epoch,
name=name,
)
else:
build_rpm(build_dir, version=version, pkg_release=pkg_release)
build_rpm(build_dir, version=version, pkg_release=pkg_release, variant=variant)
if __name__ == "__main__":

View File

@@ -1,4 +1,4 @@
Source: xrpld
Source: @PKG@
Section: net
Priority: optional
Maintainer: XRPL Foundation <contact@xrplf.org>
@@ -11,7 +11,7 @@ Homepage: https://github.com/XRPLF/rippled
Vcs-Git: https://github.com/XRPLF/rippled.git
Vcs-Browser: https://github.com/XRPLF/rippled
Package: xrpld
Package: @PKG@
Architecture: any
Depends:
${shlibs:Depends},
@@ -22,3 +22,4 @@ Description: XRP Ledger daemon
transactions, and maintains the ledger database.
This package also includes the validator-keys tool for validator key
management.
@VARIANT_FIELDS@

View File

@@ -0,0 +1,6 @@
# The /usr/local/bin/rippled symlink is deliberate compatibility for pre-FHS
# layouts, so the Policy 9.1.2 tags it raises are expected.
# TODO: remove alongside debian/links after rippled fully deprecated.
@PKG@: dir-in-usr-local [usr/local/bin/]
@PKG@: file-in-usr-local [usr/local/bin/rippled]
@PKG@: file-in-unusual-dir [usr/local/bin/rippled]

View File

@@ -8,33 +8,58 @@ export DH_VERBOSE = 1
# the binaries actually run on.
LIBC_MIN = 2.31
# The binary package's name, which a variant build changes to e.g. xrpld-assert,
# and the directory debhelper expects its files staged in.
PKG := $(firstword $(shell dh_listpackages))
PKG_DIR = debian/$(PKG)
# The base name, which every package ships under whatever it is called itself.
BASE_NAME = xrpld
# What build_pkg.py stages beside this directory, each installed under its own
# name. The binaries are also the ones checked against LIBC_MIN below.
BINARIES = $(BASE_NAME) validator-keys
CONFIGS = $(BASE_NAME).cfg validators.txt
%:
dh $@
override_dh_auto_configure override_dh_auto_build override_dh_auto_test:
@:
# The unit, sysusers, tmpfiles and logrotate files are named after the daemon
# rather than after the package, so a variant still ships xrpld.service and
# /etc/logrotate.d/xrpld. debhelper only reads debian/$(PKG).$(BASE_NAME).* when told
# the name.
override_dh_installsystemd:
dh_installsystemd --no-stop-on-upgrade xrpld.service
dh_installsystemd --no-stop-on-upgrade --name $(BASE_NAME)
# The tmpfiles snippet sets ownership to the xrpld user, so the sysusers snippet
# has to be emitted first: run it early and make its own sequence slot a no-op.
execute_before_dh_installtmpfiles:
dh_installsysusers
dh_installsysusers --name $(BASE_NAME)
override_dh_installsysusers:
override_dh_installtmpfiles:
dh_installtmpfiles --name $(BASE_NAME)
override_dh_installlogrotate:
dh_installlogrotate --name $(BASE_NAME)
override_dh_install:
install -D -m 0755 xrpld debian/xrpld/usr/bin/xrpld
install -D -m 0755 validator-keys debian/xrpld/usr/bin/validator-keys
install -D -m 0644 xrpld.cfg debian/xrpld/etc/xrpld/xrpld.cfg
install -D -m 0644 validators.txt debian/xrpld/etc/xrpld/validators.txt
for binary in $(BINARIES); do \
install -D -m 0755 "$$binary" "$(PKG_DIR)/usr/bin/$$binary"; \
done
for config in $(CONFIGS); do \
install -D -m 0644 "$$config" "$(PKG_DIR)/etc/$(BASE_NAME)/$$config"; \
done
override_dh_shlibdeps:
dh_shlibdeps
# Guards against the toolchain moving past LIBC_MIN and the packages then
# claiming a floor they do not meet.
for binary in xrpld validator-keys; do \
for binary in $(BINARIES); do \
needed=$$(readelf --dyn-syms --wide $$binary \
| grep -o 'GLIBC_[0-9.]*' | sed 's/GLIBC_//' | sort -uV | tail -1); \
if [ -z "$$needed" ]; then \
@@ -46,7 +71,7 @@ override_dh_shlibdeps:
exit 1; \
fi; \
done
sed -i 's/libc6 (>= [0-9.]*)/libc6 (>= $(LIBC_MIN))/' debian/xrpld.substvars
sed -i 's/libc6 (>= [0-9.]*)/libc6 (>= $(LIBC_MIN))/' debian/$(PKG).substvars
override_dh_dwz:
@:

View File

@@ -1,6 +0,0 @@
# The /usr/local/bin/rippled symlink is deliberate compatibility for pre-FHS
# layouts, so the Policy 9.1.2 tags it raises are expected.
# TODO: remove alongside debian/xrpld.links after rippled fully deprecated.
xrpld: dir-in-usr-local [usr/local/bin/]
xrpld: file-in-usr-local [usr/local/bin/rippled]
xrpld: file-in-unusual-dir [usr/local/bin/rippled]

View File

@@ -98,7 +98,7 @@ def main() -> None:
)
parser.add_argument(
"--nexus-url",
default="https://packages.xrplf.org",
default="https://packages-upload.xrplf.org",
help="the Nexus instance to publish to (default: %(default)s)",
)
parser.add_argument(

View File

@@ -6,10 +6,14 @@
%{error:pkg_release must be defined}
%endif
Name: xrpld
# The base name, which every package ships under. A variant build
# (build_pkg.py --variant) only suffixes the package name, e.g. xrpld-assert.
%global base_name xrpld
Name: %{base_name}%{?pkg_variant:-%{pkg_variant}}
Version: %{pkg_version}
Release: %{pkg_release}%{?dist}
Summary: XRP Ledger daemon
Summary: XRP Ledger daemon%{?pkg_variant: (%{pkg_variant} build)}
License: ISC
URL: https://github.com/XRPLF/rippled
@@ -17,6 +21,12 @@ URL: https://github.com/XRPLF/rippled
ExclusiveArch: x86_64 aarch64
BuildRequires: systemd-rpm-macros
# A variant owns the same paths, so it stands in for the plain package.
%if "%{?pkg_variant}" != ""
Conflicts: %{base_name}
Provides: %{base_name} = %{version}-%{release}
%endif
# These have to precede %%debug_package: it opens the debuginfo subpackage, and
# any tag after it is silently dropped from the main package.
%{?systemd_requires}
@@ -52,22 +62,22 @@ management.
:
%install
install -Dm0755 %{_sourcedir}/xrpld %{buildroot}%{_bindir}/%{name}
install -Dm0755 %{_sourcedir}/xrpld %{buildroot}%{_bindir}/%{base_name}
install -Dm0755 %{_sourcedir}/validator-keys %{buildroot}%{_bindir}/validator-keys
install -Dm0644 %{_sourcedir}/xrpld.cfg %{buildroot}%{_sysconfdir}/%{name}/xrpld.cfg
install -Dm0644 %{_sourcedir}/validators.txt %{buildroot}%{_sysconfdir}/%{name}/validators.txt
install -Dm0644 %{_sourcedir}/xrpld.cfg %{buildroot}%{_sysconfdir}/%{base_name}/xrpld.cfg
install -Dm0644 %{_sourcedir}/validators.txt %{buildroot}%{_sysconfdir}/%{base_name}/validators.txt
# systemd units, sysusers, tmpfiles, preset
install -Dm0644 %{_sourcedir}/xrpld.service %{buildroot}%{_unitdir}/xrpld.service
install -Dm0644 %{_sourcedir}/xrpld.sysusers %{buildroot}%{_sysusersdir}/xrpld.conf
install -Dm0644 %{_sourcedir}/xrpld.tmpfiles %{buildroot}%{_tmpfilesdir}/xrpld.conf
install -d %{buildroot}%{_presetdir}
cat >%{buildroot}%{_presetdir}/50-xrpld.preset <<'EOF'
cat >%{buildroot}%{_presetdir}/50-%{base_name}.preset <<'EOF'
enable xrpld.service
EOF
# Logrotate config
install -Dm0644 %{_sourcedir}/xrpld.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/%{name}
install -Dm0644 %{_sourcedir}/xrpld.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/%{base_name}
# Docs
install -Dm0644 %{_sourcedir}/LICENSE.md %{buildroot}%{_docdir}/%{name}/LICENSE.md
@@ -78,13 +88,13 @@ install -Dm0644 %{_sourcedir}/validator-keys-LICENSE %{buildroot}%{_docdir}/%{na
# Legacy compatibility for pre-FHS package layouts.
# TODO: remove after rippled fully deprecated.
install -d %{buildroot}/usr/local/bin
ln -s %{_bindir}/%{name} %{buildroot}/usr/local/bin/rippled
ln -s %{_bindir}/%{base_name} %{buildroot}/usr/local/bin/rippled
%pre
%sysusers_create_package %{name} %{_sourcedir}/xrpld.sysusers
%sysusers_create_package %{base_name} %{_sourcedir}/xrpld.sysusers
%post
%tmpfiles_create_package %{name} %{_sourcedir}/xrpld.tmpfiles
%tmpfiles_create_package %{base_name} %{_sourcedir}/xrpld.tmpfiles
%systemd_post xrpld.service
%preun
@@ -92,6 +102,13 @@ ln -s %{_bindir}/%{name} %{buildroot}/usr/local/bin/rippled
%postun
%systemd_postun xrpld.service
# A flavour swap installs the replacement before erasing this package, so the
# %%preun above has just disabled a unit the replacement still owns. rpm keeps a
# file that another installed package owns, so the unit outliving our own erase
# means exactly that; a plain erase takes it with us and re-presets nothing.
if [ $1 -eq 0 ] && [ -f %{_unitdir}/xrpld.service ]; then
systemctl preset xrpld.service >/dev/null 2>&1 || :
fi
%files
%attr(0755,root,root) %dir %{_docdir}/%{name}
@@ -99,18 +116,18 @@ ln -s %{_bindir}/%{name} %{buildroot}/usr/local/bin/rippled
%license %{_docdir}/%{name}/validator-keys-LICENSE
%doc %{_docdir}/%{name}/README.md
%attr(0755,root,root) %dir %{_sysconfdir}/%{name}
%attr(0755,root,root) %dir %{_sysconfdir}/%{base_name}
%{_bindir}/%{name}
%{_bindir}/%{base_name}
%{_bindir}/validator-keys
%config(noreplace) %{_sysconfdir}/%{name}/xrpld.cfg
%config(noreplace) %{_sysconfdir}/%{name}/validators.txt
%config(noreplace) %{_sysconfdir}/logrotate.d/%{name}
%config(noreplace) %{_sysconfdir}/%{base_name}/xrpld.cfg
%config(noreplace) %{_sysconfdir}/%{base_name}/validators.txt
%config(noreplace) %{_sysconfdir}/logrotate.d/%{base_name}
%{_unitdir}/xrpld.service
%attr(0644,root,root) %{_presetdir}/50-xrpld.preset
%attr(0644,root,root) %{_presetdir}/50-%{base_name}.preset
%{_sysusersdir}/xrpld.conf
%{_tmpfilesdir}/xrpld.conf
%ghost %dir /var/lib/xrpld

View File

@@ -179,7 +179,7 @@ isPaymentLate(ReadView const& view, SLE::const_ref loanSle)
: ExpiryComparison::Inclusive);
}
namespace accrual {
namespace instant_recognition {
AccountingDeltas
loanOriginationDeltas(Number const& principalRequested, Number const& interestDue)
@@ -217,7 +217,7 @@ loanPaymentDeltas(LoanPaymentParts const& parts)
.debtTotalDelta = (parts.principalPaid + parts.interestPaid) - parts.valueChange};
}
} // namespace accrual
} // namespace instant_recognition
namespace cash_basis {
@@ -250,8 +250,8 @@ 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 accrual-basis
// accounting forever, even after the amendment later turns on.
// VaultVersion::CashBasis). Vaults created before activation keep instant
// interest recognition forever, even after the amendment later turns on.
bool
cashBasisEnabled(SLE::const_ref vaultSle)
{
@@ -268,7 +268,7 @@ loanOriginationDeltas(
{
return cashBasisEnabled(vaultSle)
? cash_basis::loanOriginationDeltas(principalRequested)
: accrual::loanOriginationDeltas(principalRequested, interestDue);
: instant_recognition::loanOriginationDeltas(principalRequested, interestDue);
}
bool
@@ -283,21 +283,22 @@ loanOriginationExceedsVaultMaximum(
return false;
auto const vaultMaximum = vaultSle->at(sfAssetsMaximum);
return accrual::loanOriginationExceedsVaultMaximum(vaultMaximum, vaultTotal, interestDue);
return instant_recognition::loanOriginationExceedsVaultMaximum(
vaultMaximum, vaultTotal, interestDue);
}
Number
loanVaultExposure(SLE::const_ref vaultSle, SLE::const_ref loanSle)
{
return cashBasisEnabled(vaultSle) ? cash_basis::loanVaultExposure(loanSle)
: accrual::loanVaultExposure(loanSle);
: instant_recognition::loanVaultExposure(loanSle);
}
AccountingDeltas
loanPaymentDeltas(SLE::const_ref vaultSle, LoanPaymentParts const& parts)
{
return cashBasisEnabled(vaultSle) ? cash_basis::loanPaymentDeltas(parts)
: accrual::loanPaymentDeltas(parts);
: instant_recognition::loanPaymentDeltas(parts);
}
namespace detail {

View File

@@ -107,8 +107,12 @@ Config::makeConfig(
else
{
config.outPeers = *limits.outPeers;
config.inPeers = *limits.inPeers;
config.maxPeers = 0;
// Inbound slots only exist if we accept incoming connections, and
// `maxPeers` is the total across both directions. The legacy branch
// above upholds the same two invariants.
config.inPeers = config.wantIncoming ? *limits.inPeers : 0;
config.maxPeers = config.inPeers + config.outPeers;
}
// This will cause servers configured as validators to request that

View File

@@ -23,7 +23,7 @@ namespace {
//------------------------------------------------------------------------------
// clang-format off
// NOLINTNEXTLINE(readability-identifier-naming)
char const* const versionString = "3.4.0-rc1"
char const* const versionString = "3.5.0-b0"
// clang-format on
;

View File

@@ -6,9 +6,11 @@
#include <xrpl/basics/contract.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBlob.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/protocol/TER.h>
#include <xrpl/protocol/UintTypes.h>
@@ -397,6 +399,59 @@ checkEncryptedAmountFormat(STObject const& object)
return tesSUCCESS;
}
bool
isIssuerMirrorCurrent(SLE const& issuance, SLE const& mptoken)
{
XRPL_ASSERT(
issuance.getType() == ltMPTOKEN_ISSUANCE,
"xrpl::isIssuerMirrorCurrent : issuance MPTokenIssuance object");
XRPL_ASSERT(
mptoken.getType() == ltMPTOKEN, "xrpl::isIssuerMirrorCurrent : mptoken MPToken object");
return mptoken.isFieldPresent(sfIssuerEncryptedBalance) &&
mptoken[~sfIssuerKeyMirrorEpoch].value_or(0) == issuance[~sfIssuerKeyEpoch].value_or(0);
}
bool
isAuditorMirrorCurrent(SLE const& issuance, SLE const& mptoken)
{
XRPL_ASSERT(
issuance.getType() == ltMPTOKEN_ISSUANCE,
"xrpl::isAuditorMirrorCurrent : issuance MPTokenIssuance object");
XRPL_ASSERT(
mptoken.getType() == ltMPTOKEN, "xrpl::isAuditorMirrorCurrent : mptoken MPToken object");
if (!issuance.isFieldPresent(sfAuditorEncryptionKey))
return true;
return mptoken.isFieldPresent(sfAuditorEncryptedBalance) &&
mptoken[~sfAuditorKeyMirrorEpoch].value_or(0) == issuance[~sfAuditorKeyEpoch].value_or(0);
}
bool
areMirrorsCurrent(SLE const& issuance, SLE const& mptoken)
{
return isIssuerMirrorCurrent(issuance, mptoken) && isAuditorMirrorCurrent(issuance, mptoken);
}
void
setMirrorEpochs(SLE const& issuance, SLE& mptoken)
{
XRPL_ASSERT(
issuance.getType() == ltMPTOKEN_ISSUANCE,
"xrpl::setMirrorEpochs : issuance MPTokenIssuance object");
XRPL_ASSERT(mptoken.getType() == ltMPTOKEN, "xrpl::setMirrorEpochs : mptoken MPToken object");
if (auto const epoch = issuance[~sfIssuerKeyEpoch].value_or(0); epoch != 0)
mptoken[sfIssuerKeyMirrorEpoch] = epoch;
if (mptoken.isFieldPresent(sfAuditorEncryptedBalance))
{
if (auto const epoch = issuance[~sfAuditorKeyEpoch].value_or(0); epoch != 0)
mptoken[sfAuditorKeyMirrorEpoch] = epoch;
}
}
TER
verifySchnorrProof(Slice const& pubKeySlice, Slice const& proofSlice, uint256 const& contextHash)
{

Some files were not shown because too many files have changed in this diff Show More