Compare commits

..

23 Commits

Author SHA1 Message Date
Mayukha Vadari
dcdc5e1b52 fix clang-tidy 2026-03-24 16:12:37 -07:00
Mayukha Vadari
c0895c6e2e fix pre-commit issues 2026-03-24 14:45:37 -07:00
Mayukha Vadari
5b0b1ff1f6 refactor: Replace SLE helper inheritance with view-parameterized templates 2026-03-24 14:41:19 -07:00
Mayukha Vadari
e9c4ed6a74 establish architecture for creating a new object 2026-03-24 12:19:16 -07:00
Mayukha Vadari
deaa23f4e5 cleanup 2026-03-24 12:19:16 -07:00
Mayukha Vadari
638477c824 fix pre-commit issues 2026-03-24 12:19:16 -07:00
Mayukha Vadari
9b42e178a2 add readme 2026-03-24 12:19:16 -07:00
Mayukha Vadari
f41c02d486 WrappedSLEBase -> SLEBase 2026-03-24 12:19:16 -07:00
Mayukha Vadari
a423813098 fix issues 2026-03-24 12:19:16 -07:00
Mayukha Vadari
56c173a097 fix account_ 2026-03-24 12:19:16 -07:00
Mayukha Vadari
7900fa9ead more fixes 2026-03-24 12:19:14 -07:00
Mayukha Vadari
0ffb3e2227 fix long tail issues 2026-03-24 12:14:31 -07:00
Mayukha Vadari
add3d7e68d fix more AccountRoot stuff 2026-03-24 12:14:31 -07:00
Mayukha Vadari
c24432f43a change . to -> 2026-03-24 12:14:31 -07:00
Mayukha Vadari
1ccd84e43a clean up comments 2026-03-24 12:14:31 -07:00
Mayukha Vadari
1cc7424934 Add insert/update/erase to WritableSLE 2026-03-24 12:14:31 -07:00
Mayukha Vadari
b5562cc81e split up read only and write 2026-03-24 12:14:30 -07:00
Mayukha Vadari
e6369c0faa minor improvements 2026-03-24 12:14:30 -07:00
Mayukha Vadari
43caa7d47a fix remaining build issues 2026-03-24 12:14:30 -07:00
Mayukha Vadari
e0f487bb2e fix more build issues 2026-03-24 12:14:30 -07:00
Mayukha Vadari
a8987cf271 fix all the build issues 2026-03-24 12:14:29 -07:00
Mayukha Vadari
4157e3684c First cut of WrappedAccountRoot 2026-03-24 12:13:58 -07:00
Mayukha Vadari
659f455335 add WrappedSLEBase 2026-03-24 12:13:58 -07:00
277 changed files with 2834 additions and 2560 deletions

View File

@@ -21,7 +21,6 @@ libxrpl.protocol > xrpl.json
libxrpl.protocol > xrpl.protocol
libxrpl.protocol_autogen > xrpl.protocol_autogen
libxrpl.rdb > xrpl.basics
libxrpl.rdb > xrpl.core
libxrpl.rdb > xrpl.rdb
libxrpl.resource > xrpl.basics
libxrpl.resource > xrpl.json
@@ -91,7 +90,6 @@ test.core > xrpl.server
test.csf > xrpl.basics
test.csf > xrpld.consensus
test.csf > xrpl.json
test.csf > xrpl.ledger
test.csf > xrpl.protocol
test.json > test.jtx
test.json > xrpl.json
@@ -110,6 +108,7 @@ test.jtx > xrpl.tx
test.ledger > test.jtx
test.ledger > test.toplevel
test.ledger > xrpl.basics
test.ledger > xrpld.app
test.ledger > xrpld.core
test.ledger > xrpl.ledger
test.ledger > xrpl.protocol
@@ -126,7 +125,6 @@ test.overlay > xrpl.basics
test.overlay > xrpld.app
test.overlay > xrpld.overlay
test.overlay > xrpld.peerfinder
test.overlay > xrpl.ledger
test.overlay > xrpl.nodestore
test.overlay > xrpl.protocol
test.overlay > xrpl.shamap
@@ -185,6 +183,7 @@ xrpl.conditions > xrpl.basics
xrpl.conditions > xrpl.protocol
xrpl.core > xrpl.basics
xrpl.core > xrpl.json
xrpl.core > xrpl.ledger
xrpl.core > xrpl.protocol
xrpl.json > xrpl.basics
xrpl.ledger > xrpl.basics
@@ -235,7 +234,6 @@ xrpld.app > xrpl.shamap
xrpld.app > xrpl.tx
xrpld.consensus > xrpl.basics
xrpld.consensus > xrpl.json
xrpld.consensus > xrpl.ledger
xrpld.consensus > xrpl.protocol
xrpld.core > xrpl.basics
xrpld.core > xrpl.core

View File

@@ -1,25 +0,0 @@
name: Label PRs with merge conflicts
on:
# So that PRs touching the same files as the push are updated.
push:
# So that the `dirtyLabel` is removed if conflicts are resolved.
# We recommend `pull_request_target` so that github secrets are available.
# In `pull_request` we wouldn't be able to change labels of fork PRs.
pull_request_target:
types: [synchronize]
permissions:
pull-requests: write
jobs:
main:
runs-on: ubuntu-latest
steps:
- name: Check if PRs are dirty
uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3.0.3
with:
dirtyLabel: "PR: has conflicts"
repoToken: "${{ secrets.GITHUB_TOKEN }}"
commentOnDirty: "This PR has conflicts, please resolve them in order for the PR to be reviewed."
commentOnClean: "All conflicts have been resolved. Assigned reviewers can now start or resume their review."

View File

@@ -6,6 +6,7 @@ on:
push:
branches:
- "develop"
- "release*"
paths:
- ".github/workflows/publish-docs.yml"
- "*.md"

View File

@@ -199,7 +199,7 @@ jobs:
fi
- name: Upload the binary (Linux)
if: ${{ github.event.repository.visibility == 'public' && runner.os == 'Linux' }}
if: ${{ github.repository == 'XRPLF/rippled' && runner.os == 'Linux' }}
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: xrpld-${{ inputs.config_name }}

View File

@@ -83,7 +83,7 @@ jobs:
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" ${TARGETS} 2>&1 | tee clang-tidy-output.txt
- name: Upload clang-tidy output
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
if: steps.run_clang_tidy.outcome != 'success'
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: clang-tidy-results

View File

@@ -51,5 +51,5 @@ jobs:
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_cpp_changed == 'true' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
uses: ./.github/workflows/reusable-clang-tidy-files.yml
with:
files: ${{ (needs.determine-files.outputs.clang_tidy_config_changed != 'true' && inputs.check_only_changed) && needs.determine-files.outputs.all_changed_files || '' }}
files: ${{ needs.determine-files.outputs.clang_tidy_config_changed == 'true' && '' || (inputs.check_only_changed && needs.determine-files.outputs.all_changed_files || '') }}
create_issue_on_failure: ${{ inputs.create_issue_on_failure }}

2
.gitignore vendored
View File

@@ -71,8 +71,6 @@ DerivedData
/.zed/
# AI tools.
/.agent
/.agents
/.augment
/.claude
/CLAUDE.md

View File

@@ -125,9 +125,9 @@ default profile.
### Patched recipes
Occasionally, we need patched recipes or recipes not present in Conan Center.
We maintain a fork of the Conan Center Index
[here](https://github.com/XRPLF/conan-center-index/) containing the modified and newly added recipes.
The recipes in Conan Center occasionally need to be patched for compatibility
with the latest version of `xrpld`. We maintain a fork of the Conan Center
[here](https://github.com/XRPLF/conan-center-index/) containing the patches.
To ensure our patched recipes are used, you must add our Conan remote at a
higher index than the default Conan Center remote, so it is consulted first. You
@@ -137,11 +137,19 @@ can do this by running:
conan remote add --index 0 xrplf https://conan.ripplex.io
```
Alternatively, you can pull our recipes from the repository and export them locally:
Alternatively, you can pull the patched recipes into the repository and use them
locally:
```bash
# Extract the version number from the lockfile.
function extract_version {
version=$(cat conan.lock | sed -nE "s@.+${1}/(.+)#.+@\1@p" | head -n1)
echo ${version}
}
# Define which recipes to export.
recipes=('abseil' 'ed25519' 'grpc' 'm4' 'mpt-crypto' 'nudb' 'openssl' 'secp256k1' 'snappy' 'soci' 'wasm-xrplf' 'wasmi')
recipes=('ed25519' 'grpc' 'nudb' 'openssl' 'secp256k1' 'snappy' 'soci')
folders=('all' 'all' 'all' '3.x.x' 'all' 'all' 'all')
# Selectively check out the recipes from our CCI fork.
cd external
@@ -150,19 +158,29 @@ cd conan-center-index
git init
git remote add origin git@github.com:XRPLF/conan-center-index.git
git sparse-checkout init
for recipe in "${recipes[@]}"; do
echo "Checking out recipe '${recipe}'..."
git sparse-checkout add recipes/${recipe}
for ((index = 1; index <= ${#recipes[@]}; index++)); do
recipe=${recipes[index]}
folder=${folders[index]}
echo "Checking out recipe '${recipe}' from folder '${folder}'..."
git sparse-checkout add recipes/${recipe}/${folder}
done
git fetch origin master
git checkout master
cd ../..
./export_all.sh
cd ../../
# Export the recipes into the local cache.
for ((index = 1; index <= ${#recipes[@]}; index++)); do
recipe=${recipes[index]}
folder=${folders[index]}
version=$(extract_version ${recipe})
echo "Exporting '${recipe}/${version}' from '${recipe}/${folder}'..."
conan export --version $(extract_version ${recipe}) \
external/conan-center-index/recipes/${recipe}/${folder}
done
```
In the case we switch to a newer version of a dependency that still requires a
patch or add a new dependency, it will be necessary for you to pull in the changes and re-export the
patch, it will be necessary for you to pull in the changes and re-export the
updated dependencies with the newer version. However, if we switch to a newer
version that no longer requires a patch, no action is required on your part, as
the new recipe will be automatically pulled from the official Conan Center.
@@ -171,8 +189,6 @@ the new recipe will be automatically pulled from the official Conan Center.
> You might need to add `--lockfile=""` to your `conan install` command
> to avoid automatic use of the existing `conan.lock` file when you run
> `conan export` manually on your machine
>
> This is not recommended though, as you might end up using different revisions of recipes.
### Conan profile tweaks
@@ -188,14 +204,39 @@ Possible values are ['5.0', '5.1', '6.0', '6.1', '7.0', '7.3', '8.0', '8.1',
Read "http://docs.conan.io/2/knowledge/faq.html#error-invalid-setting"
```
you need to add your compiler to the list of compiler versions in
`$(conan config home)/settings_user.yml`, by adding the required version number(s)
you need to amend the list of compiler versions in
`$(conan config home)/settings.yml`, by appending the required version number(s)
to the `version` array specific for your compiler. For example:
```yaml
compiler:
apple-clang:
version: ["17.0"]
apple-clang:
version:
[
"5.0",
"5.1",
"6.0",
"6.1",
"7.0",
"7.3",
"8.0",
"8.1",
"9.0",
"9.1",
"10.0",
"11.0",
"12.0",
"13",
"13.0",
"13.1",
"14",
"14.0",
"15",
"15.0",
"16",
"16.0",
"17",
"17.0",
]
```
#### Multiple compilers

View File

@@ -259,10 +259,6 @@ There is a Continuous Integration job that runs clang-tidy on pull requests. The
This ensures that configuration changes don't introduce new warnings across the codebase.
### Installing clang-tidy
See the [environment setup guide](./docs/build/environment.md#clang-tidy) for platform-specific installation instructions.
### Running clang-tidy locally
Before running clang-tidy, you must build the project to generate required files (particularly protobuf headers). Refer to [`BUILD.md`](./BUILD.md) for build instructions.
@@ -270,15 +266,10 @@ Before running clang-tidy, you must build the project to generate required files
Then run clang-tidy on your local changes:
```
run-clang-tidy -p build src include tests
run-clang-tidy -p build src tests
```
This will check all source files in the `src`, `include` and `tests` directories using the compile commands from your `build` directory.
If you wish to automatically fix whatever clang-tidy finds _and_ is capable of fixing, add `-fix` to the above command:
```
run-clang-tidy -p build -fix src include tests
```
This will check all source files in the `src` and `tests` directories using the compile commands from your `build` directory.
## Contracts and instrumentation

View File

@@ -1,7 +1,7 @@
ISC License
Copyright (c) 2011, Arthur Britto, David Schwartz, Jed McCaleb, Vinnie Falco, Bob Way, Eric Lombrozo, Nikolaos D. Bougalis, Howard Hinnant.
Copyright (c) 2012-present, the XRP Ledger developers.
Copyright (c) 2012-2025, the XRP Ledger developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above

View File

@@ -140,28 +140,6 @@ function(setup_protocol_autogen)
)
endif()
# Check pip index URL configuration
execute_process(
COMMAND ${VENV_PIP} config get global.index-url
OUTPUT_VARIABLE PIP_INDEX_URL
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET
)
# Default PyPI URL
set(DEFAULT_PIP_INDEX "https://pypi.org/simple")
# Show warning if using non-default index
if(PIP_INDEX_URL AND NOT PIP_INDEX_URL STREQUAL "")
if(NOT PIP_INDEX_URL STREQUAL DEFAULT_PIP_INDEX)
message(
WARNING
"Private pip index URL detected: ${PIP_INDEX_URL}\n"
"You may need to connect to VPN to access this URL."
)
endif()
endif()
message(STATUS "Installing Python dependencies...")
execute_process(
COMMAND ${VENV_PIP} install --upgrade pip

View File

@@ -1,16 +1,16 @@
{
"version": "0.5",
"requires": [
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1774439233.809",
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1765850150.075",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987",
"sqlite3/3.51.0#66aa11eabd0e34954c5c1c061ad44abe%1763899256.358",
"soci/4.0.3#fe32b9ad5eb47e79ab9e45a68f363945%1774450067.231",
"sqlite3/3.49.1#8631739a4c9b93bd3d6b753bac548a63%1765850149.926",
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1765850149.46",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878",
"secp256k1/0.7.1#481881709eb0bdd0185a12b912bbe8ad%1770910500.329",
"secp256k1/0.7.1#3a61e95e220062ef32c48d019e9c81f7%1770306721.686",
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1765850186.86",
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1774398111.888",
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1773224203.27",
"openssl/3.6.1#e6399de266349245a4542fc5f6c71552%1774458290.139",
"re2/20230301#ca3b241baec15bd31ea9187150e0b333%1765850148.103",
"protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1765850161.038",
"openssl/3.5.5#05a4ac5b7323f7a329b2db1391d9941f%1769599205.414",
"nudb/2.0.9#0432758a24204da08fee953ec9ea03cb%1769436073.32",
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914",
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492",
@@ -18,26 +18,27 @@
"libarchive/3.8.1#ffee18995c706e02bf96e7a2f7042e0d%1765850144.736",
"jemalloc/5.3.0#e951da9cf599e956cebc117880d2d9f8%1729241615.244",
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1768312129.152",
"grpc/1.78.1#b1a9e74b145cc471bed4dc64dc6eb2c1%1772623605.068",
"grpc/1.72.0#f244a57bff01e708c55a1100b12e1589%1765850193.734",
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1765850143.772",
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1765850143.772",
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1774439234.681",
"c-ares/1.34.5#5581c2b62a608b40bb85d965ab3ec7c8%1765850144.336",
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1765850143.837",
"boost/1.90.0#d5e8defe7355494953be18524a7f135b%1769454080.269",
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196"
"abseil/20250127.0#99262a368bd01c0ccca8790dfced9719%1766517936.993"
],
"build_requires": [
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1774439233.809",
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1774447376.964",
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1773224203.27",
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1765850150.075",
"strawberryperl/5.32.1.1#707032463aa0620fa17ec0d887f5fe41%1765850165.196",
"protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1765850161.038",
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1765850144.707",
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
"m4/1.4.19#5d7a4994e5875d76faf7acf3ed056036%1774365463.87",
"cmake/4.3.0#b939a42e98f593fb34d3a8c5cc860359%1774439249.183",
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1774439233.447",
"msys2/cci.latest#eea83308ad7e9023f7318c60d5a9e6cb%1770199879.083",
"m4/1.4.19#70dc8bbb33e981d119d2acc0175cf381%1763158052.846",
"cmake/4.2.0#ae0a44f44a1ef9ab68fd4b3e9a1f8671%1765850153.937",
"cmake/3.31.10#313d16a1aa16bbdb2ca0792467214b76%1765850153.479",
"b2/5.3.3#107c15377719889654eb9a162a673975%1765850144.355",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86",
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196"
"abseil/20250127.0#99262a368bd01c0ccca8790dfced9719%1766517936.993"
],
"python_requires": [],
"overrides": {
@@ -45,14 +46,14 @@
null,
"boost/1.90.0"
],
"protobuf/[>=5.27.0 <7]": [
"protobuf/6.33.5"
"protobuf/5.27.0": [
"protobuf/6.32.1"
],
"lz4/1.9.4": [
"lz4/1.10.0"
],
"sqlite3/[>=3.44 <4]": [
"sqlite3/3.51.0"
"sqlite3/3.44.2": [
"sqlite3/3.49.1"
],
"boost/1.83.0": [
"boost/1.90.0"

View File

@@ -1,9 +1,10 @@
import os
import re
import os
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
from conan import ConanFile
from conan import __version__ as conan_version
class Xrpl(ConanFile):
@@ -29,10 +30,10 @@ class Xrpl(ConanFile):
requires = [
"ed25519/2015.03",
"grpc/1.78.1",
"grpc/1.72.0",
"libarchive/3.8.1",
"nudb/2.0.9",
"openssl/3.6.1",
"openssl/3.5.5",
"secp256k1/0.7.1",
"soci/4.0.3",
"zlib/1.3.1",
@@ -43,7 +44,7 @@ class Xrpl(ConanFile):
]
tool_requires = [
"protobuf/6.33.5",
"protobuf/6.32.1",
]
default_options = {
@@ -136,16 +137,20 @@ class Xrpl(ConanFile):
self.default_options["fPIC"] = False
def requirements(self):
self.requires("boost/1.90.0", force=True, transitive_headers=True)
self.requires("date/3.0.4", transitive_headers=True)
# Conan 2 requires transitive headers to be specified
transitive_headers_opt = (
{"transitive_headers": True} if conan_version.split(".")[0] == "2" else {}
)
self.requires("boost/1.90.0", force=True, **transitive_headers_opt)
self.requires("date/3.0.4", **transitive_headers_opt)
self.requires("lz4/1.10.0", force=True)
self.requires("protobuf/6.33.5", force=True)
self.requires("sqlite3/3.51.0", force=True)
self.requires("protobuf/6.32.1", force=True)
self.requires("sqlite3/3.49.1", force=True)
if self.options.jemalloc:
self.requires("jemalloc/5.3.0")
if self.options.rocksdb:
self.requires("rocksdb/10.5.1")
self.requires("xxhash/0.8.3", transitive_headers=True)
self.requires("xxhash/0.8.3", **transitive_headers_opt)
exports_sources = (
"CMakeLists.txt",

View File

@@ -297,7 +297,6 @@ words:
- venv
- vfalco
- vinnie
- wasmi
- wextra
- wptr
- writeme

View File

@@ -109,32 +109,3 @@ Install CMake with Homebrew too:
```
brew install cmake
```
## Clang-tidy
Clang-tidy is required to run static analysis checks locally (see [CONTRIBUTING.md](../../CONTRIBUTING.md)).
It is not required to build the project. Currently this project uses clang-tidy version 21.
### Linux
LLVM 21 is not available in the default Debian 12 (Bookworm) repositories.
Install it using the official LLVM apt installer:
```
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 21
sudo apt install --yes clang-tidy-21
```
Then use `run-clang-tidy-21` when running clang-tidy locally.
### macOS
Install LLVM 21 via Homebrew:
```
brew install llvm@21
```
Then use `run-clang-tidy` from the LLVM 21 Homebrew prefix when running clang-tidy locally.

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/Blob.h>
#include <xrpl/basics/SHAMapHash.h>
#include <xrpl/basics/TaggedCache.h>
#include <xrpl/ledger/CachedSLEs.h>
#include <boost/asio.hpp>
@@ -22,20 +23,6 @@ class PerfLog;
// This is temporary until we migrate all code to use ServiceRegistry.
class Application;
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
class TaggedCache;
class STLedgerEntry;
using SLE = STLedgerEntry;
using CachedSLEs = TaggedCache<uint256, SLE const>;
// Forward declarations
class AcceptedLedger;
class AmendmentTable;
@@ -58,7 +45,7 @@ class NetworkIDService;
class OpenLedger;
class OrderBookDB;
class Overlay;
class PathRequestManager;
class PathRequests;
class PeerReservationTable;
class PendingSaves;
class RelationalDatabase;
@@ -102,7 +89,7 @@ public:
getNodeFamily() = 0;
virtual TimeKeeper&
getTimeKeeper() = 0;
timeKeeper() = 0;
virtual JobQueue&
getJobQueue() = 0;
@@ -111,7 +98,7 @@ public:
getTempNodeCache() = 0;
virtual CachedSLEs&
getCachedSLEs() = 0;
cachedSLEs() = 0;
virtual NetworkIDService&
getNetworkIDService() = 0;
@@ -133,26 +120,26 @@ public:
getValidations() = 0;
virtual ValidatorList&
getValidators() = 0;
validators() = 0;
virtual ValidatorSite&
getValidatorSites() = 0;
validatorSites() = 0;
virtual ManifestCache&
getValidatorManifests() = 0;
validatorManifests() = 0;
virtual ManifestCache&
getPublisherManifests() = 0;
publisherManifests() = 0;
// Network services
virtual Overlay&
getOverlay() = 0;
overlay() = 0;
virtual Cluster&
getCluster() = 0;
cluster() = 0;
virtual PeerReservationTable&
getPeerReservations() = 0;
peerReservations() = 0;
virtual Resource::Manager&
getResourceManager() = 0;
@@ -187,13 +174,13 @@ public:
getLedgerReplayer() = 0;
virtual PendingSaves&
getPendingSaves() = 0;
pendingSaves() = 0;
virtual OpenLedger&
getOpenLedger() = 0;
openLedger() = 0;
virtual OpenLedger const&
getOpenLedger() const = 0;
openLedger() const = 0;
// Transaction and operation services
virtual NetworkOPs&
@@ -208,8 +195,8 @@ public:
virtual TxQ&
getTxQ() = 0;
virtual PathRequestManager&
getPathRequestManager() = 0;
virtual PathRequests&
getPathRequests() = 0;
// Server services
virtual ServerHandler&
@@ -223,16 +210,16 @@ public:
isStopping() const = 0;
virtual beast::Journal
getJournal(std::string const& name) = 0;
journal(std::string const& name) = 0;
virtual boost::asio::io_context&
getIOContext() = 0;
virtual Logs&
getLogs() = 0;
logs() = 0;
virtual std::optional<uint256> const&
getTrapTxID() const = 0;
trapTxID() const = 0;
/** Retrieve the "wallet database" */
virtual DatabaseCon&
@@ -241,7 +228,7 @@ public:
// Temporary: Get the underlying Application for functions that haven't
// been migrated yet. This should be removed once all code is migrated.
virtual Application&
getApp() = 0;
app() = 0;
};
} // namespace xrpl

View File

@@ -19,6 +19,11 @@
namespace xrpl {
// Forward declarations for SLE wrappers
template <typename ViewT>
class AccountRoot;
using ReadOnlyAccountRoot = AccountRoot<ReadView>;
enum class SkipEntry : bool { No = false, Yes };
//------------------------------------------------------------------------------
@@ -157,7 +162,7 @@ canWithdraw(
ReadView const& view,
AccountID const& from,
AccountID const& to,
SLE::const_ref toSle,
ReadOnlyAccountRoot const& toWrapped,
STAmount const& amount,
bool hasDestinationTag);

View File

@@ -2,8 +2,10 @@
#include <xrpl/basics/Expected.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/SLEBase.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Rate.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -15,40 +17,145 @@
namespace xrpl {
/** Check if the issuer has the global freeze flag set.
@param issuer The account to check
@return true if the account has global freeze set
*/
[[nodiscard]] bool
isGlobalFrozen(ReadView const& view, AccountID const& issuer);
// Calculate liquid XRP balance for an account.
// This function may be used to calculate the amount of XRP that
// the holder is able to freely spend. It subtracts reserve requirements.
//
// ownerCountAdj adjusts the owner count in case the caller calculates
// before ledger entries are added or removed. Positive to add, negative
// to subtract.
//
// @param ownerCountAdj positive to add to count, negative to reduce count.
[[nodiscard]] XRPAmount
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j);
/** Adjust the owner count up or down. */
void
adjustOwnerCount(
ApplyView& view,
std::shared_ptr<SLE> const& sle,
std::int32_t amount,
beast::Journal j);
/** Returns IOU issuer transfer fee as Rate. Rate specifies
* the fee as fractions of 1 billion. For example, 1% transfer rate
* is represented as 1,010,000,000.
* @param issuer The IOU issuer
/**
* View-parameterized wrapper for AccountRoot ledger entries.
*
* AccountRoot<ReadView> — read-only access to account data
* AccountRoot<ApplyView> — read-write access, with insert/update/erase
* and domain-specific write methods
*/
[[nodiscard]] Rate
transferRate(ReadView const& view, AccountID const& issuer);
template <typename ViewT>
class AccountRoot : public SLEBase<ViewT>
{
static constexpr bool is_writable = SLEBase<ViewT>::is_writable;
AccountID const id_;
public:
/** Constructor for read-only context */
AccountRoot(AccountID const& id, ReadView const& view)
requires(!is_writable)
: SLEBase<ViewT>(view.read(keylet::account(id)), view), id_(id)
{
}
/** Constructor for writable context */
AccountRoot(AccountID const& id, ApplyView& view)
requires is_writable
: SLEBase<ViewT>(keylet::account(id), view), id_(id)
{
}
/** Converting constructor: writable → read-only. */
template <WritableView OtherViewT>
AccountRoot(AccountRoot<OtherViewT> const& other)
requires(!is_writable)
: SLEBase<ViewT>(other), id_(other.id())
{
}
/** Create an AccountRoot backed by a brand-new SLE
* (not yet inserted into the view).
*/
[[nodiscard]] static AccountRoot
makeNew(AccountID const& id, ApplyView& view)
requires is_writable
{
return AccountRoot(id, view, std::make_shared<SLE>(keylet::account(id)));
}
AccountID const&
id() const
{
return id_;
}
// --- Read-only domain methods (available on both specializations) ---
/** Check if the issuer has the global freeze flag set.
@return true if the account has global freeze set
*/
[[nodiscard]] bool
isGlobalFrozen() const;
/** Returns IOU issuer transfer fee as Rate. Rate specifies
* the fee as fractions of 1 billion. For example, 1% transfer rate
* is represented as 1,010,000,000.
*/
[[nodiscard]] Rate
transferRate() const;
// Calculate liquid XRP balance for an account.
// This function may be used to calculate the amount of XRP that
// the holder is able to freely spend. It subtracts reserve requirements.
//
// ownerCountAdj adjusts the owner count in case the caller calculates
// before ledger entries are added or removed. Positive to add, negative
// to subtract.
//
// @param ownerCountAdj positive to add to count, negative to reduce count.
[[nodiscard]] XRPAmount
xrpLiquid(std::int32_t ownerCountAdj, beast::Journal j) const;
/** Checks the destination and tag.
- Checks that the SLE is not null.
- If the SLE requires a destination tag, checks that there is a tag.
*/
[[nodiscard]] TER
checkDestinationAndTag(bool hasDestinationTag) const;
/** Returns true if and only if sleAcct is a pseudo-account or specific
pseudo-accounts in pseudoFieldFilter.
Returns false if sleAcct is:
- NOT a pseudo-account OR
- NOT a ltACCOUNT_ROOT OR
- null pointer
*/
[[nodiscard]] bool
isPseudoAccount(std::set<SField const*> const& pseudoFieldFilter = {}) const;
[[nodiscard]] bool
operator==(AccountRoot const& other) const
{
return id_ == other.id_;
}
[[nodiscard]] bool
operator==(AccountID const& other) const
{
return id_ == other;
}
// --- Write-only domain methods (compile-time gated) ---
/** Adjust the owner count up or down. */
void
adjustOwnerCount(std::int32_t amount, beast::Journal j)
requires is_writable;
private:
// Private constructor only used by `makeNew`
AccountRoot(AccountID const& id, ApplyView& view, std::shared_ptr<SLE> sle)
requires is_writable
: SLEBase<ViewT>(std::move(sle), view), id_(id)
{
this->insert();
}
};
// CTAD deduction guide — bare AccountRoot(id, view) always deduces read-only.
// For writable access, use WritableAccountRoot(id, applyView) explicitly.
AccountRoot(AccountID const&, ReadView const&) -> AccountRoot<ReadView>;
// Backward-compatible aliases
using ReadOnlyAccountRoot = AccountRoot<ReadView>;
using WritableAccountRoot = AccountRoot<ApplyView>;
// Explicit instantiation declarations (definitions in .cpp)
extern template class AccountRoot<ReadView>;
extern template class AccountRoot<ApplyView>;
/** Generate a pseudo-account address from a pseudo owner key.
@param pseudoOwnerKey The key to generate the address from
@@ -87,7 +194,10 @@ isPseudoAccount(
AccountID const& accountId,
std::set<SField const*> const& pseudoFieldFilter = {})
{
return isPseudoAccount(view.read(keylet::account(accountId)), pseudoFieldFilter);
AccountRoot<ReadView> const acct(accountId, view);
if (!acct)
return false;
return acct.isPseudoAccount(pseudoFieldFilter);
}
/**
@@ -101,12 +211,4 @@ isPseudoAccount(
[[nodiscard]] Expected<std::shared_ptr<SLE>, TER>
createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField);
/** Checks the destination and tag.
- Checks that the SLE is not null.
- If the SLE requires a destination tag, checks that there is a tag.
*/
[[nodiscard]] TER
checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag);
} // namespace xrpl

View File

@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STTx.h>
@@ -73,8 +74,7 @@ verifyDepositPreauth(
STTx const& tx,
ApplyView& view,
AccountID const& src,
AccountID const& dst,
std::shared_ptr<SLE const> const& sleDst,
ReadOnlyAccountRoot const& dst,
beast::Journal j);
} // namespace xrpl

View File

@@ -0,0 +1,39 @@
# Ledger Entry Helpers (`entries/`)
## Overview
This folder contains helper classes and free functions for working with **Serialized Ledger Entries (SLEs)**. Its centerpiece is `SLEBase.h`, which defines two base classes — `ReadOnlySLE` and `WritableSLE` — that provide a type-safe, context-aware wrapper around the raw `std::shared_ptr<SLE>` used throughout the rest of the codebase.
## The Problem: Untyped SLE Access
Historically, ledger entries are passed around as bare `std::shared_ptr<SLE>` (or `std::shared_ptr<SLE const>`). This has several drawbacks:
1. **No compile-time entry-type safety.** Any code holding an `std::shared_ptr<SLE>` can read or write _any_ field on _any_ ledger entry type. Nothing prevents you from calling `sle->getFieldU32(sfOwnerCount)` on an Offer SLE, even though Offers don't have that field.
2. **No read/write distinction.** A function that only needs to _read_ an entry still receives a mutable `std::shared_ptr<SLE>`, making it easy to accidentally mutate state. Conversely, a function that _must_ write has no way to express that requirement in its signature.
3. **No association with the view.** The SLE and the `ReadView` / `ApplyView` it came from travel as separate arguments, so callers must manually keep them in sync and remember to call `view.update(sle)` after mutations.
## The Solution: `SLEBase.h`
`SLEBase.h` introduces two base classes that pair an SLE with its view context and enforce read/write semantics at compile time.
**`ReadOnlySLE`** bundles a `std::shared_ptr<SLE const>` with the `ReadView` it was read from. It provides existence checks and const-only access to the underlying entry. Derived classes add domain-specific read-only accessors (e.g. `AccountRoot::isGlobalFrozen()`).
**`WritableSLE`** bundles a mutable `std::shared_ptr<SLE>` with the `ApplyView` used for writes. It provides helpers to insert, update, and erase the entry in the view, keeping the SLE and its view in sync automatically.
### Dual-Inheritance Pattern
Concrete writable wrappers inherit from _both_ the read-only wrapper and `WritableSLE`:
```
WritableAccountRoot
├── AccountRoot (extends ReadOnlySLE) — read-only domain methods
└── WritableSLE — write capabilities
```
This lets a writable wrapper reuse all read-only domain logic from its parent while gaining mutation and persistence operations from `WritableSLE`.
## Migration Status
This migration is still in progress and is still in the early stages. New code should prefer the wrapper style where possible; existing free functions will be migrated incrementally.

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/IOUAmount.h>
#include <xrpl/protocol/Issue.h>
@@ -137,16 +138,16 @@ trustCreate(
bool const bSrcHigh,
AccountID const& uSrcAccountID,
AccountID const& uDstAccountID,
uint256 const& uIndex, // --> ripple state entry
SLE::ref sleAccount, // --> the account being set.
bool const bAuth, // --> authorize account.
bool const bNoRipple, // --> others cannot ripple through
bool const bFreeze, // --> funds cannot leave
bool bDeepFreeze, // --> can neither receive nor send funds
STAmount const& saBalance, // --> balance of account being set.
// Issuer should be noAccount()
STAmount const& saLimit, // --> limit for account being set.
// Issuer should be the account being set.
uint256 const& uIndex, // ripple state entry
WritableAccountRoot& wrappedAcct, // the account being set.
bool const bAuth, // authorize account.
bool const bNoRipple, // others cannot ripple through
bool const bFreeze, // funds cannot leave
bool bDeepFreeze, // can neither receive nor send funds
STAmount const& saBalance, // balance of account being set.
// Issuer should be noAccount()
STAmount const& saLimit, // limit for account being set.
// Issuer should be the account being set.
std::uint32_t uQualityIn,
std::uint32_t uQualityOut,
beast::Journal j);

View File

@@ -0,0 +1,228 @@
#pragma once
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <concepts>
#include <memory>
#include <stdexcept>
#include <type_traits>
namespace xrpl {
// Concept to distinguish read-only vs writable view types
template <typename V>
concept WritableView = std::derived_from<V, ApplyView>;
/**
* View-parameterized base class for all ledger entry wrappers.
*
* 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 wrappers cannot mutate state.
*
* Derived classes should provide domain-specific accessors that hide
* implementation details of the underlying ledger entry format.
*/
template <typename ViewT>
class SLEBase
{
public:
static constexpr bool is_writable = WritableView<ViewT>;
// SLE pointer type: mutable for writable views, const for read-only
using sle_ptr_type =
std::conditional_t<is_writable, std::shared_ptr<SLE>, std::shared_ptr<SLE const>>;
// View reference type: ApplyView& for writable, ReadView const& for read-only
using view_ref_type = std::conditional_t<is_writable, ApplyView&, ReadView const&>;
virtual ~SLEBase() = default;
SLEBase(SLEBase const&) = default;
SLEBase(SLEBase&&) = default;
SLEBase&
operator=(SLEBase const&) = delete;
SLEBase&
operator=(SLEBase&&) = delete;
// --- Common interface (always available) ---
/** Returns true if the ledger entry exists */
bool
exists() const
{
return sle_ != nullptr;
}
/** Explicit conversion to bool for convenient existence checking */
explicit
operator bool() const
{
return exists();
}
/** Returns the underlying SLE for read access */
std::shared_ptr<SLE const>
sle() const
{
return sle_;
}
/** Returns the read view (always available; ApplyView inherits ReadView) */
ReadView const&
readView() const
{
return view_;
}
/** Const dereference operators (always available) */
STLedgerEntry const*
operator->() const
{
XRPL_ASSERT(exists(), "xrpl::SLEBase::operator-> : exists");
return sle_.get();
}
STLedgerEntry const&
operator*() const
{
XRPL_ASSERT(exists(), "xrpl::SLEBase::operator* : exists");
return *sle_;
}
// --- Writable interface (compile-time gated) ---
/** Returns a mutable SLE for write operations */
sle_ptr_type const&
mutableSle() const
requires is_writable
{
return sle_;
}
/** Returns true if this wrapper supports write operations */
bool
canModify() const
requires is_writable
{
return sle_ != nullptr;
}
/** Returns the apply view for write operations */
ApplyView&
applyView() const
requires is_writable
{
return view_;
}
/** Mutable dereference operators */
STLedgerEntry*
operator->()
requires is_writable
{
XRPL_ASSERT(canModify(), "xrpl::SLEBase::operator-> : can modify");
return sle_.get();
}
STLedgerEntry&
operator*()
requires is_writable
{
XRPL_ASSERT(canModify(), "xrpl::SLEBase::operator* : can modify");
return *sle_;
}
void
insert()
requires is_writable
{
XRPL_ASSERT(canModify(), "xrpl::SLEBase::insert : can modify");
view_.insert(sle_);
}
void
erase()
requires is_writable
{
XRPL_ASSERT(canModify(), "xrpl::SLEBase::erase : can modify");
view_.erase(sle_);
}
void
update()
requires is_writable
{
XRPL_ASSERT(canModify(), "xrpl::SLEBase::update : can modify");
view_.update(sle_);
}
void
newSLE()
requires is_writable
{
XRPL_ASSERT(!canModify(), "xrpl::SLEBase::newSLE : sle_ is not null");
sle_ = std::make_shared<SLE>(key_);
}
protected:
SLEBase() = delete;
/** Constructor for read-only context */
explicit SLEBase(std::shared_ptr<SLE const> sle, ReadView const& view)
requires(!is_writable)
: view_(view), sle_(std::move(sle))
{
}
/** Converting constructor: writable → read-only.
* Enables implicit conversion from SLEBase<ApplyView> to
* SLEBase<ReadView>, so functions taking ReadOnlySLE const& can
* accept WritableSLE.
*/
template <WritableView OtherViewT>
SLEBase(SLEBase<OtherViewT> const& other)
requires(!is_writable)
: view_(other.readView()), sle_(other.sle())
{
}
/** Constructor for writable context (from existing SLE) */
explicit SLEBase(std::shared_ptr<SLE> sle, ApplyView& view)
requires is_writable
: view_(view)
, key_(sle ? Keylet(sle->getType(), sle->key()) : Keylet(ltANY, uint256{}))
, sle_(std::move(sle))
{
}
/** Constructor for writable context (peek from view by keylet) */
explicit SLEBase(Keylet const& key, ApplyView& view)
requires is_writable
: view_(view), key_(key), sle_(view_.peek(key))
{
}
view_ref_type view_;
// Keylet is only meaningful for writable views, but we conditionally
// include it to avoid wasting space in read-only wrappers.
struct Empty
{
};
[[no_unique_address]]
std::conditional_t<is_writable, Keylet, Empty> key_{};
sle_ptr_type sle_;
};
// Backward-compatible aliases
using ReadOnlySLE = SLEBase<ReadView>;
using WritableSLE = SLEBase<ApplyView>;
} // namespace xrpl

View File

@@ -232,7 +232,7 @@ canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, Acc
// Direct send w/o fees:
// - Redeeming IOUs and/or sending sender's own IOUs.
// - Create trust line of needed.
// --> bCheckIssuer : normally require issuer to be involved.
// bCheckIssuer : normally require issuer to be involved.
// [[nodiscard]] // nodiscard commented out so DirectStep.cpp compiles.
/** Calls static rippleCreditIOU if saAmount represents Issue.

View File

@@ -4,10 +4,6 @@
namespace xrpl {
// Deprecated constant for backwards compatibility with pre-XRPFees amendment.
// This was the reference fee units used in the old fee calculation.
inline constexpr std::uint32_t FEE_UNITS_DEPRECATED = 10;
/** Reflects the fee settings for a particular ledger.
The fees are always the same for any transactions applied
@@ -15,25 +11,15 @@ inline constexpr std::uint32_t FEE_UNITS_DEPRECATED = 10;
*/
struct Fees
{
/** @brief Cost of a reference transaction in drops. */
XRPAmount base{0};
/** @brief Minimum XRP an account must hold to exist on the ledger. */
XRPAmount reserve{0};
/** @brief Additional XRP reserve required per owned ledger object. */
XRPAmount increment{0};
XRPAmount base{0}; // Reference tx cost (drops)
XRPAmount reserve{0}; // Reserve base (drops)
XRPAmount increment{0}; // Reserve increment (drops)
explicit Fees() = default;
Fees(Fees const&) = default;
Fees&
operator=(Fees const&) = default;
Fees(XRPAmount base_, XRPAmount reserve_, XRPAmount increment_)
: base(base_), reserve(reserve_), increment(increment_)
{
}
/** Returns the account reserve given the owner count, in drops.
The reserve is calculated as the reserve base plus

View File

@@ -72,8 +72,4 @@ deserializeHeader(Slice data, bool hasHash = false);
LedgerHeader
deserializePrefixedHeader(Slice data, bool hasHash = false);
/** Calculate the hash of a ledger header. */
uint256
calculateLedgerHash(LedgerHeader const& info);
} // namespace xrpl

View File

@@ -16,7 +16,6 @@
// Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order.
XRPL_FIX (Security3_1_3, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (PermissionedDomainInvariant, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (ExpiredNFTokenOfferRemoval, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FIX (BatchInnerSigs, Supported::no, VoteBehavior::DefaultNo)

View File

@@ -1,7 +1,6 @@
#pragma once
#include <xrpl/core/PerfLog.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/core/StartUpType.h>
#include <xrpl/rdb/DBInit.h>
#include <xrpl/rdb/SociDB.h>
@@ -95,7 +94,7 @@ public:
struct CheckpointerSetup
{
JobQueue* jobQueue;
std::reference_wrapper<ServiceRegistry> registry;
Logs* logs;
};
template <std::size_t N, std::size_t M>
@@ -130,7 +129,7 @@ public:
beast::Journal journal)
: DatabaseCon(setup, dbName, pragma, initSQL, journal)
{
setupCheckpointing(checkpointerSetup.jobQueue, checkpointerSetup.registry.get());
setupCheckpointing(checkpointerSetup.jobQueue, *checkpointerSetup.logs);
}
template <std::size_t N, std::size_t M>
@@ -155,7 +154,7 @@ public:
beast::Journal journal)
: DatabaseCon(dataDir, dbName, pragma, initSQL, journal)
{
setupCheckpointing(checkpointerSetup.jobQueue, checkpointerSetup.registry.get());
setupCheckpointing(checkpointerSetup.jobQueue, *checkpointerSetup.logs);
}
~DatabaseCon();
@@ -178,7 +177,7 @@ public:
private:
void
setupCheckpointing(JobQueue*, ServiceRegistry&);
setupCheckpointing(JobQueue*, Logs&);
template <std::size_t N, std::size_t M>
DatabaseCon(

View File

@@ -13,8 +13,8 @@
#pragma clang diagnostic ignored "-Wdeprecated"
#endif
#include <xrpl/basics/Log.h>
#include <xrpl/core/JobQueue.h>
#include <xrpl/core/ServiceRegistry.h>
#define SOCI_USE_BOOST
#include <soci/soci.h>
@@ -111,7 +111,7 @@ public:
and so must outlive them both.
*/
std::shared_ptr<Checkpointer>
makeCheckpointer(std::uintptr_t id, std::weak_ptr<soci::session>, JobQueue&, ServiceRegistry&);
makeCheckpointer(std::uintptr_t id, std::weak_ptr<soci::session>, JobQueue&, Logs&);
} // namespace xrpl

View File

@@ -2,6 +2,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/WrappedSink.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Permissions.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/tx/ApplyContext.h>
@@ -113,7 +114,8 @@ protected:
beast::WrappedSink sink_;
beast::Journal const j_;
AccountID const account_;
AccountID const accountID_;
WritableAccountRoot account_;
XRPAmount preFeeBalance_{}; // Balance before fees.
virtual ~Transactor() = default;

View File

@@ -1,6 +1,6 @@
#pragma once
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/TER.h>
@@ -92,7 +92,7 @@ public:
STPathSet const& spsPaths,
std::optional<uint256> const& domainID,
ServiceRegistry& registry,
Logs& l,
Input const* const pInputs = nullptr);
// The view we are currently working on

View File

@@ -475,4 +475,15 @@ loanMakePayment(
LoanPaymentType const paymentType,
beast::Journal j);
// LoanBroker-specific `adjustOwnerCount` function (temporary, while the Wrapped classes are WIP)
// Assert will check the type, so that we ensure it's not used by anything else
// Order of parameters is different from the old `adjustOwnerCount` function to avoid anything
// accidentally calling this with the wrong type.
void
adjustOwnerCount(
std::shared_ptr<SLE> const& sle,
ApplyView& view,
std::int32_t amount,
beast::Journal j);
} // namespace xrpl

View File

@@ -57,8 +57,8 @@ isVaultPseudoAccountFrozen(
return false; // zero MPToken won't block deletion of MPTokenIssuance
auto const issuer = mptIssuance->getAccountID(sfIssuer);
auto const mptIssuer = view.read(keylet::account(issuer));
if (mptIssuer == nullptr)
auto const mptIssuer = AccountRoot(issuer, view);
if (!mptIssuer.exists())
{
// LCOV_EXCL_START
UNREACHABLE("xrpl::isVaultPseudoAccountFrozen : null MPToken issuer");
@@ -357,17 +357,17 @@ canWithdraw(
ReadView const& view,
AccountID const& from,
AccountID const& to,
SLE::const_ref toSle,
ReadOnlyAccountRoot const& toWrapped,
STAmount const& amount,
bool hasDestinationTag)
{
if (auto const ret = checkDestinationAndTag(toSle, hasDestinationTag))
if (auto const ret = toWrapped.checkDestinationAndTag(hasDestinationTag))
return ret;
if (from == to)
return tesSUCCESS;
if (toSle->isFlag(lsfDepositAuth))
if (toWrapped->isFlag(lsfDepositAuth))
{
if (!view.exists(keylet::depositPreauth(to, from)))
return tecNO_PERMISSION;
@@ -384,9 +384,9 @@ canWithdraw(
STAmount const& amount,
bool hasDestinationTag)
{
auto const toSle = view.read(keylet::account(to));
auto const toWrapped = AccountRoot(to, view);
return canWithdraw(view, from, to, toSle, amount, hasDestinationTag);
return canWithdraw(view, from, to, toWrapped, amount, hasDestinationTag);
}
[[nodiscard]] TER
@@ -418,8 +418,8 @@ doWithdraw(
}
else
{
auto dstSle = view.read(keylet::account(dstAcct));
if (auto err = verifyDepositPreauth(tx, view, senderAcct, dstAcct, dstSle, j))
auto dst = AccountRoot(dstAcct, view);
if (auto err = verifyDepositPreauth(tx, view, senderAcct, dst, j))
return err;
}
@@ -433,7 +433,8 @@ doWithdraw(
j) < amount)
{
// LCOV_EXCL_START
JLOG(j.error()) << "doWithdraw: negative balance of broker cover assets.";
JLOG(j.error()) << "LoanBrokerCoverWithdraw: negative balance of "
"broker cover assets.";
return tefINTERNAL;
// LCOV_EXCL_STOP
}

View File

@@ -11,14 +11,13 @@
namespace xrpl {
template <typename ViewT>
bool
isGlobalFrozen(ReadView const& view, AccountID const& issuer)
AccountRoot<ViewT>::isGlobalFrozen() const
{
if (isXRP(issuer))
if (!this->exists())
return false;
if (auto const sle = view.read(keylet::account(issuer)))
return sle->isFlag(lsfGlobalFreeze);
return false;
return this->sle_->isFlag(lsfGlobalFreeze);
}
// An owner count cannot be negative. If adjustment would cause a negative
@@ -63,28 +62,28 @@ confineOwnerCount(
return adjusted;
}
template <typename ViewT>
XRPAmount
xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj, beast::Journal j)
AccountRoot<ViewT>::xrpLiquid(std::int32_t ownerCountAdj, beast::Journal j) const
{
auto const sle = view.read(keylet::account(id));
if (sle == nullptr)
if (!this->exists())
return beast::zero;
// Return balance minus reserve
std::uint32_t const ownerCount =
confineOwnerCount(view.ownerCountHook(id, sle->getFieldU32(sfOwnerCount)), ownerCountAdj);
std::uint32_t const ownerCount = confineOwnerCount(
this->readView().ownerCountHook(id_, this->sle_->getFieldU32(sfOwnerCount)), ownerCountAdj);
// Pseudo-accounts have no reserve requirement
auto const reserve =
isPseudoAccount(sle) ? XRPAmount{0} : view.fees().accountReserve(ownerCount);
this->isPseudoAccount() ? XRPAmount{0} : this->readView().fees().accountReserve(ownerCount);
auto const fullBalance = sle->getFieldAmount(sfBalance);
auto const fullBalance = this->sle_->getFieldAmount(sfBalance);
auto const balance = view.balanceHook(id, xrpAccount(), fullBalance);
auto const balance = this->readView().balanceHook(id_, xrpAccount(), fullBalance);
STAmount const amount = (balance < reserve) ? STAmount{0} : balance - reserve;
JLOG(j.trace()) << "accountHolds:" << " account=" << to_string(id)
JLOG(j.trace()) << "accountHolds:" << " account=" << to_string(id_)
<< " amount=" << amount.getFullText()
<< " fullBalance=" << fullBalance.getFullText()
<< " balance=" << balance.getFullText() << " reserve=" << reserve
@@ -93,33 +92,29 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
return amount.xrp();
}
template <typename ViewT>
Rate
transferRate(ReadView const& view, AccountID const& issuer)
AccountRoot<ViewT>::transferRate() const
{
auto const sle = view.read(keylet::account(issuer));
if (sle && sle->isFieldPresent(sfTransferRate))
return Rate{sle->getFieldU32(sfTransferRate)};
if (this->sle_ && this->sle_->isFieldPresent(sfTransferRate))
return Rate{this->sle_->getFieldU32(sfTransferRate)};
return parityRate;
}
template <typename ViewT>
void
adjustOwnerCount(
ApplyView& view,
std::shared_ptr<SLE> const& sle,
std::int32_t amount,
beast::Journal j)
AccountRoot<ViewT>::adjustOwnerCount(std::int32_t amount, beast::Journal j)
requires is_writable
{
if (!sle)
return;
XRPL_ASSERT(this->canModify(), "xrpl::adjustOwnerCount : can modify");
XRPL_ASSERT(amount, "xrpl::adjustOwnerCount : nonzero amount input");
std::uint32_t const current{sle->getFieldU32(sfOwnerCount)};
AccountID const id = (*sle)[sfAccount];
std::uint32_t const current{this->sle_->getFieldU32(sfOwnerCount)};
AccountID const id = (*this->sle_)[sfAccount];
std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j);
view.adjustOwnerCountHook(id, current, adjusted);
sle->at(sfOwnerCount) = adjusted;
view.update(sle);
this->applyView().adjustOwnerCountHook(id_, current, adjusted);
this->sle_->at(sfOwnerCount) = adjusted;
this->update();
}
AccountID
@@ -171,6 +166,22 @@ getPseudoAccountFields()
return pseudoFields;
}
template <typename ViewT>
[[nodiscard]] bool
AccountRoot<ViewT>::isPseudoAccount(std::set<SField const*> const& pseudoFieldFilter) const
{
auto const& fields = getPseudoAccountFields();
// Intentionally use defensive coding here because it's cheap and makes the
// semantics of true return value clean.
return this->sle_ && this->sle_->getType() == ltACCOUNT_ROOT &&
std::count_if(
fields.begin(), fields.end(), [this, &pseudoFieldFilter](SField const* sf) -> bool {
return this->sle_->isFieldPresent(*sf) &&
(pseudoFieldFilter.empty() || pseudoFieldFilter.contains(sf));
}) > 0;
}
[[nodiscard]] bool
isPseudoAccount(
std::shared_ptr<SLE const> sleAcct,
@@ -230,18 +241,23 @@ createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const
return account;
}
template <typename ViewT>
[[nodiscard]] TER
checkDestinationAndTag(SLE::const_ref toSle, bool hasDestinationTag)
AccountRoot<ViewT>::checkDestinationAndTag(bool hasDestinationTag) const
{
if (toSle == nullptr)
if (this->sle_ == nullptr)
return tecNO_DST;
// The tag is basically account-specific information we don't
// understand, but we can require someone to fill it in.
if (toSle->isFlag(lsfRequireDestTag) && !hasDestinationTag)
if (this->sle_->isFlag(lsfRequireDestTag) && !hasDestinationTag)
return tecDST_TAG_NEEDED; // Cannot send without a tag
return tesSUCCESS;
}
// Explicit template instantiations
template class AccountRoot<ReadView>;
template class AccountRoot<ApplyView>;
} // namespace xrpl

View File

@@ -51,8 +51,8 @@ deleteSLE(ApplyView& view, std::shared_ptr<SLE> const& sleCredential, beast::Jou
auto delSLE = [&view, &sleCredential, j](
AccountID const& account, SField const& node, bool isOwner) -> TER {
auto const sleAccount = view.peek(keylet::account(account));
if (!sleAccount)
WritableAccountRoot wrappedAccount(account, view);
if (!wrappedAccount)
{
// LCOV_EXCL_START
JLOG(j.fatal()) << "Internal error: can't retrieve Owner account.";
@@ -71,7 +71,7 @@ deleteSLE(ApplyView& view, std::shared_ptr<SLE> const& sleCredential, beast::Jou
}
if (isOwner)
adjustOwnerCount(view, sleAccount, -1, j);
wrappedAccount.adjustOwnerCount(-1, j);
return tesSUCCESS;
};
@@ -321,8 +321,7 @@ verifyDepositPreauth(
STTx const& tx,
ApplyView& view,
AccountID const& src,
AccountID const& dst,
std::shared_ptr<SLE const> const& sleDst,
ReadOnlyAccountRoot const& dst,
beast::Journal j)
{
// If depositPreauth is enabled, then an account that requires
@@ -336,15 +335,15 @@ verifyDepositPreauth(
if (credentialsPresent && credentials::removeExpired(view, tx.getFieldV256(sfCredentialIDs), j))
return tecEXPIRED;
if (sleDst && ((sleDst->getFlags() & lsfDepositAuth) != 0u))
if (dst.exists() && ((dst->getFlags() & lsfDepositAuth) != 0u))
{
if (src != dst)
{
if (!view.exists(keylet::depositPreauth(dst, src)))
if (!view.exists(keylet::depositPreauth(dst.id(), src)))
{
return !credentialsPresent ? tecNO_PERMISSION
: credentials::authorizedDepositPreauth(
view, tx.getFieldV256(sfCredentialIDs), dst);
view, tx.getFieldV256(sfCredentialIDs), dst.id());
}
}
}

View File

@@ -69,7 +69,7 @@ forEachItem(
for (auto const& key : sle->getFieldV256(sfIndexes))
f(view.read(keylet::child(key)));
auto const next = sle->getFieldU64(sfIndexNext);
if (next == 0u)
if (!next)
return;
pos = keylet::page(root, next);
}

View File

@@ -1,7 +1,6 @@
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
//
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -13,6 +12,21 @@
namespace xrpl {
// Forward declarations for functions that remain in View.h/cpp
bool
isVaultPseudoAccountFrozen(
ReadView const& view,
AccountID const& account,
MPTIssue const& mptShare,
int depth);
[[nodiscard]] TER
dirLink(
ApplyView& view,
AccountID const& owner,
std::shared_ptr<SLE>& object,
SF_UINT64 const& node = sfOwnerNode);
bool
isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue)
{
@@ -123,8 +137,8 @@ authorizeMPToken(
std::uint32_t flags,
std::optional<AccountID> holderID)
{
auto const sleAcct = view.peek(keylet::account(account));
if (!sleAcct)
WritableAccountRoot wrappedAcct(account, view);
if (!wrappedAcct)
return tecINTERNAL; // LCOV_EXCL_LINE
// If the account that submitted the tx is a holder
@@ -135,7 +149,7 @@ authorizeMPToken(
// When a holder wants to unauthorize/delete a MPT, the ledger must
// - delete mptokenKey from owner directory
// - delete the MPToken
if ((flags & tfMPTUnauthorize) != 0)
if ((flags & tfMPTUnauthorize) != 0u)
{
auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
auto const sleMpt = view.peek(mptokenKey);
@@ -146,7 +160,7 @@ authorizeMPToken(
keylet::ownerDir(account), (*sleMpt)[sfOwnerNode], sleMpt->key(), false))
return tecINTERNAL; // LCOV_EXCL_LINE
adjustOwnerCount(view, sleAcct, -1, journal);
wrappedAcct.adjustOwnerCount(-1, journal);
view.erase(sleMpt);
return tesSUCCESS;
@@ -161,7 +175,7 @@ authorizeMPToken(
// an account owns, in the case of MPTokens we only
// *enforce* a reserve if the user owns more than two
// items. This is similar to the reserve requirements of trust lines.
std::uint32_t const uOwnerCount = sleAcct->getFieldU32(sfOwnerCount);
std::uint32_t const uOwnerCount = wrappedAcct->getFieldU32(sfOwnerCount);
XRPAmount const reserveCreate(
(uOwnerCount < 2) ? XRPAmount(beast::zero)
: view.fees().accountReserve(uOwnerCount + 1));
@@ -191,7 +205,7 @@ authorizeMPToken(
view.insert(mptoken);
// Update owner count.
adjustOwnerCount(view, sleAcct, 1, journal);
wrappedAcct.adjustOwnerCount(1, journal);
return tesSUCCESS;
}
@@ -215,7 +229,7 @@ authorizeMPToken(
// Issuer wants to unauthorize the holder, unset lsfMPTAuthorized on
// their MPToken
if ((flags & tfMPTUnauthorize) != 0)
if ((flags & tfMPTUnauthorize) != 0u)
{
flagsOut &= ~lsfMPTAuthorized;
}
@@ -278,7 +292,7 @@ requireAuth(
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
auto const mptIssuer = sleIssuance->getAccountID(sfIssuer);
auto const mptIssuer = AccountRoot(sleIssuance->getAccountID(sfIssuer), view);
// issuer is always "authorized"
if (mptIssuer == account) // Issuer won't have MPToken
@@ -292,13 +306,12 @@ requireAuth(
return tecINTERNAL; // LCOV_EXCL_LINE
// requireAuth is recursive if the issuer is a vault pseudo-account
auto const sleIssuer = view.read(keylet::account(mptIssuer));
if (!sleIssuer)
if (!mptIssuer.exists())
return tefINTERNAL; // LCOV_EXCL_LINE
if (sleIssuer->isFieldPresent(sfVaultID))
if (mptIssuer->isFieldPresent(sfVaultID))
{
auto const sleVault = view.read(keylet::vault(sleIssuer->getFieldH256(sfVaultID)));
auto const sleVault = view.read(keylet::vault(mptIssuer->getFieldH256(sfVaultID)));
if (!sleVault)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -476,7 +489,7 @@ canTransfer(
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
if (!sleIssuance->isFlag(lsfMPTCanTransfer))
if ((sleIssuance->getFieldU32(sfFlags) & lsfMPTCanTransfer) == 0u)
{
if (from != (*sleIssuance)[sfIssuer] && to != (*sleIssuance)[sfIssuer])
return TER{tecNO_AUTH};

View File

@@ -48,7 +48,8 @@ offerDelete(ApplyView& view, std::shared_ptr<SLE> const& sle, beast::Journal j)
}
}
adjustOwnerCount(view, view.peek(keylet::account(owner)), -1, j);
WritableAccountRoot wrappedOwner(owner, view);
wrappedOwner.adjustOwnerCount(-1, j);
view.erase(sle);

View File

@@ -107,14 +107,14 @@ isFrozen(
{
if (isXRP(currency))
return false;
auto sle = view.read(keylet::account(issuer));
if (sle && sle->isFlag(lsfGlobalFreeze))
auto const issuerRoot = AccountRoot(issuer, view);
if (issuerRoot.exists() && issuerRoot->isFlag(lsfGlobalFreeze))
return true;
if (issuer != account)
{
// Check if the issuer froze the line
sle = view.read(keylet::line(account, issuer, currency));
if (sle && sle->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
auto const sleLine = view.read(keylet::line(account, issuer, currency));
if (sleLine && sleLine->isFlag((issuer > account) ? lsfHighFreeze : lsfLowFreeze))
return true;
}
return false;
@@ -158,16 +158,16 @@ trustCreate(
bool const bSrcHigh,
AccountID const& uSrcAccountID,
AccountID const& uDstAccountID,
uint256 const& uIndex, // --> ripple state entry
SLE::ref sleAccount, // --> the account being set.
bool const bAuth, // --> authorize account.
bool const bNoRipple, // --> others cannot ripple through
bool const bFreeze, // --> funds cannot leave
bool bDeepFreeze, // --> can neither receive nor send funds
STAmount const& saBalance, // --> balance of account being set.
// Issuer should be noAccount()
STAmount const& saLimit, // --> limit for account being set.
// Issuer should be the account being set.
uint256 const& uIndex, // ripple state entry
WritableAccountRoot& wrappedAcct, // the account being set.
bool const bAuth, // authorize account.
bool const bNoRipple, // others cannot ripple through
bool const bFreeze, // funds cannot leave
bool bDeepFreeze, // can neither receive nor send funds
STAmount const& saBalance, // balance of account being set.
// Issuer should be noAccount()
STAmount const& saLimit, // limit for account being set.
// Issuer should be the account being set.
std::uint32_t uQualityIn,
std::uint32_t uQualityOut,
beast::Journal j)
@@ -204,15 +204,15 @@ trustCreate(
bool const bSetDst = saLimit.getIssuer() == uDstAccountID;
bool const bSetHigh = bSrcHigh ^ bSetDst;
XRPL_ASSERT(sleAccount, "xrpl::trustCreate : non-null SLE");
if (!sleAccount)
XRPL_ASSERT(wrappedAcct, "xrpl::trustCreate : non-null SLE");
if (!wrappedAcct)
return tefINTERNAL; // LCOV_EXCL_LINE
XRPL_ASSERT(
sleAccount->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
wrappedAcct->getAccountID(sfAccount) == (bSetHigh ? uHighAccountID : uLowAccountID),
"xrpl::trustCreate : matching account ID");
auto const slePeer = view.peek(keylet::account(bSetHigh ? uLowAccountID : uHighAccountID));
if (!slePeer)
auto const peer = AccountRoot(bSetHigh ? uLowAccountID : uHighAccountID, view);
if (!peer.exists())
return tecNO_TARGET;
// Remember deletion hints.
@@ -249,14 +249,14 @@ trustCreate(
uFlags |= (bSetHigh ? lsfHighDeepFreeze : lsfLowDeepFreeze);
}
if ((slePeer->getFlags() & lsfDefaultRipple) == 0)
if ((peer->getFlags() & lsfDefaultRipple) == 0)
{
// The other side's default is no rippling
uFlags |= (bSetHigh ? lsfLowNoRipple : lsfHighNoRipple);
}
sleRippleState->setFieldU32(sfFlags, uFlags);
adjustOwnerCount(view, sleAccount, 1, j);
wrappedAcct.adjustOwnerCount(1, j);
// ONLY: Create ripple balance.
sleRippleState->setFieldAmount(sfBalance, bSetHigh ? -saBalance : saBalance);
@@ -318,8 +318,8 @@ updateTrustLine(
return false;
std::uint32_t const flags(state->getFieldU32(sfFlags));
auto sle = view.peek(keylet::account(sender));
if (!sle)
WritableAccountRoot wrappedAcct(sender, view);
if (!wrappedAcct)
return false;
// YYY Could skip this if rippling in reverse.
@@ -330,7 +330,7 @@ updateTrustLine(
&& ((flags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) != 0u)
// Sender reserve is set.
&& static_cast<bool>(flags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
static_cast<bool>(sle->getFlags() & lsfDefaultRipple) &&
static_cast<bool>(wrappedAcct->getFlags() & lsfDefaultRipple) &&
((flags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) == 0u) &&
!state->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit)
// Sender trust limit is 0.
@@ -341,7 +341,7 @@ updateTrustLine(
{
// VFALCO Where is the line being deleted?
// Clear the reserve of the sender, possibly delete the line!
adjustOwnerCount(view, sle, -1, j);
wrappedAcct.adjustOwnerCount(-1, j);
// Clear reserve flag.
state->setFieldU32(sfFlags, flags & (!bSenderHigh ? ~lsfLowReserve : ~lsfHighReserve));
@@ -424,7 +424,7 @@ issueIOU(
final_balance.setIssuer(noAccount());
auto const receiverAccount = view.peek(keylet::account(account));
WritableAccountRoot receiverAccount(account, view);
if (!receiverAccount)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -538,8 +538,8 @@ requireAuth(ReadView const& view, Issue const& issue, AccountID const& account,
// If this is a weak or legacy check, or if the account has a line, fail if
// auth is required and not set on the line
if (auto const issuerAccount = view.read(keylet::account(issue.account));
issuerAccount && (((*issuerAccount)[sfFlags] & lsfRequireAuth) != 0u))
auto const issuerAccount = AccountRoot(issue.account, view);
if (issuerAccount.exists() && (((*issuerAccount)[sfFlags] & lsfRequireAuth) != 0u))
{
if (trustLine)
{
@@ -563,8 +563,8 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc
auto const& issuerId = issue.getIssuer();
if (issuerId == from || issuerId == to)
return tesSUCCESS;
auto const sleIssuer = view.read(keylet::account(issuerId));
if (sleIssuer == nullptr)
auto const issuer = AccountRoot(issuerId, view);
if (!issuer.exists())
return tefINTERNAL; // LCOV_EXCL_LINE
auto const isRippleDisabled = [&](AccountID account) -> bool {
@@ -576,7 +576,7 @@ canTransfer(ReadView const& view, Issue const& issue, AccountID const& from, Acc
bool const issuerHigh = issuerId > account;
return line->isFlag(issuerHigh ? lsfHighNoRipple : lsfLowNoRipple);
}
return !sleIssuer->isFlag(lsfDefaultRipple);
return !issuer->isFlag(lsfDefaultRipple);
};
// Fail if rippling disabled on both trust lines
@@ -606,25 +606,26 @@ addEmptyHolding(
auto const& issuerId = issue.getIssuer();
auto const& currency = issue.currency;
if (isGlobalFrozen(view, issuerId))
WritableAccountRoot wrappedIssuer(issuerId, view);
if (wrappedIssuer.isGlobalFrozen())
return tecFROZEN; // LCOV_EXCL_LINE
auto const& srcId = issuerId;
auto const& dstId = accountID;
auto const high = srcId > dstId;
auto const index = keylet::line(srcId, dstId, currency);
auto const sleSrc = view.peek(keylet::account(srcId));
auto const sleDst = view.peek(keylet::account(dstId));
if (!sleDst || !sleSrc)
WritableAccountRoot wrappedSrc(srcId, view);
WritableAccountRoot wrappedDst(dstId, view);
if (!wrappedDst || !wrappedSrc)
return tefINTERNAL; // LCOV_EXCL_LINE
if (!sleSrc->isFlag(lsfDefaultRipple))
if (!wrappedSrc->isFlag(lsfDefaultRipple))
return tecINTERNAL; // LCOV_EXCL_LINE
// If the line already exists, don't create it again.
if (view.read(index))
return tecDUPLICATE;
// Can the account cover the trust line reserve ?
std::uint32_t const ownerCount = sleDst->at(sfOwnerCount);
std::uint32_t const ownerCount = wrappedDst->at(sfOwnerCount);
if (priorBalance < view.fees().accountReserve(ownerCount + 1))
return tecNO_LINE_INSUF_RESERVE;
@@ -634,7 +635,7 @@ addEmptyHolding(
srcId,
dstId,
index.key,
sleDst,
wrappedDst,
/*bAuth=*/false,
/*bNoRipple=*/true,
/*bFreeze=*/false,
@@ -655,11 +656,11 @@ removeEmptyHolding(
{
if (issue.native())
{
auto const sle = view.read(keylet::account(accountID));
if (!sle)
auto const account = AccountRoot(accountID, view);
if (!account.exists())
return tecINTERNAL; // LCOV_EXCL_LINE
auto const balance = sle->getFieldAmount(sfBalance);
auto const balance = account->getFieldAmount(sfBalance);
if (balance.xrp() != 0)
return tecHAS_OBLIGATIONS;
@@ -680,11 +681,11 @@ removeEmptyHolding(
if (line->isFlag(lsfLowReserve))
{
// Clear reserve for low account.
auto sleLowAccount = view.peek(keylet::account(line->at(sfLowLimit)->getIssuer()));
if (!sleLowAccount)
WritableAccountRoot wrappedLow(line->at(sfLowLimit)->getIssuer(), view);
if (!wrappedLow)
return tecINTERNAL; // LCOV_EXCL_LINE
adjustOwnerCount(view, sleLowAccount, -1, journal);
wrappedLow.adjustOwnerCount(-1, journal);
// It's not really necessary to clear the reserve flag, since the line
// is about to be deleted, but this will make the metadata reflect an
// accurate state at the time of deletion.
@@ -694,11 +695,11 @@ removeEmptyHolding(
if (line->isFlag(lsfHighReserve))
{
// Clear reserve for high account.
auto sleHighAccount = view.peek(keylet::account(line->at(sfHighLimit)->getIssuer()));
if (!sleHighAccount)
WritableAccountRoot wrappedHigh(line->at(sfHighLimit)->getIssuer(), view);
if (!wrappedHigh)
return tecINTERNAL; // LCOV_EXCL_LINE
adjustOwnerCount(view, sleHighAccount, -1, journal);
wrappedHigh.adjustOwnerCount(-1, journal);
// It's not really necessary to clear the reserve flag, since the line
// is about to be deleted, but this will make the metadata reflect an
// accurate state at the time of deletion.
@@ -722,13 +723,13 @@ deleteAMMTrustLine(
auto const& [low, high] = std::minmax(
sleState->getFieldAmount(sfLowLimit).getIssuer(),
sleState->getFieldAmount(sfHighLimit).getIssuer());
auto sleLow = view.peek(keylet::account(low));
auto sleHigh = view.peek(keylet::account(high));
if (!sleLow || !sleHigh)
WritableAccountRoot wrappedLow(low, view);
WritableAccountRoot wrappedHigh(high, view);
if (!wrappedLow || !wrappedHigh)
return tecINTERNAL; // LCOV_EXCL_LINE
bool const ammLow = sleLow->isFieldPresent(sfAMMID);
bool const ammHigh = sleHigh->isFieldPresent(sfAMMID);
bool const ammLow = wrappedLow->isFieldPresent(sfAMMID);
bool const ammHigh = wrappedHigh->isFieldPresent(sfAMMID);
// can't both be AMM
if (ammLow && ammHigh)
@@ -752,7 +753,8 @@ deleteAMMTrustLine(
if ((sleState->getFlags() & uFlags) == 0u)
return tecINTERNAL; // LCOV_EXCL_LINE
adjustOwnerCount(view, !ammLow ? sleLow : sleHigh, -1, j);
WritableAccountRoot wrappedHolder = !ammLow ? wrappedLow : wrappedHigh;
wrappedHolder.adjustOwnerCount(-1, j);
return tesSUCCESS;
}

View File

@@ -39,7 +39,8 @@ isGlobalFrozen(ReadView const& view, Asset const& asset)
[&]<ValidIssueType TIss>(TIss const& issue) {
if constexpr (std::is_same_v<TIss, Issue>)
{
return isGlobalFrozen(view, issue.getIssuer());
AccountRoot issuer(issue.getIssuer(), view);
return issuer.isGlobalFrozen();
}
else
{
@@ -180,14 +181,14 @@ getLineIfUsable(
// we need to check if the associated assets have been frozen
if (view.rules().enabled(fixFrozenLPTokenTransfer))
{
auto const sleIssuer = view.read(keylet::account(issuer));
if (!sleIssuer)
auto const issuerRoot = AccountRoot(issuer, view);
if (!issuerRoot.exists())
{
return nullptr; // LCOV_EXCL_LINE
}
if (sleIssuer->isFieldPresent(sfAMMID))
if (issuerRoot->isFieldPresent(sfAMMID))
{
auto const sleAmm = view.read(keylet::amm((*sleIssuer)[sfAMMID]));
auto const sleAmm = view.read(keylet::amm((*issuerRoot)[sfAMMID]));
if (!sleAmm ||
isLPTokenFrozen(
@@ -256,7 +257,8 @@ accountHolds(
STAmount amount;
if (isXRP(currency))
{
return {xrpLiquid(view, account, 0, j)};
AccountRoot accountRoot(account, view);
return {accountRoot.xrpLiquid(0, j)};
}
bool const returnSpendable = (includeFullBalance == shFULL_BALANCE);
@@ -402,7 +404,8 @@ transferRate(ReadView const& view, STAmount const& amount)
[&]<ValidIssueType TIss>(TIss const& issue) {
if constexpr (std::is_same_v<TIss, Issue>)
{
return transferRate(view, issue.getIssuer());
AccountRoot issuer(issue.getIssuer(), view);
return issuer.transferRate();
}
else
{
@@ -425,12 +428,13 @@ canAddHolding(ReadView const& view, Issue const& issue)
{
return tesSUCCESS; // No special checks for XRP
}
auto const issuer = AccountRoot(issue.getIssuer(), view);
auto const issuer = view.read(keylet::account(issue.getIssuer()));
if (!issuer)
if (!issuer.exists())
{
return terNO_ACCOUNT;
}
if (!issuer->isFlag(lsfDefaultRipple))
{
return terNO_RIPPLE;
@@ -511,7 +515,7 @@ canTransfer(ReadView const& view, Asset const& asset, AccountID const& from, Acc
// Direct send w/o fees:
// - Redeeming IOUs and/or sending sender's own IOUs.
// - Create trust line if needed.
// --> bCheckIssuer : normally require issuer to be involved.
// bCheckIssuer : normally require issuer to be involved.
static TER
rippleCreditIOU(
ApplyView& view,
@@ -573,8 +577,7 @@ rippleCreditIOU(
&& ((uFlags & (!bSenderHigh ? lsfLowReserve : lsfHighReserve)) != 0u)
// Sender reserve is set.
&& static_cast<bool>(uFlags & (!bSenderHigh ? lsfLowNoRipple : lsfHighNoRipple)) !=
static_cast<bool>(
view.read(keylet::account(uSenderID))->getFlags() & lsfDefaultRipple) &&
static_cast<bool>(AccountRoot(uSenderID, view)->getFlags() & lsfDefaultRipple) &&
((uFlags & (!bSenderHigh ? lsfLowFreeze : lsfHighFreeze)) == 0u) &&
!sleRippleState->getFieldAmount(!bSenderHigh ? sfLowLimit : sfHighLimit)
// Sender trust limit is 0.
@@ -585,7 +588,8 @@ rippleCreditIOU(
// Sender quality out is 0.
{
// Clear the reserve of the sender, possibly delete the line!
adjustOwnerCount(view, view.peek(keylet::account(uSenderID)), -1, j);
WritableAccountRoot wrappedSender(uSenderID, view);
wrappedSender.adjustOwnerCount(-1, j);
// Clear reserve flag.
sleRippleState->setFieldU32(
@@ -628,11 +632,11 @@ rippleCreditIOU(
<< to_string(uSenderID) << " -> " << to_string(uReceiverID) << " : "
<< saAmount.getFullText();
auto const sleAccount = view.peek(keylet::account(uReceiverID));
if (!sleAccount)
WritableAccountRoot wrappedAccount(uReceiverID, view);
if (!wrappedAccount)
return tefINTERNAL; // LCOV_EXCL_LINE
bool const noRipple = (sleAccount->getFlags() & lsfDefaultRipple) == 0;
bool const noRipple = (wrappedAccount->getFlags() & lsfDefaultRipple) == 0;
return trustCreate(
view,
@@ -640,7 +644,7 @@ rippleCreditIOU(
uSenderID,
uReceiverID,
index.key,
sleAccount,
wrappedAccount,
false,
noRipple,
false,
@@ -653,7 +657,7 @@ rippleCreditIOU(
}
// Send regardless of limits.
// --> saAmount: Amount/currency/issuer to deliver to receiver.
// saAmount: Amount/currency/issuer to deliver to receiver.
// <-- saActual: Amount actually cost. Sender pays fees.
static TER
rippleSendIOU(
@@ -686,8 +690,10 @@ rippleSendIOU(
// Calculate the amount to transfer accounting
// for any transfer fees if the fee is not waived:
saActual = (waiveFee == WaiveTransferFee::Yes) ? saAmount
: multiply(saAmount, transferRate(view, issuer));
WritableAccountRoot wrappedIssuer(issuer, view);
saActual = (waiveFee == WaiveTransferFee::Yes)
? saAmount
: multiply(saAmount, wrappedIssuer.transferRate());
JLOG(j.debug()) << "rippleSendIOU> " << to_string(uSenderID) << " - > "
<< to_string(uReceiverID) << " : deliver=" << saAmount.getFullText()
@@ -702,7 +708,7 @@ rippleSendIOU(
}
// Send regardless of limits.
// --> receivers: Amount/currency/issuer to deliver to receivers.
// receivers: Amount/currency/issuer to deliver to receivers.
// <-- saActual: Amount actually cost to sender. Sender pays fees.
static TER
rippleSendMultiIOU(
@@ -752,9 +758,10 @@ rippleSendMultiIOU(
// Calculate the amount to transfer accounting
// for any transfer fees if the fee is not waived:
WritableAccountRoot wrappedIssuer(issuer, view);
STAmount actualSend = (waiveFee == WaiveTransferFee::Yes)
? amount
: multiply(amount, transferRate(view, issuer));
: multiply(amount, wrappedIssuer.transferRate());
actual += actualSend;
takeFromSender += actualSend;
@@ -1362,15 +1369,15 @@ transferXRP(
XRPL_ASSERT(from != to, "xrpl::transferXRP : sender is not receiver");
XRPL_ASSERT(amount.native(), "xrpl::transferXRP : amount is XRP");
SLE::pointer const sender = view.peek(keylet::account(from));
SLE::pointer const receiver = view.peek(keylet::account(to));
if (!sender || !receiver)
WritableAccountRoot acctSender(from, view);
WritableAccountRoot acctReceiver(to, view);
if (!acctSender || !acctReceiver)
return tefINTERNAL; // LCOV_EXCL_LINE
JLOG(j.trace()) << "transferXRP: " << to_string(from) << " -> " << to_string(to)
<< ") : " << amount.getFullText();
if (sender->getFieldAmount(sfBalance) < amount)
if (acctSender->getFieldAmount(sfBalance) < amount)
{
// VFALCO Its unfortunate we have to keep
// mutating these TER everywhere
@@ -1381,11 +1388,11 @@ transferXRP(
}
// Decrement XRP balance.
sender->setFieldAmount(sfBalance, sender->getFieldAmount(sfBalance) - amount);
view.update(sender);
acctSender->setFieldAmount(sfBalance, acctSender->getFieldAmount(sfBalance) - amount);
acctSender.update();
receiver->setFieldAmount(sfBalance, receiver->getFieldAmount(sfBalance) + amount);
view.update(receiver);
acctReceiver->setFieldAmount(sfBalance, acctReceiver->getFieldAmount(sfBalance) + amount);
acctReceiver.update();
return tesSUCCESS;
}

View File

@@ -92,7 +92,7 @@ sharesToAssetsWithdraw(
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares)
{
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsWithdraw : non-negative shares");
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares");
XRPL_ASSERT(
shares.asset() == vault->at(sfShareMPTID),
"xrpl::sharesToAssetsWithdraw : shares and vault match");

View File

@@ -1,9 +1,7 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/protocol/HashPrefix.h>
#include <xrpl/protocol/LedgerHeader.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/protocol/digest.h>
namespace xrpl {
@@ -53,21 +51,4 @@ deserializePrefixedHeader(Slice data, bool hasHash)
return deserializeHeader(data + 4, hasHash);
}
uint256
calculateLedgerHash(LedgerHeader const& info)
{
// VFALCO This has to match addRaw in View.h.
return sha512Half(
HashPrefix::ledgerMaster,
std::uint32_t(info.seq),
std::uint64_t(info.drops.drops()),
info.parentHash,
info.txHash,
info.accountHash,
std::uint32_t(info.parentCloseTime.time_since_epoch().count()),
std::uint32_t(info.closeTime.time_since_epoch().count()),
std::uint8_t(info.closeTimeResolution.count()),
std::uint8_t(info.closeFlags));
}
} // namespace xrpl

View File

@@ -1,5 +1,5 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/contract.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/rdb/DatabaseCon.h>
#include <xrpl/rdb/SociDB.h>
@@ -40,14 +40,11 @@ public:
}
std::shared_ptr<Checkpointer>
create(
std::shared_ptr<soci::session> const& session,
JobQueue& jobQueue,
ServiceRegistry& registry)
create(std::shared_ptr<soci::session> const& session, JobQueue& jobQueue, Logs& logs)
{
std::lock_guard lock{mutex_};
auto const id = nextId_++;
auto const r = makeCheckpointer(id, session, jobQueue, registry);
auto const r = makeCheckpointer(id, session, jobQueue, logs);
checkpointers_[id] = r;
return r;
}
@@ -85,11 +82,11 @@ DatabaseCon::~DatabaseCon()
std::unique_ptr<std::vector<std::string> const> DatabaseCon::Setup::globalPragma;
void
DatabaseCon::setupCheckpointing(JobQueue* q, ServiceRegistry& registry)
DatabaseCon::setupCheckpointing(JobQueue* q, Logs& l)
{
if (q == nullptr)
Throw<std::logic_error>("No JobQueue");
checkpointer_ = checkpointers.create(session_, *q, registry);
checkpointer_ = checkpointers.create(session_, *q, l);
}
} // namespace xrpl

View File

@@ -187,11 +187,8 @@ public:
std::uintptr_t id,
std::weak_ptr<soci::session> session,
JobQueue& q,
ServiceRegistry& registry)
: id_(id)
, session_(std::move(session))
, jobQueue_(q)
, j_(registry.getJournal("WALCheckpointer"))
Logs& logs)
: id_(id), session_(std::move(session)), jobQueue_(q), j_(logs.journal("WALCheckpointer"))
{
if (auto [conn, keepAlive] = getConnection(); conn)
{
@@ -310,9 +307,9 @@ makeCheckpointer(
std::uintptr_t id,
std::weak_ptr<soci::session> session,
JobQueue& queue,
ServiceRegistry& registry)
Logs& logs)
{
return std::make_shared<WALCheckpointer>(id, std::move(session), queue, registry);
return std::make_shared<WALCheckpointer>(id, std::move(session), queue, logs);
}
} // namespace xrpl

View File

@@ -12,6 +12,8 @@ namespace xrpl {
Expected<std::vector<SignerEntries::SignerEntry>, NotTEC>
SignerEntries::deserialize(STObject const& obj, beast::Journal journal, std::string_view annotation)
{
std::pair<std::vector<SignerEntry>, NotTEC> s;
if (!obj.isFieldPresent(sfSignerEntries))
{
JLOG(journal.trace()) << "Malformed " << annotation << ": Need signer entry array.";

View File

@@ -1,3 +1,4 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/contract.h>
#include <xrpl/core/NetworkIDService.h>
#include <xrpl/json/to_string.h>
@@ -231,7 +232,8 @@ Transactor::Transactor(ApplyContext& ctx)
: ctx_(ctx)
, sink_(ctx.journal, to_short_string(ctx.tx.getTransactionID()) + " ")
, j_(sink_)
, account_(ctx.tx.getAccountID(sfAccount))
, accountID_(ctx.tx.getAccountID(sfAccount))
, account_(accountID_, ctx.view())
{
}
@@ -301,7 +303,7 @@ Transactor::calculateOwnerReserveFee(ReadView const& view, STTx const& tx)
// need to rethink charging an owner reserve as a transaction fee.
// TODO: This function is static, and I don't want to add more parameters.
// When it is finally refactored to be in a context that has access to the
// Application, include "app().getOverlay().networkID() > 2 ||" in the
// Application, include "app().overlay().networkID() > 2 ||" in the
// condition.
XRPL_ASSERT(
view.fees().increment > view.fees().base * 100,
@@ -357,11 +359,11 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
return tesSUCCESS;
auto const id = ctx.tx.getFeePayer();
auto const sle = ctx.view.read(keylet::account(id));
if (!sle)
AccountRoot const acctRoot(id, ctx.view);
if (!acctRoot)
return terNO_ACCOUNT;
auto const balance = (*sle)[sfBalance].xrp();
auto const balance = (*acctRoot)[sfBalance].xrp();
if (balance < feePaid)
{
@@ -386,17 +388,15 @@ Transactor::payFee()
auto const feePaid = ctx_.tx[sfFee].xrp();
auto const feePayer = ctx_.tx.getFeePayer();
auto const sle = view().peek(keylet::account(feePayer));
if (!sle)
WritableAccountRoot payerAcct(feePayer, view());
if (!payerAcct)
return tefINTERNAL; // LCOV_EXCL_LINE
// Deduct the fee, so it's not available during the transaction.
// Will only write the account back if the transaction succeeds.
sle->setFieldAmount(sfBalance, sle->getFieldAmount(sfBalance) - feePaid);
if (feePayer != account_)
view().update(sle); // done in `apply()` for the account
// VFALCO Should we call view().rawDestroyXRP() here as well?
payerAcct->setFieldAmount(sfBalance, payerAcct->getFieldAmount(sfBalance) - feePaid);
if (feePayer != accountID_)
payerAcct.update(); // done in `apply()` for the account
return tesSUCCESS;
}
@@ -405,9 +405,9 @@ Transactor::checkSeqProxy(ReadView const& view, STTx const& tx, beast::Journal j
{
auto const id = tx.getAccountID(sfAccount);
auto const sle = view.read(keylet::account(id));
AccountRoot const acctRoot(id, view);
if (!sle)
if (!acctRoot)
{
JLOG(j.trace()) << "applyTransaction: delay: source account does not exist "
<< toBase58(id);
@@ -415,7 +415,7 @@ Transactor::checkSeqProxy(ReadView const& view, STTx const& tx, beast::Journal j
}
SeqProxy const t_seqProx = tx.getSeqProxy();
SeqProxy const a_seq = SeqProxy::sequence((*sle)[sfSequence]);
SeqProxy const a_seq = SeqProxy::sequence((*acctRoot)[sfSequence]);
if (t_seqProx.isSeq())
{
@@ -470,9 +470,9 @@ Transactor::checkPriorTxAndLastLedger(PreclaimContext const& ctx)
{
auto const id = ctx.tx.getAccountID(sfAccount);
auto const sle = ctx.view.read(keylet::account(id));
AccountRoot const acctRoot(id, ctx.view);
if (!sle)
if (!acctRoot)
{
JLOG(ctx.j.trace()) << "applyTransaction: delay: source account does not exist "
<< toBase58(id);
@@ -480,7 +480,7 @@ Transactor::checkPriorTxAndLastLedger(PreclaimContext const& ctx)
}
if (ctx.tx.isFieldPresent(sfAccountTxnID) &&
(sle->getFieldH256(sfAccountTxnID) != ctx.tx.getFieldH256(sfAccountTxnID)))
(acctRoot->getFieldH256(sfAccountTxnID) != ctx.tx.getFieldH256(sfAccountTxnID)))
return tefWRONG_PRIOR;
if (ctx.tx.isFieldPresent(sfLastLedgerSequence) &&
@@ -506,7 +506,7 @@ Transactor::consumeSeqProxy(SLE::pointer const& sleAccount)
sleAccount->setFieldU32(sfSequence, seqProx.value() + 1);
return tesSUCCESS;
}
return ticketDelete(view(), account_, getTicketIndex(account_, seqProx), j_);
return ticketDelete(view(), accountID_, getTicketIndex(accountID_, seqProx), j_);
}
// Remove a single Ticket from the ledger.
@@ -539,8 +539,8 @@ Transactor::ticketDelete(
// Update the account root's TicketCount. If the ticket count drops to
// zero remove the (optional) field.
auto sleAccount = view.peek(keylet::account(account));
if (!sleAccount)
WritableAccountRoot wrappedAcct(account, view);
if (!wrappedAcct)
{
// LCOV_EXCL_START
JLOG(j.fatal()) << "Could not find Ticket owner account root.";
@@ -548,11 +548,11 @@ Transactor::ticketDelete(
// LCOV_EXCL_STOP
}
if (auto ticketCount = (*sleAccount)[~sfTicketCount])
if (auto ticketCount = (*wrappedAcct)[~sfTicketCount])
{
if (*ticketCount == 1)
{
sleAccount->makeFieldAbsent(sfTicketCount);
wrappedAcct->makeFieldAbsent(sfTicketCount);
}
else
{
@@ -568,7 +568,7 @@ Transactor::ticketDelete(
}
// Update the Ticket owner's reserve.
adjustOwnerCount(view, sleAccount, -1, j);
wrappedAcct.adjustOwnerCount(-1, j);
// Remove Ticket from ledger.
view.erase(sleTicket);
@@ -579,7 +579,7 @@ Transactor::ticketDelete(
void
Transactor::preCompute()
{
XRPL_ASSERT(account_ != beast::zero, "xrpl::Transactor::preCompute : nonzero account");
XRPL_ASSERT(accountID_ != beast::zero, "xrpl::Transactor::preCompute : nonzero account");
}
TER
@@ -589,19 +589,19 @@ Transactor::apply()
// If the transactor requires a valid account and the transaction doesn't
// list one, preflight will have already a flagged a failure.
auto const sle = view().peek(keylet::account(account_));
WritableAccountRoot acct(accountID_, view());
// sle must exist except for transactions
// acct must exist except for transactions
// that allow zero account.
XRPL_ASSERT(
sle != nullptr || account_ == beast::zero,
acct.exists() || accountID_ == beast::zero,
"xrpl::Transactor::apply : non-null SLE or zero account");
if (sle)
if (acct)
{
preFeeBalance_ = STAmount{(*sle)[sfBalance]}.xrp();
preFeeBalance_ = STAmount{(*acct)[sfBalance]}.xrp();
TER result = consumeSeqProxy(sle);
TER result = consumeSeqProxy(acct.mutableSle());
if (!isTesSuccess(result))
return result;
@@ -609,10 +609,10 @@ Transactor::apply()
if (!isTesSuccess(result))
return result;
if (sle->isFieldPresent(sfAccountTxnID))
sle->setFieldH256(sfAccountTxnID, ctx_.tx.getTransactionID());
if (acct->isFieldPresent(sfAccountTxnID))
acct->setFieldH256(sfAccountTxnID, ctx_.tx.getTransactionID());
view().update(sle);
acct.update();
}
return doApply();
@@ -627,10 +627,9 @@ Transactor::checkSign(
STObject const& sigObject,
beast::Journal const j)
{
AccountRoot const acctSign(idAccount, view);
{
auto const sle = view.read(keylet::account(idAccount));
if (view.rules().enabled(featureLendingProtocol) && isPseudoAccount(sle))
if (view.rules().enabled(featureLendingProtocol) && acctSign.isPseudoAccount())
{
// Pseudo-accounts can't sign transactions. This check is gated on
// the Lending Protocol amendment because that's the project it was
@@ -676,12 +675,12 @@ Transactor::checkSign(
}
// Look up the account.
auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
auto const sleAccount = view.read(keylet::account(idAccount));
if (!sleAccount)
auto const idSigner =
pkSigner.empty() ? idAccount : calcAccountID(PublicKey(makeSlice(pkSigner)));
if (!acctSign)
return terNO_ACCOUNT;
return checkSingleSign(view, idSigner, idAccount, sleAccount, j);
return checkSingleSign(view, idSigner, idAccount, acctSign.sle(), j);
}
NotTEC
@@ -716,11 +715,11 @@ Transactor::checkBatchSign(PreclaimContext const& ctx)
// LCOV_EXCL_STOP
auto const idSigner = calcAccountID(PublicKey(makeSlice(pkSigner)));
auto const sleAccount = ctx.view.read(keylet::account(idAccount));
AccountRoot const acctRoot(idAccount, ctx.view);
// A batch can include transactions from an un-created account ONLY
// when the account master key is the signer
if (!sleAccount)
if (!acctRoot)
{
if (idAccount != idSigner)
return tefBAD_AUTH;
@@ -728,7 +727,7 @@ Transactor::checkBatchSign(PreclaimContext const& ctx)
return tesSUCCESS;
}
if (ret = checkSingleSign(ctx.view, idSigner, idAccount, sleAccount, ctx.j);
if (ret = checkSingleSign(ctx.view, idSigner, idAccount, acctRoot.sle(), ctx.j);
!isTesSuccess(ret))
return ret;
}
@@ -874,15 +873,15 @@ Transactor::checkMultiSign(
// In any of these cases we need to know whether the account is in
// the ledger. Determine that now.
auto const sleTxSignerRoot = view.read(keylet::account(txSignerAcctID));
AccountRoot const acctSigner(txSignerAcctID, view);
if (signingAcctIDFromPubKey == txSignerAcctID)
{
// Either Phantom or Master. Phantoms automatically pass.
if (sleTxSignerRoot)
if (acctSigner)
{
// Master Key. Account may not have asfDisableMaster set.
std::uint32_t const signerAccountFlags = sleTxSignerRoot->getFieldU32(sfFlags);
std::uint32_t const signerAccountFlags = acctSigner->getFieldU32(sfFlags);
if ((signerAccountFlags & lsfDisableMaster) != 0u)
{
@@ -895,19 +894,19 @@ Transactor::checkMultiSign(
{
// May be a Regular Key. Let's find out.
// Public key must hash to the account's regular key.
if (!sleTxSignerRoot)
if (!acctSigner)
{
JLOG(j.trace()) << "applyTransaction: Non-phantom signer "
"lacks account root.";
return tefBAD_SIGNATURE;
}
if (!sleTxSignerRoot->isFieldPresent(sfRegularKey))
if (!acctSigner->isFieldPresent(sfRegularKey))
{
JLOG(j.trace()) << "applyTransaction: Account lacks RegularKey.";
return tefBAD_SIGNATURE;
}
if (signingAcctIDFromPubKey != sleTxSignerRoot->getAccountID(sfRegularKey))
if (signingAcctIDFromPubKey != acctSigner->getAccountID(sfRegularKey))
{
JLOG(j.trace()) << "applyTransaction: Account doesn't match RegularKey.";
return tefBAD_SIGNATURE;
@@ -1009,18 +1008,25 @@ Transactor::reset(XRPAmount fee)
{
ctx_.discard();
auto const txnAcct = view().peek(keylet::account(ctx_.tx.getAccountID(sfAccount)));
WritableAccountRoot txnAcct(ctx_.tx.getAccountID(sfAccount), view());
// The account should never be missing from the ledger. But if it
// is missing then we can't very well charge it a fee, can we?
if (!txnAcct)
return {tefINTERNAL, beast::zero};
auto const payerSle = view().peek(keylet::account(ctx_.tx.getFeePayer()));
if (!payerSle)
return {tefINTERNAL, beast::zero}; // LCOV_EXCL_LINE
auto const feePayer = ctx_.tx.getFeePayer();
bool const hasDelegateAcct = (feePayer != accountID_);
std::optional<WritableAccountRoot> delegateAcct;
if (hasDelegateAcct)
{
delegateAcct.emplace(feePayer, view());
if (!*delegateAcct)
return {tefINTERNAL, beast::zero}; // LCOV_EXCL_LINE
}
auto const balance = payerSle->getFieldAmount(sfBalance).xrp();
auto& payer = hasDelegateAcct ? *delegateAcct : txnAcct;
auto const balance = payer->getFieldAmount(sfBalance).xrp();
// balance should have already been checked in checkFee / preFlight.
XRPL_ASSERT(
@@ -1039,15 +1045,15 @@ Transactor::reset(XRPAmount fee)
// If for some reason we are unable to consume the ticket or sequence
// then the ledger is corrupted. Rather than make things worse we
// reject the transaction.
payerSle->setFieldAmount(sfBalance, balance - fee);
TER const ter{consumeSeqProxy(txnAcct)};
payer->setFieldAmount(sfBalance, balance - fee);
TER const ter{consumeSeqProxy(txnAcct.mutableSle())};
XRPL_ASSERT(isTesSuccess(ter), "xrpl::Transactor::reset : result is tesSUCCESS");
if (isTesSuccess(ter))
{
view().update(txnAcct);
if (payerSle != txnAcct)
view().update(payerSle);
txnAcct.update();
if (hasDelegateAcct)
delegateAcct->update();
}
return {ter, fee};
@@ -1095,7 +1101,7 @@ Transactor::operator()()
}
#endif
if (auto const& trap = ctx_.registry.getTrapTxID(); trap && *trap == ctx_.tx.getTransactionID())
if (auto const& trap = ctx_.registry.trapTxID(); trap && *trap == ctx_.tx.getTransactionID())
{
trapTransaction(*trap);
}
@@ -1197,25 +1203,16 @@ Transactor::operator()()
// If necessary, remove any offers found unfunded during processing
if ((result == tecOVERSIZE) || (result == tecKILLED))
{
removeUnfundedOffers(view(), removedOffers, ctx_.registry.getJournal("View"));
}
removeUnfundedOffers(view(), removedOffers, ctx_.registry.journal("View"));
if (result == tecEXPIRED)
{
removeExpiredNFTokenOffers(
view(), expiredNFTokenOffers, ctx_.registry.getJournal("View"));
}
removeExpiredNFTokenOffers(view(), expiredNFTokenOffers, ctx_.registry.journal("View"));
if (result == tecINCOMPLETE)
{
removeDeletedTrustLines(view(), removedTrustLines, ctx_.registry.getJournal("View"));
}
removeDeletedTrustLines(view(), removedTrustLines, ctx_.registry.journal("View"));
if (result == tecEXPIRED)
{
removeExpiredCredentials(view(), expiredCredentials, ctx_.registry.getJournal("View"));
}
removeExpiredCredentials(view(), expiredCredentials, ctx_.registry.journal("View"));
applied = isTecClaim(result);
}

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -98,7 +99,7 @@ ValidLoanBroker::finalize(
{
for (auto const& field : {&sfLowLimit, &sfHighLimit})
{
auto const account = view.read(keylet::account(line->at(*field).getIssuer()));
AccountRoot const account(line->at(*field).getIssuer(), view);
// This Invariant doesn't know about the rules for Trust Lines, so
// if the account is missing, don't treat it as an error. This
// loop is only concerned with finding Broker pseudo-accounts
@@ -112,7 +113,7 @@ ValidLoanBroker::finalize(
}
for (auto const& mpt : mpts_)
{
auto const account = view.read(keylet::account(mpt->at(sfAccount)));
AccountRoot const account(mpt->at(sfAccount), view);
// This Invariant doesn't know about the rules for MPTokens, so
// if the account is missing, don't treat is as an error. This
// loop is only concerned with finding Broker pseudo-accounts
@@ -236,7 +237,8 @@ ValidLoan::finalize(
after->at(sfPrincipalOutstanding) == beast::zero &&
after->at(sfManagementFeeOutstanding) == beast::zero)
{
JLOG(j.fatal()) << "Invariant failed: Fully paid off Loan still has payments remaining";
JLOG(j.fatal()) << "Invariant failed: Loan with zero payments "
"remaining has not been paid off";
return false;
}
if (before && (before->isFlag(lsfLoanOverpayment) != after->isFlag(lsfLoanOverpayment)))

View File

@@ -481,16 +481,15 @@ ValidVault::finalize(
result = false;
}
auto const sleSharesIssuer =
view.read(keylet::account(updatedShares->share.getIssuer()));
if (!sleSharesIssuer)
AccountRoot const acctSharesIssuer(updatedShares->share.getIssuer(), view);
if (!acctSharesIssuer)
{
JLOG(j.fatal()) //
<< "Invariant failed: shares issuer must exist";
return false;
}
if (!isPseudoAccount(sleSharesIssuer))
if (!acctSharesIssuer.isPseudoAccount())
{
JLOG(j.fatal()) //
<< "Invariant failed: shares issuer must be a "
@@ -498,7 +497,7 @@ ValidVault::finalize(
result = false;
}
if (auto const vaultId = (*sleSharesIssuer)[~sfVaultID];
if (auto const vaultId = acctSharesIssuer->at(~sfVaultID);
!vaultId || *vaultId != afterVault.key)
{
JLOG(j.fatal()) //

View File

@@ -1,3 +1,4 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/View.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/tx/paths/Flow.h>
@@ -34,12 +35,12 @@ RippleCalc::rippleCalculate(
STPathSet const& spsPaths,
std::optional<uint256> const& domainID,
ServiceRegistry& registry,
Logs& l,
Input const* const pInputs)
{
Output flowOut;
PaymentSandbox flowSB(&view);
auto j = registry.getJournal("Flow");
auto j = l.journal("Flow");
{
bool const defaultPaths = (pInputs == nullptr) ? true : pInputs->defaultPathsAllowed;

View File

@@ -1,6 +1,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
@@ -208,12 +209,12 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
AccountID const account{ctx.tx[sfAccount]};
AccountID const dst{ctx.tx[sfDestination]};
auto sleDst = ctx.view.read(keylet::account(dst));
AccountRoot const acctDst(dst, ctx.view);
if (!sleDst)
if (!acctDst)
return tecNO_DST;
if ((((*sleDst)[sfFlags] & lsfRequireDestTag) != 0u) && !ctx.tx[~sfDestinationTag])
if (((acctDst->getFlags() & lsfRequireDestTag) != 0u) && !ctx.tx[~sfDestinationTag])
return tecDST_TAG_NEEDED;
// If credentials are provided - check them anyway
@@ -225,21 +226,21 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
if (!ctx.tx.isFieldPresent(sfCredentialIDs))
{
// Check whether the destination account requires deposit authorization.
if ((sleDst->getFlags() & lsfDepositAuth) != 0u)
if ((acctDst->getFlags() & lsfDepositAuth) != 0u)
{
if (!ctx.view.exists(keylet::depositPreauth(dst, account)))
return tecNO_PERMISSION;
}
}
auto sleAccount = ctx.view.read(keylet::account(account));
XRPL_ASSERT(sleAccount, "xrpl::AccountDelete::preclaim : non-null account");
if (!sleAccount)
AccountRoot const acctSrc(account, ctx.view);
XRPL_ASSERT(acctSrc, "xrpl::AccountDelete::preclaim : non-null account");
if (!acctSrc)
return terNO_ACCOUNT;
// If an issuer has any issued NFTs resident in the ledger then it
// cannot be deleted.
if ((*sleAccount)[~sfMintedNFTokens] != (*sleAccount)[~sfBurnedNFTokens])
if (acctSrc->at(~sfMintedNFTokens) != acctSrc->at(~sfBurnedNFTokens))
return tecHAS_OBLIGATIONS;
// If the account owns any NFTs it cannot be deleted.
@@ -258,7 +259,7 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
// We look at the account's Sequence rather than the transaction's
// Sequence in preparation for Tickets.
constexpr std::uint32_t seqDelta{255};
if ((*sleAccount)[sfSequence] + seqDelta > ctx.view.seq())
if (acctSrc->getFieldU32(sfSequence) + seqDelta > ctx.view.seq())
return tecTOO_SOON;
// We don't allow an account to be deleted if
@@ -272,8 +273,8 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
// their account and mints a NFToken, it is possible that the
// NFTokenSequence of this NFToken is the same as the one that the
// authorized minter minted in a previous ledger.
if ((*sleAccount)[~sfFirstNFTokenSequence].value_or(0) +
(*sleAccount)[~sfMintedNFTokens].value_or(0) + seqDelta >
if (acctSrc->at(~sfFirstNFTokenSequence).value_or(0) +
acctSrc->at(~sfMintedNFTokens).value_or(0) + seqDelta >
ctx.view.seq())
return tecTOO_SOON;
@@ -326,25 +327,24 @@ AccountDelete::preclaim(PreclaimContext const& ctx)
TER
AccountDelete::doApply()
{
auto src = view().peek(keylet::account(account_));
XRPL_ASSERT(src, "xrpl::AccountDelete::doApply : non-null source account");
WritableAccountRoot src(accountID_, view());
XRPL_ASSERT(src.exists(), "xrpl::AccountDelete::doApply : non-null source account");
auto const dstID = ctx_.tx[sfDestination];
auto dst = view().peek(keylet::account(dstID));
XRPL_ASSERT(dst, "xrpl::AccountDelete::doApply : non-null destination account");
WritableAccountRoot dst(dstID, view());
XRPL_ASSERT(dst.exists(), "xrpl::AccountDelete::doApply : non-null destination account");
if (!src || !dst)
if (!src.exists() || !dst.exists())
return tefBAD_LEDGER; // LCOV_EXCL_LINE
if (ctx_.tx.isFieldPresent(sfCredentialIDs))
{
if (auto err =
verifyDepositPreauth(ctx_.tx, ctx_.view(), account_, dstID, dst, ctx_.journal);
if (auto err = verifyDepositPreauth(ctx_.tx, ctx_.view(), accountID_, dst, ctx_.journal);
!isTesSuccess(err))
return err;
}
Keylet const ownerDirKeylet{keylet::ownerDir(account_)};
Keylet const ownerDirKeylet{keylet::ownerDir(accountID_)};
auto const ter = cleanupOnAccountDelete(
view(),
ownerDirKeylet,
@@ -353,7 +353,7 @@ AccountDelete::doApply()
std::shared_ptr<SLE>& sleItem) -> std::pair<TER, SkipEntry> {
if (auto deleter = nonObligationDeleter(nodeType))
{
TER const result{deleter(ctx_.registry, view(), account_, dirEntry, sleItem, j_)};
TER const result{deleter(ctx_.registry, view(), accountID_, dirEntry, sleItem, j_)};
return {result, SkipEntry::No};
}
@@ -384,7 +384,7 @@ AccountDelete::doApply()
// delete it.
if (view().exists(ownerDirKeylet) && !view().emptyDirDelete(ownerDirKeylet))
{
JLOG(j_.error()) << "AccountDelete cannot delete root dir node of " << toBase58(account_);
JLOG(j_.error()) << "AccountDelete cannot delete root dir node of " << toBase58(accountID_);
return tecHAS_OBLIGATIONS;
}
@@ -392,8 +392,8 @@ AccountDelete::doApply()
if (remainingBalance > XRPAmount(0) && dst->isFlag(lsfPasswordSpent))
dst->clearFlag(lsfPasswordSpent);
view().update(dst);
view().erase(src);
dst.update();
src.erase();
return tesSUCCESS;
}

View File

@@ -1,5 +1,6 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -208,11 +209,11 @@ AccountSet::preclaim(PreclaimContext const& ctx)
std::uint32_t const uTxFlags = ctx.tx.getFlags();
auto const sle = ctx.view.read(keylet::account(id));
if (!sle)
AccountRoot const acctRoot(id, ctx.view);
if (!acctRoot)
return terNO_ACCOUNT;
std::uint32_t const uFlagsIn = sle->getFieldU32(sfFlags);
std::uint32_t const uFlagsIn = acctRoot->getFieldU32(sfFlags);
std::uint32_t const uSetFlag = ctx.tx.getFieldU32(sfSetFlag);
@@ -267,11 +268,11 @@ AccountSet::preclaim(PreclaimContext const& ctx)
TER
AccountSet::doApply()
{
auto const sle = view().peek(keylet::account(account_));
if (!sle)
WritableAccountRoot acct(accountID_, view());
if (!acct)
return tefINTERNAL; // LCOV_EXCL_LINE
std::uint32_t const uFlagsIn = sle->getFieldU32(sfFlags);
std::uint32_t const uFlagsIn = acct->getFieldU32(sfFlags);
std::uint32_t uFlagsOut = uFlagsIn;
STTx const& tx{ctx_.tx};
@@ -290,7 +291,7 @@ AccountSet::doApply()
bool const bSetDisallowXRP{((uTxFlags & tfDisallowXRP) != 0u) || (uSetFlag == asfDisallowXRP)};
bool const bClearDisallowXRP{((uTxFlags & tfAllowXRP) != 0u) || (uClearFlag == asfDisallowXRP)};
bool const sigWithMaster{[&tx, &acct = account_]() {
bool const sigWithMaster{[&tx, &acct = accountID_]() {
auto const spk = tx.getSigningPubKey();
if (publicKeyType(makeSlice(spk)))
@@ -359,7 +360,7 @@ AccountSet::doApply()
return tecNEED_MASTER_KEY;
}
if ((!sle->isFieldPresent(sfRegularKey)) && (!view().peek(keylet::signers(account_))))
if ((!acct->isFieldPresent(sfRegularKey)) && (!view().peek(keylet::signers(accountID_))))
{
// Account has no regular key or multi-signer signer list.
return tecNO_ALTERNATIVE_KEY;
@@ -424,16 +425,16 @@ AccountSet::doApply()
//
// Track transaction IDs signed by this account in its root
//
if ((uSetFlag == asfAccountTxnID) && !sle->isFieldPresent(sfAccountTxnID))
if ((uSetFlag == asfAccountTxnID) && !acct->isFieldPresent(sfAccountTxnID))
{
JLOG(j_.trace()) << "Set AccountTxnID.";
sle->makeFieldPresent(sfAccountTxnID);
acct->makeFieldPresent(sfAccountTxnID);
}
if ((uClearFlag == asfAccountTxnID) && sle->isFieldPresent(sfAccountTxnID))
if ((uClearFlag == asfAccountTxnID) && acct->isFieldPresent(sfAccountTxnID))
{
JLOG(j_.trace()) << "Clear AccountTxnID.";
sle->makeFieldAbsent(sfAccountTxnID);
acct->makeFieldAbsent(sfAccountTxnID);
}
//
@@ -460,12 +461,12 @@ AccountSet::doApply()
if (!uHash)
{
JLOG(j_.trace()) << "unset email hash";
sle->makeFieldAbsent(sfEmailHash);
acct->makeFieldAbsent(sfEmailHash);
}
else
{
JLOG(j_.trace()) << "set email hash";
sle->setFieldH128(sfEmailHash, uHash);
acct->setFieldH128(sfEmailHash, uHash);
}
}
@@ -479,12 +480,12 @@ AccountSet::doApply()
if (!uHash)
{
JLOG(j_.trace()) << "unset wallet locator";
sle->makeFieldAbsent(sfWalletLocator);
acct->makeFieldAbsent(sfWalletLocator);
}
else
{
JLOG(j_.trace()) << "set wallet locator";
sle->setFieldH256(sfWalletLocator, uHash);
acct->setFieldH256(sfWalletLocator, uHash);
}
}
@@ -498,12 +499,12 @@ AccountSet::doApply()
if (messageKey.empty())
{
JLOG(j_.debug()) << "clear message key";
sle->makeFieldAbsent(sfMessageKey);
acct->makeFieldAbsent(sfMessageKey);
}
else
{
JLOG(j_.debug()) << "set message key";
sle->setFieldVL(sfMessageKey, messageKey);
acct->setFieldVL(sfMessageKey, messageKey);
}
}
@@ -517,12 +518,12 @@ AccountSet::doApply()
if (domain.empty())
{
JLOG(j_.trace()) << "unset domain";
sle->makeFieldAbsent(sfDomain);
acct->makeFieldAbsent(sfDomain);
}
else
{
JLOG(j_.trace()) << "set domain";
sle->setFieldVL(sfDomain, domain);
acct->setFieldVL(sfDomain, domain);
}
}
@@ -536,12 +537,12 @@ AccountSet::doApply()
if (uRate == 0 || uRate == QUALITY_ONE)
{
JLOG(j_.trace()) << "unset transfer rate";
sle->makeFieldAbsent(sfTransferRate);
acct->makeFieldAbsent(sfTransferRate);
}
else
{
JLOG(j_.trace()) << "set transfer rate";
sle->setFieldU32(sfTransferRate, uRate);
acct->setFieldU32(sfTransferRate, uRate);
}
}
@@ -554,21 +555,21 @@ AccountSet::doApply()
if ((uTickSize == 0) || (uTickSize == Quality::maxTickSize))
{
JLOG(j_.trace()) << "unset tick size";
sle->makeFieldAbsent(sfTickSize);
acct->makeFieldAbsent(sfTickSize);
}
else
{
JLOG(j_.trace()) << "set tick size";
sle->setFieldU8(sfTickSize, uTickSize);
acct->setFieldU8(sfTickSize, uTickSize);
}
}
// Configure authorized minting account:
if (uSetFlag == asfAuthorizedNFTokenMinter)
sle->setAccountID(sfNFTokenMinter, ctx_.tx[sfNFTokenMinter]);
acct->setAccountID(sfNFTokenMinter, ctx_.tx[sfNFTokenMinter]);
if (uClearFlag == asfAuthorizedNFTokenMinter && sle->isFieldPresent(sfNFTokenMinter))
sle->makeFieldAbsent(sfNFTokenMinter);
if (uClearFlag == asfAuthorizedNFTokenMinter && acct->isFieldPresent(sfNFTokenMinter))
acct->makeFieldAbsent(sfNFTokenMinter);
if (uSetFlag == asfDisallowIncomingNFTokenOffer)
{
@@ -627,9 +628,9 @@ AccountSet::doApply()
}
if (uFlagsIn != uFlagsOut)
sle->setFieldU32(sfFlags, uFlagsOut);
acct->setFieldU32(sfFlags, uFlagsOut);
ctx_.view().update(sle);
acct.update();
return tesSUCCESS;
}

View File

@@ -1,4 +1,5 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/account/SetRegularKey.h>
@@ -15,9 +16,9 @@ SetRegularKey::calculateBaseFee(ReadView const& view, STTx const& tx)
{
if (calcAccountID(PublicKey(makeSlice(spk))) == id)
{
auto const sle = view.read(keylet::account(id));
AccountRoot const acct(id, view);
if (sle && ((sle->getFlags() & lsfPasswordSpent) == 0u))
if (acct && ((acct->getFlags() & lsfPasswordSpent) == 0u))
{
// flag is armed and they signed with the right account
return XRPAmount{0};
@@ -43,27 +44,27 @@ SetRegularKey::preflight(PreflightContext const& ctx)
TER
SetRegularKey::doApply()
{
auto const sle = view().peek(keylet::account(account_));
if (!sle)
WritableAccountRoot acct(accountID_, view());
if (!acct)
return tefINTERNAL; // LCOV_EXCL_LINE
if (!minimumFee(ctx_.registry, ctx_.baseFee, view().fees(), view().flags()))
sle->setFlag(lsfPasswordSpent);
acct->setFlag(lsfPasswordSpent);
if (ctx_.tx.isFieldPresent(sfRegularKey))
{
sle->setAccountID(sfRegularKey, ctx_.tx.getAccountID(sfRegularKey));
acct->setAccountID(sfRegularKey, ctx_.tx.getAccountID(sfRegularKey));
}
else
{
// Account has disabled master key and no multi-signer signer list.
if (sle->isFlag(lsfDisableMaster) && !view().peek(keylet::signers(account_)))
if (acct->isFlag(lsfDisableMaster) && !view().peek(keylet::signers(accountID_)))
return tecNO_ALTERNATIVE_KEY;
sle->makeFieldAbsent(sfRegularKey);
acct->makeFieldAbsent(sfRegularKey);
}
ctx_.view().update(sle);
acct.update();
return tesSUCCESS;
}

View File

@@ -1,3 +1,4 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -160,11 +161,11 @@ static TER
removeSignersFromLedger(
ServiceRegistry& registry,
ApplyView& view,
Keylet const& accountKeylet,
Keylet const& ownerDirKeylet,
Keylet const& signerListKeylet,
AccountID const& account,
beast::Journal j)
{
auto const ownerDirKeylet = keylet::ownerDir(account);
auto const signerListKeylet = keylet::signers(account);
// We have to examine the current SignerList so we know how much to
// reduce the OwnerCount.
SLE::pointer signers = view.peek(signerListKeylet);
@@ -195,8 +196,8 @@ removeSignersFromLedger(
// LCOV_EXCL_STOP
}
adjustOwnerCount(
view, view.peek(accountKeylet), removeFromOwnerCount, registry.getJournal("View"));
WritableAccountRoot wrappedAcct(account, view);
wrappedAcct.adjustOwnerCount(removeFromOwnerCount, registry.journal("View"));
view.erase(signers);
@@ -210,12 +211,7 @@ SignerListSet::removeFromLedger(
AccountID const& account,
beast::Journal j)
{
auto const accountKeylet = keylet::account(account);
auto const ownerDirKeylet = keylet::ownerDir(account);
auto const signerListKeylet = keylet::signers(account);
return removeSignersFromLedger(
registry, view, accountKeylet, ownerDirKeylet, signerListKeylet, j);
return removeSignersFromLedger(registry, view, account, j);
}
NotTEC
@@ -280,23 +276,18 @@ SignerListSet::validateQuorumAndSignerEntries(
TER
SignerListSet::replaceSignerList()
{
auto const accountKeylet = keylet::account(account_);
auto const ownerDirKeylet = keylet::ownerDir(account_);
auto const signerListKeylet = keylet::signers(account_);
// This may be either a create or a replace. Preemptively remove any
// old signer list. May reduce the reserve, so this is done before
// checking the reserve.
if (TER const ter = removeSignersFromLedger(
ctx_.registry, view(), accountKeylet, ownerDirKeylet, signerListKeylet, j_))
if (TER const ter = removeSignersFromLedger(ctx_.registry, view(), accountID_, j_))
return ter;
auto const sle = view().peek(accountKeylet);
if (!sle)
WritableAccountRoot wrappedAcct(accountID_, view());
if (!wrappedAcct)
return tefINTERNAL; // LCOV_EXCL_LINE
// Compute new reserve. Verify the account has funds to meet the reserve.
std::uint32_t const oldOwnerCount{(*sle)[sfOwnerCount]};
std::uint32_t const oldOwnerCount{(*wrappedAcct)[sfOwnerCount]};
constexpr int addedOwnerCount = 1;
std::uint32_t flags{lsfOneOwnerCount};
@@ -310,16 +301,18 @@ SignerListSet::replaceSignerList()
return tecINSUFFICIENT_RESERVE;
// Everything's ducky. Add the ltSIGNER_LIST to the ledger.
Keylet const ownerDirKeylet = keylet::ownerDir(accountID_);
Keylet const signerListKeylet = keylet::signers(accountID_);
auto signerList = std::make_shared<SLE>(signerListKeylet);
view().insert(signerList);
writeSignersToSLE(signerList, flags);
auto viewJ = ctx_.registry.getJournal("View");
auto viewJ = ctx_.registry.journal("View");
// Add the signer list to the account's directory.
auto const page =
ctx_.view().dirInsert(ownerDirKeylet, signerListKeylet, describeOwnerDir(account_));
ctx_.view().dirInsert(ownerDirKeylet, signerListKeylet, describeOwnerDir(accountID_));
JLOG(j_.trace()) << "Create signer list for account " << toBase58(account_) << ": "
JLOG(j_.trace()) << "Create signer list for account " << toBase58(accountID_) << ": "
<< (page ? "success" : "failure");
if (!page)
@@ -329,27 +322,22 @@ SignerListSet::replaceSignerList()
// If we succeeded, the new entry counts against the
// creator's reserve.
adjustOwnerCount(view(), sle, addedOwnerCount, viewJ);
wrappedAcct.adjustOwnerCount(addedOwnerCount, viewJ);
return tesSUCCESS;
}
TER
SignerListSet::destroySignerList()
{
auto const accountKeylet = keylet::account(account_);
// Destroying the signer list is only allowed if either the master key
// is enabled or there is a regular key.
SLE::pointer ledgerEntry = view().peek(accountKeylet);
if (!ledgerEntry)
if (!account_)
return tefINTERNAL; // LCOV_EXCL_LINE
if ((ledgerEntry->isFlag(lsfDisableMaster)) && (!ledgerEntry->isFieldPresent(sfRegularKey)))
if ((account_->isFlag(lsfDisableMaster)) && (!account_->isFieldPresent(sfRegularKey)))
return tecNO_ALTERNATIVE_KEY;
auto const ownerDirKeylet = keylet::ownerDir(account_);
auto const signerListKeylet = keylet::signers(account_);
return removeSignersFromLedger(
ctx_.registry, view(), accountKeylet, ownerDirKeylet, signerListKeylet, j_);
return removeSignersFromLedger(ctx_.registry, view(), accountID_, j_);
}
void
@@ -358,7 +346,7 @@ SignerListSet::writeSignersToSLE(SLE::pointer const& ledgerEntry, std::uint32_t
// Assign the quorum, default SignerListID, and flags.
if (ctx_.view().rules().enabled(fixIncludeKeyletFields))
{
ledgerEntry->setAccountID(sfOwner, account_);
ledgerEntry->setAccountID(sfOwner, accountID_);
}
ledgerEntry->setFieldU32(sfSignerQuorum, quorum_);
ledgerEntry->setFieldU32(sfSignerListID, DEFAULT_SIGNER_LIST_ID);

View File

@@ -103,13 +103,12 @@ checkAttestationPublicKey(
AccountID const accountFromPK = calcAccountID(pk);
if (auto const sleAttestationSigningAccount =
view.read(keylet::account(attestationSignerAccount)))
if (AccountRoot const acctSigner(attestationSignerAccount, view); acctSigner)
{
if (accountFromPK == attestationSignerAccount)
{
// master key
if ((sleAttestationSigningAccount->getFieldU32(sfFlags) & lsfDisableMaster) != 0u)
if ((acctSigner->getFieldU32(sfFlags) & lsfDisableMaster) != 0u)
{
JLOG(j.trace()) << "Attempt to add an attestation with "
"disabled master key.";
@@ -119,8 +118,7 @@ checkAttestationPublicKey(
else
{
// regular key
if (std::optional<AccountID> regularKey =
(*sleAttestationSigningAccount)[~sfRegularKey];
if (std::optional<AccountID> regularKey = acctSigner->at(~sfRegularKey);
regularKey != accountFromPK)
{
if (!regularKey)
@@ -381,12 +379,12 @@ transferHelper(
if (dst == src)
return tesSUCCESS;
auto const dstK = keylet::account(dst);
if (auto sleDst = psb.read(dstK))
AccountRoot const acctDst(dst, psb);
if (acctDst)
{
// Check dst tag and deposit auth
if (((sleDst->getFlags() & lsfRequireDestTag) != 0u) && !dstTag)
if (((acctDst->getFlags() & lsfRequireDestTag) != 0u) && !dstTag)
return tecDST_TAG_NEEDED;
// If the destination is the claim owner, and this is a claim
@@ -395,7 +393,7 @@ transferHelper(
bool const canBypassDepositAuth =
dst == claimOwner && depositAuthPolicy == DepositAuthPolicy::dstCanBypass;
if (!canBypassDepositAuth && ((sleDst->getFlags() & lsfDepositAuth) != 0u) &&
if (!canBypassDepositAuth && ((acctDst->getFlags() & lsfDepositAuth) != 0u) &&
!psb.exists(keylet::depositPreauth(dst, src)))
{
return tecNO_PERMISSION;
@@ -408,17 +406,17 @@ transferHelper(
if (amt.native())
{
auto const sleSrc = psb.peek(keylet::account(src));
XRPL_ASSERT(sleSrc, "xrpl::transferHelper : non-null source account");
if (!sleSrc)
WritableAccountRoot acctSrc(src, psb);
XRPL_ASSERT(acctSrc, "xrpl::transferHelper : non-null source account");
if (!acctSrc)
return tecINTERNAL; // LCOV_EXCL_LINE
{
auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
auto const ownerCount = acctSrc->getFieldU32(sfOwnerCount);
auto const reserve = psb.fees().accountReserve(ownerCount);
auto const availableBalance = [&]() -> STAmount {
STAmount const curBal = (*sleSrc)[sfBalance];
STAmount const curBal = acctSrc->at(sfBalance);
// Checking that account == src and postFeeBalance == curBal is
// not strictly necessary, but helps protect against future
// changes
@@ -434,8 +432,8 @@ transferHelper(
}
}
auto sleDst = psb.peek(dstK);
if (!sleDst)
WritableAccountRoot acctDst(dst, psb);
if (!acctDst)
{
if (canCreate == CanCreateDstPolicy::no)
{
@@ -449,17 +447,17 @@ transferHelper(
}
// Create the account.
sleDst = std::make_shared<SLE>(dstK);
sleDst->setAccountID(sfAccount, dst);
sleDst->setFieldU32(sfSequence, psb.seq());
acctDst.newSLE();
acctDst->setAccountID(sfAccount, dst);
acctDst->setFieldU32(sfSequence, psb.seq());
psb.insert(sleDst);
acctDst.insert();
}
(*sleSrc)[sfBalance] = (*sleSrc)[sfBalance] - amt;
(*sleDst)[sfBalance] = (*sleDst)[sfBalance] + amt;
psb.update(sleSrc);
psb.update(sleDst);
acctSrc->at(sfBalance) = acctSrc->at(sfBalance) - amt;
acctDst->at(sfBalance) = acctDst->at(sfBalance) + amt;
acctSrc.update();
acctDst.update();
return tesSUCCESS;
}
@@ -695,7 +693,7 @@ finalizeClaimHelper(
auto const cidOwner = (*sleClaimID)[sfAccount];
{
// Remove the claim id
auto const sleOwner = outerSb.peek(keylet::account(cidOwner));
WritableAccountRoot wrappedOwner(cidOwner, outerSb);
auto const page = (*sleClaimID)[sfOwnerNode];
if (!outerSb.dirRemove(keylet::ownerDir(cidOwner), page, sleClaimID->key(), true))
{
@@ -707,7 +705,7 @@ finalizeClaimHelper(
// Remove the claim id from the ledger
outerSb.erase(sleClaimID);
adjustOwnerCount(outerSb, sleOwner, -1, j);
wrappedOwner.adjustOwnerCount(-1, j);
}
}
@@ -730,9 +728,9 @@ getSignersListAndQuorum(ReadView const& view, SLE const& sleBridge, beast::Journ
std::uint32_t q = std::numeric_limits<std::uint32_t>::max();
AccountID const thisDoor = sleBridge[sfAccount];
auto const sleDoor = [&] { return view.read(keylet::account(thisDoor)); }();
AccountRoot const acctDoor(thisDoor, view);
if (!sleDoor)
if (!acctDoor)
{
return {r, q, tecINTERNAL};
}
@@ -1111,14 +1109,13 @@ applyCreateAccountAttestations(
return tecDIR_FULL; // LCOV_EXCL_LINE
(*createdSleClaimID)[sfOwnerNode] = *page;
auto const sleDoor = psb.peek(doorK);
if (!sleDoor)
WritableAccountRoot wrappedDoor(doorAccount, psb);
if (!wrappedDoor)
return tecINTERNAL; // LCOV_EXCL_LINE
// Reserve was already checked
adjustOwnerCount(psb, sleDoor, 1, j);
wrappedDoor.adjustOwnerCount(1, j);
psb.insert(createdSleClaimID);
psb.update(sleDoor);
}
psb.apply(rawView);
@@ -1396,25 +1393,25 @@ XChainCreateBridge::preclaim(PreclaimContext const& ctx)
if (!isXRP(bridgeSpec.issue(chainType)))
{
auto const sleIssuer = ctx.view.read(keylet::account(bridgeSpec.issue(chainType).account));
AccountRoot const acctIssuer(bridgeSpec.issue(chainType).account, ctx.view);
if (!sleIssuer)
if (!acctIssuer)
return tecNO_ISSUER;
// Allowing clawing back funds would break the bridge's invariant that
// wrapped funds are always backed by locked funds
if ((sleIssuer->getFlags() & lsfAllowTrustLineClawback) != 0u)
if ((acctIssuer->getFlags() & lsfAllowTrustLineClawback) != 0u)
return tecNO_PERMISSION;
}
{
// Check reserve
auto const sleAcc = ctx.view.read(keylet::account(account));
if (!sleAcc)
AccountRoot const acctSrc(account, ctx.view);
if (!acctSrc)
return terNO_ACCOUNT;
auto const balance = (*sleAcc)[sfBalance];
auto const reserve = ctx.view.fees().accountReserve((*sleAcc)[sfOwnerCount] + 1);
auto const balance = acctSrc->at(sfBalance);
auto const reserve = ctx.view.fees().accountReserve(acctSrc->getFieldU32(sfOwnerCount) + 1);
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -1431,8 +1428,8 @@ XChainCreateBridge::doApply()
auto const reward = ctx_.tx[sfSignatureReward];
auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount];
auto const sleAcct = ctx_.view().peek(keylet::account(account));
if (!sleAcct)
WritableAccountRoot wrappedAcct(account, ctx_.view());
if (!wrappedAcct)
return tecINTERNAL; // LCOV_EXCL_LINE
STXChainBridge::ChainType const chainType =
@@ -1459,10 +1456,10 @@ XChainCreateBridge::doApply()
(*sleBridge)[sfOwnerNode] = *page;
}
adjustOwnerCount(ctx_.view(), sleAcct, 1, ctx_.journal);
wrappedAcct.adjustOwnerCount(1, ctx_.journal);
ctx_.view().insert(sleBridge);
ctx_.view().update(sleAcct);
wrappedAcct.update();
return tesSUCCESS;
}
@@ -1542,8 +1539,7 @@ BridgeModify::doApply()
auto const minAccountCreate = ctx_.tx[~sfMinAccountCreateAmount];
bool const clearAccountCreate = (ctx_.tx.getFlags() & tfClearAccountCreateAmount) != 0u;
auto const sleAcct = ctx_.view().peek(keylet::account(account));
if (!sleAcct)
if (!AccountRoot(account, ctx_.view()))
return tecINTERNAL; // LCOV_EXCL_LINE
STXChainBridge::ChainType const chainType =
@@ -1600,7 +1596,7 @@ XChainClaim::preclaim(PreclaimContext const& ctx)
return tecNO_ENTRY;
}
if (!ctx.view.read(keylet::account(ctx.tx[sfDestination])))
if (!AccountRoot(ctx.tx[sfDestination], ctx.view))
{
return tecNO_DST;
}
@@ -1705,11 +1701,11 @@ XChainClaim::doApply()
// `finalizeClaimHelper`. Since `finalizeClaimHelper` can create child
// views, it's important that the sle's lifetime doesn't overlap.
auto const sleAcct = psb.peek(keylet::account(account));
AccountRoot const acctRoot(account, psb);
auto const sleBridge = peekBridge(psb, bridgeSpec);
auto const sleClaimID = psb.peek(claimIDKeylet);
if (!(sleBridge && sleClaimID && sleAcct))
if (!(sleBridge && sleClaimID && acctRoot))
return Unexpected(tecINTERNAL);
AccountID const thisDoor = (*sleBridge)[sfAccount];
@@ -1886,8 +1882,8 @@ XChainCommit::doApply()
auto const amount = ctx_.tx[sfAmount];
auto const bridgeSpec = ctx_.tx[sfXChainBridge];
auto const sleAccount = psb.read(keylet::account(account));
if (!sleAccount)
AccountRoot const acctRoot(account, psb);
if (!acctRoot)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const sleBridge = readBridge(psb, bridgeSpec);
@@ -1898,7 +1894,7 @@ XChainCommit::doApply()
// Support dipping into reserves to pay the fee
TransferHelperSubmittingAccountInfo submittingAccountInfo{
account_, preFeeBalance_, (*sleAccount)[sfBalance]};
accountID_, preFeeBalance_, (*acctRoot)[sfBalance]};
auto const thTer = transferHelper(
psb,
@@ -1955,12 +1951,12 @@ XChainCreateClaimID::preclaim(PreclaimContext const& ctx)
{
// Check reserve
auto const sleAcc = ctx.view.read(keylet::account(account));
if (!sleAcc)
AccountRoot const acctSrc(account, ctx.view);
if (!acctSrc)
return terNO_ACCOUNT;
auto const balance = (*sleAcc)[sfBalance];
auto const reserve = ctx.view.fees().accountReserve((*sleAcc)[sfOwnerCount] + 1);
auto const balance = acctSrc->at(sfBalance);
auto const reserve = ctx.view.fees().accountReserve(acctSrc->getFieldU32(sfOwnerCount) + 1);
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -1977,8 +1973,8 @@ XChainCreateClaimID::doApply()
auto const reward = ctx_.tx[sfSignatureReward];
auto const otherChainSrc = ctx_.tx[sfOtherChainSource];
auto const sleAcct = ctx_.view().peek(keylet::account(account));
if (!sleAcct)
WritableAccountRoot wrappedAcct(account, ctx_.view());
if (!wrappedAcct)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const sleBridge = peekBridge(ctx_.view(), bridgeSpec);
@@ -2019,11 +2015,10 @@ XChainCreateClaimID::doApply()
(*sleClaimID)[sfOwnerNode] = *page;
}
adjustOwnerCount(ctx_.view(), sleAcct, 1, ctx_.journal);
wrappedAcct.adjustOwnerCount(1, ctx_.journal);
ctx_.view().insert(sleClaimID);
ctx_.view().update(sleBridge);
ctx_.view().update(sleAcct);
return tesSUCCESS;
}
@@ -2161,8 +2156,8 @@ XChainCreateAccountCommit::doApply()
STAmount const reward = ctx_.tx[sfSignatureReward];
STXChainBridge const bridge = ctx_.tx[sfXChainBridge];
auto const sle = psb.peek(keylet::account(account));
if (!sle)
AccountRoot const acctRoot(account, psb);
if (!acctRoot)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const sleBridge = peekBridge(psb, bridge);
@@ -2173,7 +2168,7 @@ XChainCreateAccountCommit::doApply()
// Support dipping into reserves to pay the fee
TransferHelperSubmittingAccountInfo submittingAccountInfo{
account_, preFeeBalance_, (*sle)[sfBalance]};
accountID_, preFeeBalance_, (*acctRoot)[sfBalance]};
STAmount const toTransfer = amount + reward;
auto const thTer = transferHelper(
psb,

View File

@@ -1,3 +1,4 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
@@ -57,7 +58,7 @@ CheckCancel::doApply()
AccountID const srcId{sleCheck->getAccountID(sfAccount)};
AccountID const dstId{sleCheck->getAccountID(sfDestination)};
auto viewJ = ctx_.registry.getJournal("View");
auto viewJ = ctx_.registry.journal("View");
// If the check is not written to self (and it shouldn't be), remove the
// check from the destination account root.
@@ -84,8 +85,8 @@ CheckCancel::doApply()
}
// If we succeeded, update the check owner's reserve.
auto const sleSrc = view().peek(keylet::account(srcId));
adjustOwnerCount(view(), sleSrc, -1, viewJ);
WritableAccountRoot wrappedSrc(srcId, view());
wrappedSrc.adjustOwnerCount(-1, viewJ);
// Remove check from ledger.
view().erase(sleCheck);

View File

@@ -1,3 +1,4 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/scope.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
@@ -72,16 +73,16 @@ CheckCash::preclaim(PreclaimContext const& ctx)
// LCOV_EXCL_STOP
}
{
auto const sleSrc = ctx.view.read(keylet::account(srcId));
auto const sleDst = ctx.view.read(keylet::account(dstId));
if (!sleSrc || !sleDst)
AccountRoot const acctSrc(srcId, ctx.view);
AccountRoot const acctDst(dstId, ctx.view);
if (!acctSrc || !acctDst)
{
// If the check exists this should never occur.
JLOG(ctx.j.warn()) << "Malformed transaction: source or destination not in ledger";
return tecNO_ENTRY;
}
if (((sleDst->getFlags() & lsfRequireDestTag) != 0u) &&
if (((acctDst->getFlags() & lsfRequireDestTag) != 0u) &&
!sleCheck->isFieldPresent(sfDestinationTag))
{
// The tag is basically account-specific information we don't
@@ -147,15 +148,15 @@ CheckCash::preclaim(PreclaimContext const& ctx)
// An issuer can always accept their own currency.
if (!value.native() && (value.getIssuer() != dstId))
{
auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
if (!sleIssuer)
AccountRoot const acctIssuer(issuerId, ctx.view);
if (!acctIssuer)
{
JLOG(ctx.j.warn())
<< "Can't receive IOUs from non-existent issuer: " << to_string(issuerId);
return tecNO_ISSUER;
}
if ((sleIssuer->at(sfFlags) & lsfRequireAuth) != 0u)
if ((acctIssuer->at(sfFlags) & lsfRequireAuth) != 0u)
{
auto const sleTrustLine = ctx.view.read(keylet::line(dstId, issuerId, currency));
@@ -214,7 +215,7 @@ CheckCash::doApply()
}
AccountID const srcId{sleCheck->getAccountID(sfAccount)};
if (!psb.exists(keylet::account(srcId)) || !psb.exists(keylet::account(account_)))
if (!psb.exists(keylet::account(srcId)) || !psb.exists(keylet::account(accountID_)))
{
// LCOV_EXCL_START
JLOG(ctx_.journal.fatal()) << "Precheck did not verify source or destination's existence.";
@@ -232,10 +233,10 @@ CheckCash::doApply()
//
// If it is not a check to self (as should be the case), then there's
// work to do...
auto viewJ = ctx_.registry.getJournal("View");
auto viewJ = ctx_.registry.journal("View");
auto const optDeliverMin = ctx_.tx[~sfDeliverMin];
if (srcId != account_)
if (srcId != accountID_)
{
STAmount const sendMax = sleCheck->at(sfSendMax);
@@ -250,7 +251,8 @@ CheckCash::doApply()
// from src's directory, we allow them to send that additional
// incremental reserve amount in the transfer. Hence the -1
// argument.
STAmount const srcLiquid{xrpLiquid(psb, srcId, -1, viewJ)};
WritableAccountRoot wrappedSrc(srcId, psb);
STAmount const srcLiquid{wrappedSrc.xrpLiquid(-1, viewJ)};
// Now, how much do they need in order to be successful?
STAmount const xrpDeliver{
@@ -273,7 +275,7 @@ CheckCash::doApply()
}
// The source account has enough XRP so make the ledger change.
if (TER const ter{transferXRP(psb, srcId, account_, xrpDeliver, viewJ)};
if (TER const ter{transferXRP(psb, srcId, accountID_, xrpDeliver, viewJ)};
!isTesSuccess(ter))
{
// The transfer failed. Return the error code.
@@ -296,9 +298,9 @@ CheckCash::doApply()
// If a trust line does not exist yet create one.
Issue const& trustLineIssue = flowDeliver.issue();
AccountID const issuer = flowDeliver.getIssuer();
AccountID const truster = issuer == account_ ? srcId : account_;
AccountID const truster = issuer == accountID_ ? srcId : accountID_;
Keylet const trustLineKey = keylet::line(truster, trustLineIssue);
bool const destLow = issuer > account_;
bool const destLow = issuer > accountID_;
if (!psb.exists(trustLineKey))
{
@@ -309,10 +311,10 @@ CheckCash::doApply()
// a. this (destination) account and
// b. issuing account (not sending account).
auto const sleDst = psb.peek(keylet::account(account_));
WritableAccountRoot wrappedDst(accountID_, psb);
// Can the account cover the trust line's reserve?
if (std::uint32_t const ownerCount = {sleDst->at(sfOwnerCount)};
if (std::uint32_t const ownerCount = {wrappedDst->at(sfOwnerCount)};
preFeeBalance_ < psb.fees().accountReserve(ownerCount + 1))
{
JLOG(j_.trace()) << "Trust line does not exist. "
@@ -330,15 +332,15 @@ CheckCash::doApply()
psb, // payment sandbox
destLow, // is dest low?
issuer, // source
account_, // destination
accountID_, // destination
trustLineKey.key, // ledger index
sleDst, // Account to add to
wrappedDst, // Account to add to
false, // authorize account
(sleDst->getFlags() & lsfDefaultRipple) == 0,
(wrappedDst->getFlags() & lsfDefaultRipple) == 0,
false, // freeze trust line
false, // deep freeze trust line
initialBalance, // zero initial balance
Issue(currency, account_), // limit of zero
Issue(currency, accountID_), // limit of zero
0, // quality in
0, // quality out
viewJ); // journal
@@ -348,7 +350,7 @@ CheckCash::doApply()
}
// clang-format on
psb.update(sleDst);
wrappedDst.update();
// Note that we _don't_ need to be careful about destroying
// the trust line if the check cashing fails. The transaction
@@ -382,7 +384,7 @@ CheckCash::doApply()
psb,
flowDeliver,
srcId,
account_,
accountID_,
STPathSet{},
true, // default path
static_cast<bool>(optDeliverMin), // partial payment
@@ -419,9 +421,9 @@ CheckCash::doApply()
// Check was cashed. If not a self send (and it shouldn't be), remove
// check link from destination directory.
if (srcId != account_ &&
if (srcId != accountID_ &&
!psb.dirRemove(
keylet::ownerDir(account_), sleCheck->at(sfDestinationNode), sleCheck->key(), true))
keylet::ownerDir(accountID_), sleCheck->at(sfDestinationNode), sleCheck->key(), true))
{
// LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete check from destination.";
@@ -439,7 +441,8 @@ CheckCash::doApply()
}
// If we succeeded, update the check owner's reserve.
adjustOwnerCount(psb, psb.peek(keylet::account(srcId)), -1, viewJ);
WritableAccountRoot wrappedSrc(srcId, psb);
wrappedSrc.adjustOwnerCount(-1, viewJ);
// Remove check from ledger.
psb.erase(sleCheck);

View File

@@ -1,3 +1,4 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -52,14 +53,14 @@ TER
CheckCreate::preclaim(PreclaimContext const& ctx)
{
AccountID const dstId{ctx.tx[sfDestination]};
auto const sleDst = ctx.view.read(keylet::account(dstId));
if (!sleDst)
AccountRoot const acctDst(dstId, ctx.view);
if (!acctDst)
{
JLOG(ctx.j.warn()) << "Destination account does not exist.";
return tecNO_DST;
}
auto const flags = sleDst->getFlags();
auto const flags = acctDst->getFlags();
// Check if the destination has disallowed incoming checks
if ((flags & lsfDisallowIncomingCheck) != 0u)
@@ -69,7 +70,7 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
// because all writes to pseudo-account discriminator fields **are**
// amendment gated, hence the behaviour of this check will always match the
// currently active amendments.
if (isPseudoAccount(sleDst))
if (acctDst.isPseudoAccount())
return tecNO_PERMISSION;
if (((flags & lsfRequireDestTag) != 0u) && !ctx.tx.isFieldPresent(sfDestinationTag))
@@ -85,8 +86,9 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
if (!sendMax.native())
{
// The currency may not be globally frozen
AccountID const& issuerId{sendMax.getIssuer()};
if (isGlobalFrozen(ctx.view, issuerId))
AccountID const issuerId{sendMax.getIssuer()};
AccountRoot wrappedIssuer(issuerId, ctx.view);
if (wrappedIssuer.isGlobalFrozen())
{
JLOG(ctx.j.warn()) << "Creating a check for frozen asset";
return tecFROZEN;
@@ -132,15 +134,15 @@ CheckCreate::preclaim(PreclaimContext const& ctx)
TER
CheckCreate::doApply()
{
auto const sle = view().peek(keylet::account(account_));
if (!sle)
if (!account_)
return tefINTERNAL; // LCOV_EXCL_LINE
// A check counts against the reserve of the issuing account, but we
// check the starting balance because we want to allow dipping into the
// reserve to pay fees.
{
STAmount const reserve{view().fees().accountReserve(sle->getFieldU32(sfOwnerCount) + 1)};
STAmount const reserve{
view().fees().accountReserve(account_->getFieldU32(sfOwnerCount) + 1)};
if (preFeeBalance_ < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -149,10 +151,10 @@ CheckCreate::doApply()
// Note that we use the value from the sequence or ticket as the
// Check sequence. For more explanation see comments in SeqProxy.h.
std::uint32_t const seq = ctx_.tx.getSeqValue();
Keylet const checkKeylet = keylet::check(account_, seq);
Keylet const checkKeylet = keylet::check(accountID_, seq);
auto sleCheck = std::make_shared<SLE>(checkKeylet);
sleCheck->setAccountID(sfAccount, account_);
sleCheck->setAccountID(sfAccount, accountID_);
AccountID const dstAccountId = ctx_.tx[sfDestination];
sleCheck->setAccountID(sfDestination, dstAccountId);
sleCheck->setFieldU32(sfSequence, seq);
@@ -168,10 +170,10 @@ CheckCreate::doApply()
view().insert(sleCheck);
auto viewJ = ctx_.registry.getJournal("View");
auto viewJ = ctx_.registry.journal("View");
// If it's not a self-send (and it shouldn't be), add Check to the
// destination's owner directory.
if (dstAccountId != account_)
if (dstAccountId != accountID_)
{
auto const page = view().dirInsert(
keylet::ownerDir(dstAccountId), checkKeylet, describeOwnerDir(dstAccountId));
@@ -186,8 +188,8 @@ CheckCreate::doApply()
}
{
auto const page =
view().dirInsert(keylet::ownerDir(account_), checkKeylet, describeOwnerDir(account_));
auto const page = view().dirInsert(
keylet::ownerDir(accountID_), checkKeylet, describeOwnerDir(accountID_));
JLOG(j_.trace()) << "Adding Check to owner directory " << to_string(checkKeylet.key) << ": "
<< (page ? "success" : "failure");
@@ -198,7 +200,7 @@ CheckCreate::doApply()
sleCheck->setFieldU64(sfOwnerNode, *page);
}
// If we succeeded, the new entry counts against the creator's reserve.
adjustOwnerCount(view(), sle, 1, viewJ);
account_.adjustOwnerCount(1, viewJ);
return tesSUCCESS;
}

View File

@@ -76,21 +76,21 @@ CredentialAccept::doApply()
AccountID const issuer{ctx_.tx[sfIssuer]};
// Both exist as credential object exist itself (checked in preclaim)
auto const sleSubject = view().peek(keylet::account(account_));
auto const sleIssuer = view().peek(keylet::account(issuer));
WritableAccountRoot wrappedSubject(accountID_, view());
WritableAccountRoot wrappedIssuer(issuer, view());
if (!sleSubject || !sleIssuer)
if (!wrappedSubject || !wrappedIssuer)
return tefINTERNAL; // LCOV_EXCL_LINE
{
STAmount const reserve{
view().fees().accountReserve(sleSubject->getFieldU32(sfOwnerCount) + 1)};
view().fees().accountReserve(wrappedSubject->getFieldU32(sfOwnerCount) + 1)};
if (preFeeBalance_ < reserve)
return tecINSUFFICIENT_RESERVE;
}
auto const credType(ctx_.tx[sfCredentialType]);
Keylet const credentialKey = keylet::credential(account_, issuer, credType);
Keylet const credentialKey = keylet::credential(accountID_, issuer, credType);
auto const sleCred = view().peek(credentialKey); // Checked in preclaim()
if (checkExpired(sleCred, view().header().parentCloseTime))
@@ -104,8 +104,8 @@ CredentialAccept::doApply()
sleCred->setFieldU32(sfFlags, lsfAccepted);
view().update(sleCred);
adjustOwnerCount(view(), sleIssuer, -1, j_);
adjustOwnerCount(view(), sleSubject, 1, j_);
wrappedIssuer.adjustOwnerCount(-1, j_);
wrappedSubject.adjustOwnerCount(1, j_);
return tesSUCCESS;
}

View File

@@ -89,7 +89,7 @@ CredentialCreate::doApply()
{
auto const subject = ctx_.tx[sfSubject];
auto const credType(ctx_.tx[sfCredentialType]);
Keylet const credentialKey = keylet::credential(subject, account_, credType);
Keylet const credentialKey = keylet::credential(subject, accountID_, credType);
auto const sleCred = std::make_shared<SLE>(credentialKey);
if (!sleCred)
@@ -111,37 +111,37 @@ CredentialCreate::doApply()
sleCred->setFieldU32(sfExpiration, *optExp);
}
auto const sleIssuer = view().peek(keylet::account(account_));
if (!sleIssuer)
WritableAccountRoot wrappedIssuer(accountID_, view());
if (!wrappedIssuer)
return tefINTERNAL; // LCOV_EXCL_LINE
{
STAmount const reserve{
view().fees().accountReserve(sleIssuer->getFieldU32(sfOwnerCount) + 1)};
view().fees().accountReserve(wrappedIssuer->getFieldU32(sfOwnerCount) + 1)};
if (preFeeBalance_ < reserve)
return tecINSUFFICIENT_RESERVE;
}
sleCred->setAccountID(sfSubject, subject);
sleCred->setAccountID(sfIssuer, account_);
sleCred->setAccountID(sfIssuer, accountID_);
sleCred->setFieldVL(sfCredentialType, credType);
if (ctx_.tx.isFieldPresent(sfURI))
sleCred->setFieldVL(sfURI, ctx_.tx.getFieldVL(sfURI));
{
auto const page =
view().dirInsert(keylet::ownerDir(account_), credentialKey, describeOwnerDir(account_));
auto const page = view().dirInsert(
keylet::ownerDir(accountID_), credentialKey, describeOwnerDir(accountID_));
JLOG(j_.trace()) << "Adding Credential to owner directory " << to_string(credentialKey.key)
<< ": " << (page ? "success" : "failure");
if (!page)
return tecDIR_FULL;
sleCred->setFieldU64(sfIssuerNode, *page);
adjustOwnerCount(view(), sleIssuer, 1, j_);
wrappedIssuer.adjustOwnerCount(1, j_);
}
if (subject == account_)
if (subject == accountID_)
{
sleCred->setFieldU32(sfFlags, lsfAccepted);
}

View File

@@ -69,15 +69,15 @@ CredentialDelete::preclaim(PreclaimContext const& ctx)
TER
CredentialDelete::doApply()
{
auto const subject = ctx_.tx[~sfSubject].value_or(account_);
auto const issuer = ctx_.tx[~sfIssuer].value_or(account_);
auto const subject = ctx_.tx[~sfSubject].value_or(accountID_);
auto const issuer = ctx_.tx[~sfIssuer].value_or(accountID_);
auto const credType(ctx_.tx[sfCredentialType]);
auto const sleCred = view().peek(keylet::credential(subject, issuer, credType));
if (!sleCred)
return tefINTERNAL; // LCOV_EXCL_LINE
if ((subject != account_) && (issuer != account_) &&
if ((subject != accountID_) && (issuer != accountID_) &&
!checkExpired(sleCred, ctx_.view().header().parentCloseTime))
{
JLOG(j_.trace()) << "Can't delete non-expired credential.";

View File

@@ -56,12 +56,12 @@ DelegateSet::preclaim(PreclaimContext const& ctx)
TER
DelegateSet::doApply()
{
auto const sleOwner = ctx_.view().peek(keylet::account(account_));
if (!sleOwner)
WritableAccountRoot wrappedOwner(accountID_, ctx_.view());
if (!wrappedOwner)
return tefINTERNAL; // LCOV_EXCL_LINE
auto const& authAccount = ctx_.tx[sfAuthorize];
auto const delegateKey = keylet::delegate(account_, authAccount);
auto const delegateKey = keylet::delegate(accountID_, authAccount);
auto sle = ctx_.view().peek(delegateKey);
if (sle)
@@ -70,7 +70,7 @@ DelegateSet::doApply()
if (permissions.empty())
{
// if permissions array is empty, delete the ledger object.
return deleteDelegate(view(), sle, account_, j_);
return deleteDelegate(view(), sle, accountID_, j_);
}
sle->setFieldArray(sfPermissions, permissions);
@@ -83,25 +83,25 @@ DelegateSet::doApply()
return tecINTERNAL; // LCOV_EXCL_LINE
STAmount const reserve{
ctx_.view().fees().accountReserve(sleOwner->getFieldU32(sfOwnerCount) + 1)};
ctx_.view().fees().accountReserve(wrappedOwner->getFieldU32(sfOwnerCount) + 1)};
if (preFeeBalance_ < reserve)
return tecINSUFFICIENT_RESERVE;
sle = std::make_shared<SLE>(delegateKey);
sle->setAccountID(sfAccount, account_);
sle->setAccountID(sfAccount, accountID_);
sle->setAccountID(sfAuthorize, authAccount);
sle->setFieldArray(sfPermissions, permissions);
auto const page =
ctx_.view().dirInsert(keylet::ownerDir(account_), delegateKey, describeOwnerDir(account_));
auto const page = ctx_.view().dirInsert(
keylet::ownerDir(accountID_), delegateKey, describeOwnerDir(accountID_));
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE
(*sle)[sfOwnerNode] = *page;
ctx_.view().insert(sle);
adjustOwnerCount(ctx_.view(), sleOwner, 1, ctx_.journal);
wrappedOwner.adjustOwnerCount(1, ctx_.journal);
return tesSUCCESS;
}
@@ -124,11 +124,11 @@ DelegateSet::deleteDelegate(
// LCOV_EXCL_STOP
}
auto const sleOwner = view.peek(keylet::account(account));
if (!sleOwner)
WritableAccountRoot wrappedOwner(account, view);
if (!wrappedOwner)
return tecINTERNAL; // LCOV_EXCL_LINE
adjustOwnerCount(view, sleOwner, -1, j);
wrappedOwner.adjustOwnerCount(-1, j);
view.erase(sle);

View File

@@ -1,5 +1,6 @@
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AMMCore.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/TER.h>
@@ -90,7 +91,7 @@ AMMBid::preclaim(PreclaimContext const& ctx)
{
for (auto const& account : ctx.tx.getFieldArray(sfAuthAccounts))
{
if (!ctx.view.read(keylet::account(account[sfAccount])))
if (AccountRoot const acct(account[sfAccount], ctx.view); !acct)
{
JLOG(ctx.j.debug()) << "AMM Bid: Invalid Account.";
return terNO_ACCOUNT;
@@ -147,14 +148,14 @@ AMMBid::preclaim(PreclaimContext const& ctx)
}
static std::pair<TER, bool>
applyBid(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Journal j_)
applyBid(ApplyContext& ctx_, Sandbox& sb, AccountID const& accountID_, beast::Journal j_)
{
using namespace std::chrono;
auto const ammSle = sb.peek(keylet::amm(ctx_.tx[sfAsset], ctx_.tx[sfAsset2]));
if (!ammSle)
return {tecINTERNAL, false};
STAmount const lptAMMBalance = (*ammSle)[sfLPTokenBalance];
auto const lpTokens = ammLPHolds(sb, *ammSle, account_, ctx_.journal);
auto const lpTokens = ammLPHolds(sb, *ammSle, accountID_, ctx_.journal);
auto const& rules = ctx_.view().rules();
if (!rules.enabled(fixInnerObjTemplate))
{
@@ -186,11 +187,11 @@ applyBid(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jour
auto validOwner = [&](AccountID const& account) {
// Valid range is 0-19 but the tailing slot pays MinSlotPrice
// and doesn't refund so the check is < instead of <= to optimize.
return timeSlot && *timeSlot < tailingSlot && sb.read(keylet::account(account));
return timeSlot && *timeSlot < tailingSlot && AccountRoot(account, sb);
};
auto updateSlot = [&](std::uint32_t fee, Number const& minPrice, Number const& burn) -> TER {
auctionSlot.setAccountID(sfAccount, account_);
auctionSlot.setAccountID(sfAccount, accountID_);
auctionSlot.setFieldU32(sfExpiration, current + TOTAL_TIME_SLOT_SECS);
if (fee != 0)
{
@@ -221,7 +222,7 @@ applyBid(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jour
return tecINTERNAL;
// LCOV_EXCL_STOP
}
auto res = redeemIOU(sb, account_, saBurn, lpTokens.issue(), ctx_.journal);
auto res = redeemIOU(sb, accountID_, saBurn, lpTokens.issue(), ctx_.journal);
if (!isTesSuccess(res))
{
JLOG(ctx_.journal.debug()) << "AMM Bid: failed to redeem.";
@@ -319,7 +320,7 @@ applyBid(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jour
}
res = accountSend(
sb,
account_,
accountID_,
auctionSlot[sfAccount],
toSTAmount(lpTokens.issue(), refund),
ctx_.journal);
@@ -343,7 +344,7 @@ AMMBid::doApply()
// as we go on processing transactions.
Sandbox sb(&ctx_.view());
auto const result = applyBid(ctx_, sb, account_, j_);
auto const result = applyBid(ctx_, sb, accountID_, j_);
if (result.second)
sb.apply(ctx_.rawView());

View File

@@ -1,5 +1,6 @@
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/TxFlags.h>
@@ -72,11 +73,11 @@ AMMClawback::preclaim(PreclaimContext const& ctx)
{
auto const asset = ctx.tx[sfAsset].get<Issue>();
auto const asset2 = ctx.tx[sfAsset2].get<Issue>();
auto const sleIssuer = ctx.view.read(keylet::account(ctx.tx[sfAccount]));
if (!sleIssuer)
AccountRoot const acctIssuer(ctx.tx[sfAccount], ctx.view);
if (!acctIssuer)
return terNO_ACCOUNT; // LCOV_EXCL_LINE
if (!ctx.view.read(keylet::account(ctx.tx[sfHolder])))
if (AccountRoot const acctHolder(ctx.tx[sfHolder], ctx.view); !acctHolder)
return terNO_ACCOUNT;
auto const ammSle = ctx.view.read(keylet::amm(asset, asset2));
@@ -86,7 +87,7 @@ AMMClawback::preclaim(PreclaimContext const& ctx)
return terNO_AMM;
}
std::uint32_t const issuerFlagsIn = sleIssuer->getFieldU32(sfFlags);
std::uint32_t const issuerFlagsIn = acctIssuer->getFieldU32(sfFlags);
// If AllowTrustLineClawback is not set or NoFreeze is set, return no
// permission
@@ -123,8 +124,8 @@ AMMClawback::applyGuts(Sandbox& sb)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const ammAccount = (*ammSle)[sfAccount];
auto const accountSle = sb.read(keylet::account(ammAccount));
if (!accountSle)
AccountRoot const ammAcct(ammAccount, sb);
if (!ammAcct)
return tecINTERNAL; // LCOV_EXCL_LINE
if (sb.rules().enabled(fixAMMClawbackRounding))

View File

@@ -97,8 +97,9 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
if (isXRP(issue))
return false;
if (auto const issuerAccount = view.read(keylet::account(issue.account)))
return (issuerAccount->getFlags() & lsfDefaultRipple) == 0;
AccountRoot const issuerAcct(issue.account, view);
if (issuerAcct)
return (issuerAcct->getFlags() & lsfDefaultRipple) == 0;
return false;
};
@@ -110,7 +111,8 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
}
// Check the reserve for LPToken trustline
STAmount const xrpBalance = xrpLiquid(ctx.view, accountID, 1, ctx.j);
AccountRoot wrappedAcct(accountID, ctx.view);
STAmount const xrpBalance = wrappedAcct.xrpLiquid(1, ctx.j);
// Insufficient reserve
if (xrpBalance <= beast::zero)
{
@@ -134,8 +136,9 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
}
auto isLPToken = [&](STAmount const& amount) -> bool {
if (auto const sle = ctx.view.read(keylet::account(amount.issue().account)))
return sle->isFieldPresent(sfAMMID);
AccountRoot const acct(amount.issue().account, ctx.view);
if (acct)
return acct->isFieldPresent(sfAMMID);
return false;
};
@@ -164,10 +167,10 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
auto clawbackDisabled = [&](Issue const& issue) -> TER {
if (isXRP(issue))
return tesSUCCESS;
auto const sle = ctx.view.read(keylet::account(issue.account));
if (!sle)
AccountRoot const acct(issue.account, ctx.view);
if (!acct)
return tecINTERNAL; // LCOV_EXCL_LINE
if (sle->getFlags() & lsfAllowTrustLineClawback)
if (acct->getFlags() & lsfAllowTrustLineClawback)
return tecNO_PERMISSION;
return tesSUCCESS;
};
@@ -178,7 +181,7 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
}
static std::pair<TER, bool>
applyCreate(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Journal j_)
applyCreate(ApplyContext& ctx_, Sandbox& sb, AccountID const& accountID_, beast::Journal j_)
{
auto const amount = ctx_.tx[sfAmount];
auto const amount2 = ctx_.tx[sfAmount2];
@@ -221,7 +224,7 @@ applyCreate(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::J
ammSle->setFieldIssue(sfAsset, STIssue{sfAsset, issue1});
ammSle->setFieldIssue(sfAsset2, STIssue{sfAsset2, issue2});
// AMM creator gets the auction slot and the voting slot.
initializeFeeAuctionVote(ctx_.view(), ammSle, account_, lptIss, ctx_.tx[sfTradingFee]);
initializeFeeAuctionVote(ctx_.view(), ammSle, accountID_, lptIss, ctx_.tx[sfTradingFee]);
// Add owner directory to link the root account and AMM object.
if (auto ter = dirLink(sb, accountId, ammSle); ter)
@@ -232,7 +235,7 @@ applyCreate(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::J
sb.insert(ammSle);
// Send LPT to LP.
auto res = accountSend(sb, accountId, account_, lpTokens, ctx_.journal);
auto res = accountSend(sb, accountId, accountID_, lpTokens, ctx_.journal);
if (!isTesSuccess(res))
{
JLOG(j_.debug()) << "AMM Instance: failed to send LPT " << lpTokens;
@@ -241,7 +244,7 @@ applyCreate(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::J
auto sendAndTrustSet = [&](STAmount const& amount) -> TER {
if (auto const res =
accountSend(sb, account_, accountId, amount, ctx_.journal, WaiveTransferFee::Yes))
accountSend(sb, accountID_, accountId, amount, ctx_.journal, WaiveTransferFee::Yes))
return res;
// Set AMM flag on AMM trustline
if (!isXRP(amount))
@@ -296,7 +299,7 @@ AMMCreate::doApply()
// as we go on processing transactions.
Sandbox sb(&ctx_.view());
auto const result = applyCreate(ctx_, sb, account_, j_);
auto const result = applyCreate(ctx_, sb, accountID_, j_);
if (result.second)
sb.apply(ctx_.rawView());

View File

@@ -187,6 +187,7 @@ AMMDeposit::preclaim(PreclaimContext const& ctx)
// Have to check again in deposit() because
// amounts might be derived based on tokens or
// limits.
AccountRoot wrappedAcct(accountID, ctx.view);
auto balance = [&](auto const& deposit) -> TER {
if (isXRP(deposit))
{
@@ -194,7 +195,7 @@ AMMDeposit::preclaim(PreclaimContext const& ctx)
// Adjust the reserve if LP doesn't have LPToken trustline
auto const sle =
ctx.view.read(keylet::line(accountID, lpIssue.account, lpIssue.currency));
if (xrpLiquid(ctx.view, accountID, !sle, ctx.j) >= deposit)
if (wrappedAcct.xrpLiquid(!sle, ctx.j) >= deposit)
return TER(tesSUCCESS);
if (sle)
return tecUNFUNDED_AMM;
@@ -311,7 +312,7 @@ AMMDeposit::preclaim(PreclaimContext const& ctx)
// We checked above but need to check again if depositing IOU only.
if (ammLPHolds(ctx.view, *ammSle, accountID, ctx.j) == beast::zero)
{
STAmount const xrpBalance = xrpLiquid(ctx.view, accountID, 1, ctx.j);
STAmount const xrpBalance = wrappedAcct.xrpLiquid(1, ctx.j);
// Insufficient reserve
if (xrpBalance <= beast::zero)
{
@@ -347,7 +348,7 @@ AMMDeposit::applyGuts(Sandbox& sb)
auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected;
auto const tfee = (lptAMMBalance == beast::zero)
? ctx_.tx[~sfTradingFee].value_or(0)
: getTradingFee(ctx_.view(), *ammSle, account_);
: getTradingFee(ctx_.view(), *ammSle, accountID_);
auto const subTxType = ctx_.tx.getFlags() & tfDepositSubTx;
@@ -418,7 +419,7 @@ AMMDeposit::applyGuts(Sandbox& sb)
// LP depositing into AMM empty state gets the auction slot
// and the voting
if (lptAMMBalance == beast::zero)
initializeFeeAuctionVote(sb, ammSle, account_, lptAMMBalance.issue(), tfee);
initializeFeeAuctionVote(sb, ammSle, accountID_, lptAMMBalance.issue(), tfee);
sb.update(ammSle);
}
@@ -463,15 +464,15 @@ AMMDeposit::deposit(
{
auto const& lpIssue = lpTokensDeposit.issue();
// Adjust the reserve if LP doesn't have LPToken trustline
auto const sle = view.read(keylet::line(account_, lpIssue.account, lpIssue.currency));
if (xrpLiquid(view, account_, !sle, j_) >= depositAmount)
auto const sle = view.read(keylet::line(accountID_, lpIssue.account, lpIssue.currency));
if (account_.xrpLiquid(!sle, j_) >= depositAmount)
return tesSUCCESS;
}
else if (
account_ == depositAmount.issue().account ||
accountID_ == depositAmount.issue().account ||
accountHolds(
view,
account_,
accountID_,
depositAmount.issue(),
FreezeHandling::fhIGNORE_FREEZE,
ctx_.journal) >= depositAmount)
@@ -518,7 +519,7 @@ AMMDeposit::deposit(
}
auto res = accountSend(
view, account_, ammAccount, amountDepositActual, ctx_.journal, WaiveTransferFee::Yes);
view, accountID_, ammAccount, amountDepositActual, ctx_.journal, WaiveTransferFee::Yes);
if (!isTesSuccess(res))
{
JLOG(ctx_.journal.debug()) << "AMM Deposit: failed to deposit " << amountDepositActual;
@@ -537,7 +538,12 @@ AMMDeposit::deposit(
}
res = accountSend(
view, account_, ammAccount, *amount2DepositActual, ctx_.journal, WaiveTransferFee::Yes);
view,
accountID_,
ammAccount,
*amount2DepositActual,
ctx_.journal,
WaiveTransferFee::Yes);
if (!isTesSuccess(res))
{
JLOG(ctx_.journal.debug())
@@ -547,7 +553,7 @@ AMMDeposit::deposit(
}
// Deposit LP tokens
res = accountSend(view, ammAccount, account_, lpTokensDepositActual, ctx_.journal);
res = accountSend(view, ammAccount, accountID_, lpTokensDepositActual, ctx_.journal);
if (!isTesSuccess(res))
{
JLOG(ctx_.journal.debug()) << "AMM Deposit: failed to deposit LPTokens";

View File

@@ -1,6 +1,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AMMCore.h>
#include <xrpl/protocol/STObject.h>
#include <xrpl/tx/transactors/dex/AMMHelpers.h>
@@ -184,8 +185,8 @@ ammAccountHolds(ReadView const& view, AccountID const& ammAccountID, Issue const
{
if (isXRP(issue))
{
if (auto const sle = view.read(keylet::account(ammAccountID)))
return (*sle)[sfBalance];
if (AccountRoot const acct(ammAccountID, view); acct)
return (*acct)[sfBalance];
}
else if (
auto const sle = view.read(keylet::line(ammAccountID, issue.account, issue.currency));
@@ -255,8 +256,8 @@ deleteAMMAccount(Sandbox& sb, Issue const& asset, Issue const& asset2, beast::Jo
}
auto const ammAccountID = (*ammSle)[sfAccount];
auto sleAMMRoot = sb.peek(keylet::account(ammAccountID));
if (!sleAMMRoot)
WritableAccountRoot ammRoot(ammAccountID, sb);
if (!ammRoot)
{
// LCOV_EXCL_START
JLOG(j.error()) << "deleteAMMAccount: AMM account does not exist "
@@ -287,7 +288,7 @@ deleteAMMAccount(Sandbox& sb, Issue const& asset, Issue const& asset2, beast::Jo
}
sb.erase(ammSle);
sb.erase(sleAMMRoot);
ammRoot.erase();
return tesSUCCESS;
}

View File

@@ -56,14 +56,14 @@ AMMVote::preclaim(PreclaimContext const& ctx)
}
static std::pair<TER, bool>
applyVote(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Journal j_)
applyVote(ApplyContext& ctx_, Sandbox& sb, AccountID const& accountID_, beast::Journal j_)
{
auto const feeNew = ctx_.tx[sfTradingFee];
auto ammSle = sb.peek(keylet::amm(ctx_.tx[sfAsset], ctx_.tx[sfAsset2]));
if (!ammSle)
return {tecINTERNAL, false};
STAmount const lptAMMBalance = (*ammSle)[sfLPTokenBalance];
auto const lpTokensNew = ammLPHolds(sb, *ammSle, account_, ctx_.journal);
auto const lpTokensNew = ammLPHolds(sb, *ammSle, accountID_, ctx_.journal);
std::optional<STAmount> minTokens;
std::size_t minPos{0};
AccountID minAccount{0};
@@ -90,7 +90,7 @@ applyVote(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jou
auto feeVal = entry[sfTradingFee];
STObject newEntry = STObject::makeInnerObject(sfVoteEntry);
// The account already has the vote entry.
if (account == account_)
if (account == accountID_)
{
lpTokens = lpTokensNew;
feeVal = feeNew;
@@ -132,7 +132,7 @@ applyVote(ApplyContext& ctx_, Sandbox& sb, AccountID const& account_, beast::Jou
sfVoteWeight,
static_cast<std::int64_t>(
Number(lpTokensNew) * VOTE_WEIGHT_SCALE_FACTOR / lptAMMBalance));
newEntry.setAccountID(sfAccount, account_);
newEntry.setAccountID(sfAccount, accountID_);
num += feeNew * lpTokensNew;
den += lpTokensNew;
if (minPos)
@@ -214,7 +214,7 @@ AMMVote::doApply()
// as we go on processing transactions.
Sandbox sb(&ctx_.view());
auto const result = applyVote(ctx_, sb, account_, j_);
auto const result = applyVote(ctx_, sb, accountID_, j_);
if (result.second)
sb.apply(ctx_.rawView());

View File

@@ -1,5 +1,6 @@
#include <xrpl/basics/Number.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/AMMCore.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/dex/AMMHelpers.h>
@@ -269,8 +270,8 @@ AMMWithdraw::applyGuts(Sandbox& sb)
if (!ammSle)
return {tecINTERNAL, false}; // LCOV_EXCL_LINE
auto const ammAccountID = (*ammSle)[sfAccount];
auto const accountSle = sb.read(keylet::account(ammAccountID));
if (!accountSle)
AccountRoot const ammAcct(ammAccountID, sb);
if (!ammAcct)
return {tecINTERNAL, false}; // LCOV_EXCL_LINE
auto const lpTokens = ammLPHolds(ctx_.view(), *ammSle, ctx_.tx[sfAccount], ctx_.journal);
auto const lpTokensWithdraw =
@@ -280,11 +281,11 @@ AMMWithdraw::applyGuts(Sandbox& sb)
// might not match the LP's trustline balance
if (sb.rules().enabled(fixAMMv1_1))
{
if (auto const res = verifyAndAdjustLPTokenBalance(sb, lpTokens, ammSle, account_); !res)
if (auto const res = verifyAndAdjustLPTokenBalance(sb, lpTokens, ammSle, accountID_); !res)
return {res.error(), false};
}
auto const tfee = getTradingFee(ctx_.view(), *ammSle, account_);
auto const tfee = getTradingFee(ctx_.view(), *ammSle, accountID_);
auto const expected = ammHolds(
sb,
@@ -413,7 +414,7 @@ AMMWithdraw::withdraw(
view,
ammSle,
ammAccount,
account_,
accountID_,
amountBalance,
amountWithdraw,
amount2Withdraw,
@@ -532,11 +533,11 @@ AMMWithdraw::withdraw(
return tesSUCCESS;
if (!view.exists(keylet::line(account, issue)))
{
auto const sleAccount = view.read(keylet::account(account));
if (!sleAccount)
AccountRoot const acct(account, view);
if (!acct)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const balance = (*sleAccount)[sfBalance].xrp();
std::uint32_t const ownerCount = sleAccount->at(sfOwnerCount);
auto const balance = acct->getFieldAmount(sfBalance).xrp();
std::uint32_t const ownerCount = acct->at(sfOwnerCount);
// See also TrustSet::doApply()
XRPAmount const reserve(
@@ -628,7 +629,7 @@ AMMWithdraw::equalWithdrawTokens(
std::tie(ter, newLPTokenBalance, std::ignore, std::ignore) = equalWithdrawTokens(
view,
ammSle,
account_,
accountID_,
ammAccount,
amountBalance,
amount2Balance,

View File

@@ -1,4 +1,6 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/OfferHelpers.h>
#include <xrpl/protocol/st.h>
#include <xrpl/tx/transactors/dex/OfferCancel.h>
@@ -25,11 +27,11 @@ OfferCancel::preclaim(PreclaimContext const& ctx)
auto const id = ctx.tx[sfAccount];
auto const offerSequence = ctx.tx[sfOfferSequence];
auto const sle = ctx.view.read(keylet::account(id));
if (!sle)
AccountRoot const acct(id, ctx.view);
if (!acct)
return terNO_ACCOUNT;
if ((*sle)[sfSequence] <= offerSequence)
if (acct->getFieldU32(sfSequence) <= offerSequence)
{
JLOG(ctx.j.trace()) << "Malformed transaction: "
<< "Sequence " << offerSequence << " is invalid.";
@@ -46,14 +48,13 @@ OfferCancel::doApply()
{
auto const offerSequence = ctx_.tx[sfOfferSequence];
auto const sle = view().read(keylet::account(account_));
if (!sle)
if (AccountRoot const acct(accountID_, view()); !acct)
return tefINTERNAL; // LCOV_EXCL_LINE
if (auto sleOffer = view().peek(keylet::offer(account_, offerSequence)))
if (auto sleOffer = view().peek(keylet::offer(accountID_, offerSequence)))
{
JLOG(j_.debug()) << "Trying to cancel offer #" << offerSequence;
return offerDelete(view(), sleOffer, ctx_.registry.getJournal("View"));
return offerDelete(view(), sleOffer, ctx_.registry.journal("View"));
}
JLOG(j_.debug()) << "Offer #" << offerSequence << " can't be found.";

View File

@@ -138,15 +138,17 @@ OfferCreate::preclaim(PreclaimContext const& ctx)
auto const cancelSequence = ctx.tx[~sfOfferSequence];
auto const sleCreator = ctx.view.read(keylet::account(id));
if (!sleCreator)
AccountRoot const acctCreator(id, ctx.view);
if (!acctCreator)
return terNO_ACCOUNT;
std::uint32_t const uAccountSequence = sleCreator->getFieldU32(sfSequence);
std::uint32_t const uAccountSequence = acctCreator->getFieldU32(sfSequence);
auto viewJ = ctx.registry.getJournal("View");
auto viewJ = ctx.registry.journal("View");
AccountRoot wrappedPays(uPaysIssuerID, ctx.view);
AccountRoot wrappedGets(uGetsIssuerID, ctx.view);
if (isGlobalFrozen(ctx.view, uPaysIssuerID) || isGlobalFrozen(ctx.view, uGetsIssuerID))
if (wrappedPays.isGlobalFrozen() || wrappedGets.isGlobalFrozen())
{
JLOG(ctx.j.debug()) << "Offer involves frozen asset";
return tecFROZEN;
@@ -205,9 +207,9 @@ OfferCreate::checkAcceptAsset(
// Only valid for custom currencies
XRPL_ASSERT(!isXRP(issue.currency), "xrpl::OfferCreate::checkAcceptAsset : input is not XRP");
auto const issuerAccount = view.read(keylet::account(issue.account));
AccountRoot const issuerAcct(issue.account, view);
if (!issuerAccount)
if (!issuerAcct)
{
JLOG(j.debug()) << "delay: can't receive IOUs from non-existent issuer: "
<< to_string(issue.account);
@@ -221,7 +223,7 @@ OfferCreate::checkAcceptAsset(
if (issue.account == id)
return tesSUCCESS;
if (((*issuerAccount)[sfFlags] & lsfRequireAuth) != 0u)
if ((issuerAcct->getFlags() & lsfRequireAuth) != 0u)
{
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
@@ -281,7 +283,7 @@ OfferCreate::flowCross(
// cause a user's available balance to go to 0 (by causing it to dip
// below the reserve) so we check this case again.
STAmount const inStartBalance =
accountFunds(psb, account_, takerAmount.in, fhZERO_IF_FROZEN, j_);
accountFunds(psb, accountID_, takerAmount.in, fhZERO_IF_FROZEN, j_);
if (inStartBalance <= beast::zero)
{
// The account balance can't cover even part of the offer.
@@ -294,9 +296,10 @@ OfferCreate::flowCross(
// offer taker. Set sendMax to allow for the gateway's cut.
Rate gatewayXferRate{QUALITY_ONE};
STAmount sendMax = takerAmount.in;
if (!sendMax.native() && (account_ != sendMax.getIssuer()))
if (!sendMax.native() && (accountID_ != sendMax.getIssuer()))
{
gatewayXferRate = transferRate(psb, sendMax.getIssuer());
WritableAccountRoot wrappedAcct(sendMax.getIssuer(), psb);
gatewayXferRate = wrappedAcct.transferRate();
if (gatewayXferRate.value != QUALITY_ONE)
{
sendMax =
@@ -357,8 +360,8 @@ OfferCreate::flowCross(
auto const result = flow(
psb,
deliver,
account_,
account_,
accountID_,
accountID_,
paths,
true, // default path
(txFlags & tfFillOrKill) == 0u, // partial payment
@@ -383,7 +386,7 @@ OfferCreate::flowCross(
if (isTesSuccess(result.result()))
{
STAmount const takerInBalance =
accountFunds(psb, account_, takerAmount.in, fhZERO_IF_FROZEN, j_);
accountFunds(psb, accountID_, takerAmount.in, fhZERO_IF_FROZEN, j_);
if (takerInBalance <= beast::zero)
{
@@ -536,14 +539,14 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
// end up on the books.
auto uRate = getRate(saTakerGets, saTakerPays);
auto viewJ = ctx_.registry.getJournal("View");
auto viewJ = ctx_.registry.journal("View");
TER result = tesSUCCESS;
// Process a cancellation request that's passed along with an offer.
if (cancelSequence)
{
auto const sleCancel = sb.peek(keylet::offer(account_, *cancelSequence));
auto const sleCancel = sb.peek(keylet::offer(accountID_, *cancelSequence));
// It's not an error to not find the offer to cancel: it might have
// been consumed or removed. If it is found, however, it's an error
@@ -576,15 +579,15 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
std::uint8_t uTickSize = Quality::maxTickSize;
if (!isXRP(uPaysIssuerID))
{
auto const sle = sb.read(keylet::account(uPaysIssuerID));
if (sle && sle->isFieldPresent(sfTickSize))
uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
AccountRoot const acctPays(uPaysIssuerID, sb);
if (acctPays && acctPays->isFieldPresent(sfTickSize))
uTickSize = std::min(uTickSize, (*acctPays)[sfTickSize]);
}
if (!isXRP(uGetsIssuerID))
{
auto const sle = sb.read(keylet::account(uGetsIssuerID));
if (sle && sle->isFieldPresent(sfTickSize))
uTickSize = std::min(uTickSize, (*sle)[sfTickSize]);
AccountRoot const acctGets(uGetsIssuerID, sb);
if (acctGets && acctGets->isFieldPresent(sfTickSize))
uTickSize = std::min(uTickSize, (*acctGets)[sfTickSize]);
}
if (uTickSize < Quality::maxTickSize)
{
@@ -732,12 +735,12 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
return {tesSUCCESS, true};
}
auto const sleCreator = sb.peek(keylet::account(account_));
if (!sleCreator)
WritableAccountRoot wrappedCreator(accountID_, sb);
if (!wrappedCreator)
return {tefINTERNAL, false};
{
XRPAmount reserve = sb.fees().accountReserve(sleCreator->getFieldU32(sfOwnerCount) + 1);
XRPAmount reserve = sb.fees().accountReserve(wrappedCreator->getFieldU32(sfOwnerCount) + 1);
if (preFeeBalance_ < reserve)
{
@@ -757,11 +760,11 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
}
// We need to place the remainder of the offer into its order book.
auto const offer_index = keylet::offer(account_, offerSequence);
auto const offer_index = keylet::offer(accountID_, offerSequence);
// Add offer to owner's directory.
auto const ownerNode =
sb.dirInsert(keylet::ownerDir(account_), offer_index, describeOwnerDir(account_));
sb.dirInsert(keylet::ownerDir(accountID_), offer_index, describeOwnerDir(accountID_));
if (!ownerNode)
{
@@ -772,7 +775,7 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
}
// Update owner count.
adjustOwnerCount(sb, sleCreator, 1, viewJ);
wrappedCreator.adjustOwnerCount(1, viewJ);
JLOG(j_.trace()) << "adding to book: " << to_string(saTakerPays.issue()) << " : "
<< to_string(saTakerGets.issue())
@@ -818,7 +821,7 @@ OfferCreate::applyGuts(Sandbox& sb, Sandbox& sbCancel)
}
auto sleOffer = std::make_shared<SLE>(offer_index);
sleOffer->setAccountID(sfAccount, account_);
sleOffer->setAccountID(sfAccount, accountID_);
sleOffer->setFieldU32(sfSequence, offerSequence);
sleOffer->setFieldH256(sfBookDirectory, dir.key);
sleOffer->setFieldAmount(sfTakerPays, saTakerPays);

View File

@@ -38,12 +38,12 @@ DIDDelete::deleteSLE(
// LCOV_EXCL_STOP
}
auto const sleOwner = view.peek(keylet::account(owner));
if (!sleOwner)
WritableAccountRoot wrappedOwner(owner, view);
if (!wrappedOwner)
return tecINTERNAL; // LCOV_EXCL_LINE
adjustOwnerCount(view, sleOwner, -1, j);
view.update(sleOwner);
wrappedOwner.adjustOwnerCount(-1, j);
wrappedOwner.update();
// Remove object from ledger
view.erase(sle);
@@ -53,7 +53,7 @@ DIDDelete::deleteSLE(
TER
DIDDelete::doApply()
{
return deleteSLE(ctx_, keylet::did(account_), account_);
return deleteSLE(ctx_, keylet::did(accountID_), accountID_);
}
} // namespace xrpl

View File

@@ -51,14 +51,14 @@ DIDSet::preflight(PreflightContext const& ctx)
static TER
addSLE(ApplyContext& ctx, std::shared_ptr<SLE> const& sle, AccountID const& owner)
{
auto const sleAccount = ctx.view().peek(keylet::account(owner));
if (!sleAccount)
WritableAccountRoot wrappedAcct(owner, ctx.view());
if (!wrappedAcct)
return tefINTERNAL; // LCOV_EXCL_LINE
// Check reserve availability for new object creation
{
auto const balance = STAmount((*sleAccount)[sfBalance]).xrp();
auto const reserve = ctx.view().fees().accountReserve((*sleAccount)[sfOwnerCount] + 1);
auto const balance = STAmount((*wrappedAcct)[sfBalance]).xrp();
auto const reserve = ctx.view().fees().accountReserve((*wrappedAcct)[sfOwnerCount] + 1);
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -75,8 +75,8 @@ addSLE(ApplyContext& ctx, std::shared_ptr<SLE> const& sle, AccountID const& owne
return tecDIR_FULL; // LCOV_EXCL_LINE
(*sle)[sfOwnerNode] = *page;
}
adjustOwnerCount(ctx.view(), sleAccount, 1, ctx.journal);
ctx.view().update(sleAccount);
wrappedAcct.adjustOwnerCount(1, ctx.journal);
wrappedAcct.update();
return tesSUCCESS;
}
@@ -85,7 +85,7 @@ TER
DIDSet::doApply()
{
// Edit ledger object if it already exists
Keylet const didKeylet = keylet::did(account_);
Keylet const didKeylet = keylet::did(accountID_);
if (auto const sleDID = ctx_.view().peek(didKeylet))
{
auto update = [&](auto const& sField) {
@@ -116,7 +116,7 @@ DIDSet::doApply()
// Create new ledger object otherwise
auto const sleDID = std::make_shared<SLE>(didKeylet);
(*sleDID)[sfAccount] = account_;
(*sleDID)[sfAccount] = accountID_;
auto set = [&](auto const& sField) {
if (auto const field = ctx_.tx[~sField]; field && !field->empty())
@@ -132,7 +132,7 @@ DIDSet::doApply()
return tecEMPTY_DID;
}
return addSLE(ctx_, sleDID, account_);
return addSLE(ctx_, sleDID, accountID_);
}
} // namespace xrpl

View File

@@ -149,13 +149,13 @@ EscrowCancel::doApply()
}
}
auto const sle = ctx_.view().peek(keylet::account(account));
WritableAccountRoot wrappedAcct(account, ctx_.view());
STAmount const amount = slep->getFieldAmount(sfAmount);
// Transfer amount back to the owner
if (isXRP(amount))
{
(*sle)[sfBalance] = (*sle)[sfBalance] + amount;
(*wrappedAcct)[sfBalance] = (*wrappedAcct)[sfBalance] + amount;
}
else
{
@@ -163,13 +163,13 @@ EscrowCancel::doApply()
return temDISABLED; // LCOV_EXCL_LINE
auto const issuer = amount.getIssuer();
bool const createAsset = account == account_;
bool const createAsset = account == accountID_;
if (auto const ret = std::visit(
[&]<typename T>(T const&) {
return escrowUnlockApplyHelper<T>(
ctx_.view(),
parityRate,
slep,
slep, // Bug: should be wrappedAcct, will be fixed by amendment in #6171
preFeeBalance_,
amount,
issuer,
@@ -195,8 +195,8 @@ EscrowCancel::doApply()
}
}
adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
ctx_.view().update(sle);
wrappedAcct.adjustOwnerCount(-1, ctx_.journal);
wrappedAcct.update();
// Remove escrow from ledger
ctx_.view().erase(slep);

View File

@@ -169,10 +169,10 @@ escrowCreatePreclaimHelper<Issue>(
return tecNO_PERMISSION;
// If the lsfAllowTrustLineLocking is not enabled, return tecNO_PERMISSION
auto const sleIssuer = ctx.view.read(keylet::account(issuer));
if (!sleIssuer)
AccountRoot const acctIssuer(issuer, ctx.view);
if (!acctIssuer)
return tecNO_ISSUER;
if (!sleIssuer->isFlag(lsfAllowTrustLineLocking))
if (!acctIssuer->isFlag(lsfAllowTrustLineLocking))
return tecNO_PERMISSION;
// If the account does not have a trustline to the issuer, return tecNO_LINE
@@ -304,15 +304,15 @@ EscrowCreate::preclaim(PreclaimContext const& ctx)
AccountID const account{ctx.tx[sfAccount]};
AccountID const dest{ctx.tx[sfDestination]};
auto const sled = ctx.view.read(keylet::account(dest));
if (!sled)
AccountRoot const acctDest(dest, ctx.view);
if (!acctDest)
return tecNO_DST;
// Pseudo-accounts cannot receive escrow. Note, this is not amendment-gated
// because all writes to pseudo-account discriminator fields **are**
// amendment gated, hence the behaviour of this check will always match the
// currently active amendments.
if (isPseudoAccount(sled))
if (acctDest.isPseudoAccount())
return tecNO_PERMISSION;
if (!isXRP(amount))
@@ -389,16 +389,15 @@ EscrowCreate::doApply()
if (ctx_.tx[~sfFinishAfter] && after(closeTime, ctx_.tx[sfFinishAfter]))
return tecNO_PERMISSION;
auto const sle = ctx_.view().peek(keylet::account(account_));
if (!sle)
if (!account_)
return tefINTERNAL; // LCOV_EXCL_LINE
// Check reserve and funds availability
STAmount const amount{ctx_.tx[sfAmount]};
auto const reserve = ctx_.view().fees().accountReserve((*sle)[sfOwnerCount] + 1);
auto const reserve = ctx_.view().fees().accountReserve((*account_)[sfOwnerCount] + 1);
auto const balance = sle->getFieldAmount(sfBalance).xrp();
auto const balance = account_->getFieldAmount(sfBalance).xrp();
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -411,19 +410,19 @@ EscrowCreate::doApply()
// Check destination account
{
auto const sled = ctx_.view().read(keylet::account(ctx_.tx[sfDestination]));
if (!sled)
AccountRoot const acctDest(ctx_.tx[sfDestination], ctx_.view());
if (!acctDest)
return tecNO_DST; // LCOV_EXCL_LINE
if ((((*sled)[sfFlags] & lsfRequireDestTag) != 0u) && !ctx_.tx[~sfDestinationTag])
if (((acctDest->getFlags() & lsfRequireDestTag) != 0u) && !ctx_.tx[~sfDestinationTag])
return tecDST_TAG_NEEDED;
}
// Create escrow in ledger. Note that we we use the value from the
// sequence or ticket. For more explanation see comments in SeqProxy.h.
Keylet const escrowKeylet = keylet::escrow(account_, ctx_.tx.getSeqValue());
Keylet const escrowKeylet = keylet::escrow(accountID_, ctx_.tx.getSeqValue());
auto const slep = std::make_shared<SLE>(escrowKeylet);
(*slep)[sfAmount] = amount;
(*slep)[sfAccount] = account_;
(*slep)[sfAccount] = accountID_;
(*slep)[~sfCondition] = ctx_.tx[~sfCondition];
(*slep)[~sfSourceTag] = ctx_.tx[~sfSourceTag];
(*slep)[sfDestination] = ctx_.tx[sfDestination];
@@ -448,7 +447,7 @@ EscrowCreate::doApply()
// Add escrow to sender's owner directory
{
auto page = ctx_.view().dirInsert(
keylet::ownerDir(account_), escrowKeylet, describeOwnerDir(account_));
keylet::ownerDir(accountID_), escrowKeylet, describeOwnerDir(accountID_));
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE
(*slep)[sfOwnerNode] = *page;
@@ -456,7 +455,7 @@ EscrowCreate::doApply()
// If it's not a self-send, add escrow to recipient's owner directory.
AccountID const dest = ctx_.tx[sfDestination];
if (dest != account_)
if (dest != accountID_)
{
auto page =
ctx_.view().dirInsert(keylet::ownerDir(dest), escrowKeylet, describeOwnerDir(dest));
@@ -469,7 +468,7 @@ EscrowCreate::doApply()
// track the total locked balance. For MPT, this isn't necessary because the
// locked balance is already stored directly in the MPTokenIssuance object.
AccountID const issuer = amount.getIssuer();
if (!isXRP(amount) && issuer != account_ && issuer != dest && !amount.holds<MPTIssue>())
if (!isXRP(amount) && issuer != accountID_ && issuer != dest && !amount.holds<MPTIssue>())
{
auto page =
ctx_.view().dirInsert(keylet::ownerDir(issuer), escrowKeylet, describeOwnerDir(issuer));
@@ -481,13 +480,13 @@ EscrowCreate::doApply()
// Deduct owner's balance
if (isXRP(amount))
{
(*sle)[sfBalance] = (*sle)[sfBalance] - amount;
(*account_)[sfBalance] = (*account_)[sfBalance] - amount;
}
else
{
if (auto const ret = std::visit(
[&]<typename T>(T const&) {
return escrowLockApplyHelper<T>(ctx_.view(), issuer, account_, amount, j_);
return escrowLockApplyHelper<T>(ctx_.view(), issuer, accountID_, amount, j_);
},
amount.asset().value());
!isTesSuccess(ret))
@@ -497,8 +496,8 @@ EscrowCreate::doApply()
}
// increment owner count
adjustOwnerCount(ctx_.view(), sle, 1, ctx_.journal);
ctx_.view().update(sle);
account_.adjustOwnerCount(1, ctx_.journal);
account_.update();
return tesSUCCESS;
}

View File

@@ -289,11 +289,11 @@ EscrowFinish::doApply()
// NOTE: Escrow payments cannot be used to fund accounts.
AccountID const destID = (*slep)[sfDestination];
auto const sled = ctx_.view().peek(keylet::account(destID));
if (!sled)
WritableAccountRoot dest(destID, ctx_.view());
if (!dest.exists())
return tecNO_DST;
if (auto err = verifyDepositPreauth(ctx_.tx, ctx_.view(), account_, destID, sled, ctx_.journal);
if (auto err = verifyDepositPreauth(ctx_.tx, ctx_.view(), accountID_, dest, ctx_.journal);
!isTesSuccess(err))
return err;
@@ -327,7 +327,7 @@ EscrowFinish::doApply()
// Transfer amount to destination
if (isXRP(amount))
{
(*sled)[sfBalance] = (*sled)[sfBalance] + amount;
(*dest)[sfBalance] = (*dest)[sfBalance] + amount;
}
else
{
@@ -338,13 +338,13 @@ EscrowFinish::doApply()
? xrpl::Rate(slep->getFieldU32(sfTransferRate))
: parityRate;
auto const issuer = amount.getIssuer();
bool const createAsset = destID == account_;
bool const createAsset = destID == accountID_;
if (auto const ret = std::visit(
[&]<typename T>(T const&) {
return escrowUnlockApplyHelper<T>(
ctx_.view(),
lockedRate,
sled,
dest,
preFeeBalance_,
amount,
issuer,
@@ -370,12 +370,12 @@ EscrowFinish::doApply()
}
}
ctx_.view().update(sled);
dest.update();
// Adjust source owner count
auto const sle = ctx_.view().peek(keylet::account(account));
adjustOwnerCount(ctx_.view(), sle, -1, ctx_.journal);
ctx_.view().update(sle);
WritableAccountRoot wrappedAcct(account, ctx_.view());
wrappedAcct.adjustOwnerCount(-1, ctx_.journal);
wrappedAcct.update();
// Remove escrow from ledger
ctx_.view().erase(slep);

View File

@@ -12,6 +12,8 @@
#include <xrpl/protocol/Rate.h>
#include <xrpl/tx/transactors/token/MPTokenAuthorize.h>
#include <variant>
namespace xrpl {
template <ValidIssueType T>
@@ -19,7 +21,7 @@ TER
escrowUnlockApplyHelper(
ApplyView& view,
Rate lockedRate,
std::shared_ptr<SLE> const& sleDest,
std::variant<std::shared_ptr<SLE>, WritableAccountRoot> dest,
STAmount const& xrpBalance,
STAmount const& amount,
AccountID const& issuer,
@@ -33,7 +35,7 @@ inline TER
escrowUnlockApplyHelper<Issue>(
ApplyView& view,
Rate lockedRate,
std::shared_ptr<SLE> const& sleDest,
std::variant<std::shared_ptr<SLE>, WritableAccountRoot> dest,
STAmount const& xrpBalance,
STAmount const& amount,
AccountID const& issuer,
@@ -55,8 +57,14 @@ escrowUnlockApplyHelper<Issue>(
if (!view.exists(trustLineKey) && createAsset)
{
// For backwards compatibility: if dest is not WritableAccountRoot, return error
if (!std::holds_alternative<WritableAccountRoot>(dest))
return tefEXCEPTION;
auto& wrappedDest = std::get<WritableAccountRoot>(dest);
// Can the account cover the trust line's reserve?
if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
if (std::uint32_t const ownerCount = {wrappedDest->at(sfOwnerCount)};
xrpBalance < view.fees().accountReserve(ownerCount + 1))
{
JLOG(journal.trace()) << "Trust line does not exist. "
@@ -76,9 +84,9 @@ escrowUnlockApplyHelper<Issue>(
issuer, // source
receiver, // destination
trustLineKey.key, // ledger index
sleDest, // Account to add to
wrappedDest, // Account to add to
false, // authorize account
(sleDest->getFlags() & lsfDefaultRipple) == 0,
(wrappedDest->getFlags() & lsfDefaultRipple) == 0,
false, // freeze trust line
false, // deep freeze trust line
initialBalance, // zero initial balance
@@ -92,7 +100,7 @@ escrowUnlockApplyHelper<Issue>(
}
// clang-format on
view.update(sleDest);
wrappedDest.update();
}
if (!view.exists(trustLineKey) && !receiverIssuer)
@@ -163,7 +171,7 @@ inline TER
escrowUnlockApplyHelper<MPTIssue>(
ApplyView& view,
Rate lockedRate,
std::shared_ptr<SLE> const& sleDest,
std::variant<std::shared_ptr<SLE>, WritableAccountRoot> dest,
STAmount const& xrpBalance,
STAmount const& amount,
AccountID const& issuer,
@@ -179,7 +187,13 @@ escrowUnlockApplyHelper<MPTIssue>(
auto const issuanceKey = keylet::mptIssuance(mptID);
if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && createAsset && !receiverIssuer)
{
if (std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
// For backwards compatibility: if dest is not WritableAccountRoot, return error
if (!std::holds_alternative<WritableAccountRoot>(dest))
return tefEXCEPTION;
auto& wrappedDest = std::get<WritableAccountRoot>(dest);
if (std::uint32_t const ownerCount = {wrappedDest->at(sfOwnerCount)};
xrpBalance < view.fees().accountReserve(ownerCount + 1))
{
return tecINSUFFICIENT_RESERVE;
@@ -192,7 +206,7 @@ escrowUnlockApplyHelper<MPTIssue>(
}
// update owner count.
adjustOwnerCount(view, sleDest, 1, journal);
wrappedDest.adjustOwnerCount(1, journal);
}
if (!view.exists(keylet::mptoken(issuanceKey.key, receiver)) && !receiverIssuer)

View File

@@ -1900,4 +1900,68 @@ loanMakePayment(
"xrpl::loanMakePayment : fee paid is valid");
return totalParts;
}
// An owner count cannot be negative. If adjustment would cause a negative
// owner count, clamp the owner count at 0. Similarly for overflow. This
// adjustment allows the ownerCount to be adjusted up or down in multiple steps.
// If id != std::nullopt, then do error reporting.
//
// Returns adjusted owner count.
static std::uint32_t
confineOwnerCount(
std::uint32_t current,
std::int32_t adjustment,
std::optional<AccountID> const& id = std::nullopt,
beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
{
std::uint32_t adjusted{current + adjustment};
if (adjustment > 0)
{
// Overflow is well defined on unsigned
if (adjusted < current)
{
if (id)
{
JLOG(j.fatal()) << "Account " << *id << " owner count exceeds max!";
}
adjusted = std::numeric_limits<std::uint32_t>::max();
}
}
else
{
// Underflow is well defined on unsigned
if (adjusted > current)
{
if (id)
{
JLOG(j.fatal()) << "Account " << *id << " owner count set below 0!";
}
adjusted = 0;
XRPL_ASSERT(!id, "xrpl::confineOwnerCount : id is not set");
}
}
return adjusted;
}
void
adjustOwnerCount(
std::shared_ptr<SLE> const& sle,
ApplyView& view,
std::int32_t amount,
beast::Journal j)
{
// This function is only used for LoanBrokers, so assert that
// AccountRoot should use WritableAccountRoot.adjustOwnerCount instead
XRPL_ASSERT(sle->getType() == ltLOAN_BROKER, "xrpl::adjustOwnerCount : sle is loan broker");
if (!sle)
return;
XRPL_ASSERT(amount, "xrpl::adjustOwnerCount : nonzero amount input");
std::uint32_t const current{sle->getFieldU32(sfOwnerCount)};
AccountID const id = (*sle)[sfAccount];
std::uint32_t const adjusted = confineOwnerCount(current, amount, id, j);
view.adjustOwnerCountHook(id, current, adjusted);
sle->at(sfOwnerCount) = adjusted;
view.update(sle);
}
} // namespace xrpl

View File

@@ -1,5 +1,6 @@
#include <xrpl/tx/transactors/lending/LoanBrokerCoverClawback.h>
//
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/STTakesAsset.h>
#include <xrpl/tx/transactors/lending/LendingHelpers.h>
@@ -81,16 +82,16 @@ determineBrokerID(ReadView const& view, STTx const& tx)
// Thus, Amount.issuer _should_ be the loan broker's
// pseudo-account, but we don't know yet whether it is.
auto const maybePseudo = dstAmount->getIssuer();
auto const sle = view.read(keylet::account(maybePseudo));
AccountRoot const acct(maybePseudo, view);
// If the account was not found, the transaction can't go further.
if (!sle)
if (!acct)
return Unexpected{tecNO_ENTRY};
// If the account was found, and has a LoanBrokerID (and therefore
// is a pseudo-account), that's the
// answer we need.
if (auto const brokerID = sle->at(~sfLoanBrokerID))
if (auto const brokerID = acct->at(~sfLoanBrokerID))
return *brokerID;
// If the account does not have a LoanBrokerID, the transaction
@@ -273,8 +274,8 @@ LoanBrokerCoverClawback::preclaim(PreclaimContext const& ctx)
return tecINTERNAL; // tecINSUFFICIENT_FUNDS; LCOV_EXCL_LINE
// Check if the vault asset issuer has the correct flags
auto const sleIssuer = ctx.view.read(keylet::account(vaultAsset.getIssuer()));
if (!sleIssuer)
AccountRoot const acctIssuer(vaultAsset.getIssuer(), ctx.view);
if (!acctIssuer)
{
// LCOV_EXCL_START
JLOG(ctx.j.fatal()) << "Issuer account does not exist.";
@@ -283,7 +284,7 @@ LoanBrokerCoverClawback::preclaim(PreclaimContext const& ctx)
}
return std::visit(
[&]<typename T>(T const&) { return preclaimHelper<T>(ctx, *sleIssuer, clawAmount); },
[&]<typename T>(T const&) { return preclaimHelper<T>(ctx, *acctIssuer.sle(), clawAmount); },
vaultAsset.value());
}

View File

@@ -109,7 +109,8 @@ LoanBrokerCoverDeposit::doApply()
auto const brokerPseudoID = broker->at(sfAccount);
// Transfer assets from depositor to pseudo-account.
if (auto ter = accountSend(view(), account_, brokerPseudoID, amount, j_, WaiveTransferFee::Yes))
if (auto ter =
accountSend(view(), accountID_, brokerPseudoID, amount, j_, WaiveTransferFee::Yes))
return ter;
// Increase the LoanBroker's CoverAvailable by Amount

View File

@@ -149,7 +149,7 @@ LoanBrokerCoverWithdraw::doApply()
auto const brokerID = tx[sfLoanBrokerID];
auto const amount = tx[sfAmount];
auto const dstAcct = tx[~sfDestination].value_or(account_);
auto const dstAcct = tx[~sfDestination].value_or(accountID_);
auto broker = view().peek(keylet::loanbroker(brokerID));
if (!broker)
@@ -169,7 +169,7 @@ LoanBrokerCoverWithdraw::doApply()
associateAsset(*broker, vaultAsset);
return doWithdraw(view(), tx, account_, dstAcct, brokerPseudoID, preFeeBalance_, amount, j_);
return doWithdraw(view(), tx, accountID_, dstAcct, brokerPseudoID, preFeeBalance_, amount, j_);
}
//------------------------------------------------------------------------------

View File

@@ -115,7 +115,7 @@ LoanBrokerDelete::doApply()
auto const brokerPseudoID = broker->at(sfAccount);
if (!view().dirRemove(
keylet::ownerDir(account_), broker->at(sfOwnerNode), broker->key(), false))
keylet::ownerDir(accountID_), broker->at(sfOwnerNode), broker->key(), false))
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
@@ -128,25 +128,25 @@ LoanBrokerDelete::doApply()
{
auto const coverAvailable = STAmount{vaultAsset, broker->at(sfCoverAvailable)};
if (auto const ter = accountSend(
view(), brokerPseudoID, account_, coverAvailable, j_, WaiveTransferFee::Yes))
view(), brokerPseudoID, accountID_, coverAvailable, j_, WaiveTransferFee::Yes))
return ter;
}
if (auto ter = removeEmptyHolding(view(), brokerPseudoID, vaultAsset, j_))
return ter;
auto brokerPseudoSLE = view().peek(keylet::account(brokerPseudoID));
if (!brokerPseudoSLE)
WritableAccountRoot brokerPseudo(brokerPseudoID, view());
if (!brokerPseudo)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
// Making the payment and removing the empty holding should have deleted any
// obligations associated with the broker or broker pseudo-account.
if (*brokerPseudoSLE->at(sfBalance))
if (*brokerPseudo->at(sfBalance))
{
JLOG(j_.warn()) << "LoanBrokerDelete: Pseudo-account has a balance";
return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
}
if (brokerPseudoSLE->at(sfOwnerCount) != 0)
if (brokerPseudo->at(sfOwnerCount) != 0)
{
JLOG(j_.warn()) << "LoanBrokerDelete: Pseudo-account still owns objects";
return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
@@ -157,18 +157,18 @@ LoanBrokerDelete::doApply()
return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
}
view().erase(brokerPseudoSLE);
brokerPseudo.erase();
view().erase(broker);
{
auto owner = view().peek(keylet::account(account_));
if (!owner)
WritableAccountRoot wrappedOwner(accountID_, view());
if (!wrappedOwner)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
// Decreases the owner count by two: one for the LoanBroker object, and
// one for the pseudo-account.
adjustOwnerCount(view(), owner, -2, j_);
wrappedOwner.adjustOwnerCount(-2, j_);
}
associateAsset(*broker, vaultAsset);

View File

@@ -202,7 +202,7 @@ LoanBrokerSet::doApply()
auto const vaultAsset = sleVault->at(sfAsset);
auto const sequence = tx.getSeqValue();
auto owner = view.peek(keylet::account(account_));
WritableAccountRoot owner(accountID_, view);
if (!owner)
{
// This should be impossible
@@ -211,16 +211,16 @@ LoanBrokerSet::doApply()
return tefBAD_LEDGER;
// LCOV_EXCL_STOP
}
auto broker = std::make_shared<SLE>(keylet::loanbroker(account_, sequence));
auto broker = std::make_shared<SLE>(keylet::loanbroker(accountID_, sequence));
if (auto const ter = dirLink(view, account_, broker))
if (auto const ter = dirLink(view, accountID_, broker))
return ter; // LCOV_EXCL_LINE
if (auto const ter = dirLink(view, vaultPseudoID, broker, sfVaultNode))
return ter; // LCOV_EXCL_LINE
// Increases the owner count by two: one for the LoanBroker object, and
// one for the pseudo-account.
adjustOwnerCount(view, owner, 2, j_);
owner.adjustOwnerCount(2, j_);
auto const ownerCount = owner->at(sfOwnerCount);
if (preFeeBalance_ < view.fees().accountReserve(ownerCount))
return tecINSUFFICIENT_RESERVE;
@@ -237,7 +237,7 @@ LoanBrokerSet::doApply()
// Initialize data fields:
broker->at(sfSequence) = sequence;
broker->at(sfVaultID) = vaultID;
broker->at(sfOwner) = account_;
broker->at(sfOwner) = accountID_;
broker->at(sfAccount) = pseudoId;
// The LoanSequence indexes loans created by this broker, starting at 1
broker->at(sfLoanSequence) = 1;

View File

@@ -68,8 +68,8 @@ LoanDelete::doApply()
if (!loanSle)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const borrower = loanSle->at(sfBorrower);
auto const borrowerSle = view.peek(keylet::account(borrower));
if (!borrowerSle)
WritableAccountRoot wrappedBorrower(borrower, view);
if (!wrappedBorrower)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const brokerID = loanSle->at(sfLoanBrokerID);
@@ -97,7 +97,7 @@ LoanDelete::doApply()
// Decrement the LoanBroker's owner count.
// The broker's owner count is solely for the number of outstanding loans,
// and is distinct from the broker's pseudo-account's owner count
adjustOwnerCount(view, brokerSle, -1, j_);
adjustOwnerCount(brokerSle, view, -1, j_);
// If there are no loans left, then any remaining debt must be forgiven,
// because there is no other way to pay it back.
if (brokerSle->at(sfOwnerCount) == 0)
@@ -117,7 +117,7 @@ LoanDelete::doApply()
}
}
// Decrement the borrower's owner count
adjustOwnerCount(view, borrowerSle, -1, j_);
wrappedBorrower.adjustOwnerCount(-1, j_);
// These associations shouldn't do anything, but do them just to be safe
associateAsset(*loanSle, vaultAsset);

View File

@@ -1,6 +1,7 @@
#include <xrpl/tx/transactors/lending/LoanPay.h>
//
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/STTakesAsset.h>
@@ -286,7 +287,7 @@ LoanPay::doApply()
}();
auto const brokerPayee = sendBrokerFeeToOwner ? brokerOwner : brokerPseudoAccount;
auto const brokerPayeeSle = view.peek(keylet::account(brokerPayee));
WritableAccountRoot brokerPayeeAcct(brokerPayee, view);
if (!sendBrokerFeeToOwner)
{
// If we can't send the fee to the owner, and the pseudo-account is
@@ -488,13 +489,13 @@ LoanPay::doApply()
#if !NDEBUG
auto const accountBalanceBefore = accountHolds(
view,
account_,
accountID_,
asset,
fhIGNORE_FREEZE,
ahIGNORE_AUTH,
j_,
SpendableHandling::shFULL_BALANCE);
auto const vaultBalanceBefore = account_ == vaultPseudoAccount
auto const vaultBalanceBefore = accountID_ == vaultPseudoAccount
? STAmount{asset, 0}
: accountHolds(
view,
@@ -504,7 +505,7 @@ LoanPay::doApply()
ahIGNORE_AUTH,
j_,
SpendableHandling::shFULL_BALANCE);
auto const brokerBalanceBefore = account_ == brokerPayee
auto const brokerBalanceBefore = accountID_ == brokerPayee
? STAmount{asset, 0}
: accountHolds(
view,
@@ -524,11 +525,11 @@ LoanPay::doApply()
if (totalPaidToBroker != beast::zero)
{
if (brokerPayee == account_)
if (brokerPayee == accountID_)
{
// The broker may have deleted their holding. Recreate it if needed
if (auto const ter = addEmptyHolding(
view, brokerPayee, brokerPayeeSle->at(sfBalance).value().xrp(), asset, j_);
view, brokerPayee, brokerPayeeAcct->at(sfBalance).value().xrp(), asset, j_);
ter && ter != tecDUPLICATE)
{
// ignore tecDUPLICATE. That means the holding already exists,
@@ -542,7 +543,7 @@ LoanPay::doApply()
if (auto const ter = accountSendMulti(
view,
account_,
accountID_,
asset,
{{vaultPseudoAccount, totalPaidToVaultRounded}, {brokerPayee, totalPaidToBroker}},
j_,
@@ -565,13 +566,13 @@ LoanPay::doApply()
auto const accountBalanceAfter = accountHolds(
view,
account_,
accountID_,
asset,
fhIGNORE_FREEZE,
ahIGNORE_AUTH,
j_,
SpendableHandling::shFULL_BALANCE);
auto const vaultBalanceAfter = account_ == vaultPseudoAccount
auto const vaultBalanceAfter = accountID_ == vaultPseudoAccount
? STAmount{asset, 0}
: accountHolds(
view,
@@ -581,7 +582,7 @@ LoanPay::doApply()
ahIGNORE_AUTH,
j_,
SpendableHandling::shFULL_BALANCE);
auto const brokerBalanceAfter = account_ == brokerPayee
auto const brokerBalanceAfter = accountID_ == brokerPayee
? STAmount{asset, 0}
: accountHolds(
view,
@@ -600,7 +601,7 @@ LoanPay::doApply()
XRPL_ASSERT_PARTS(
accountBalanceAfter >= beast::zero, "xrpl::LoanPay::doApply", "positive account balance");
XRPL_ASSERT_PARTS(
accountBalanceAfter < accountBalanceBefore || account_ == asset.getIssuer(),
accountBalanceAfter < accountBalanceBefore || accountID_ == asset.getIssuer(),
"xrpl::LoanPay::doApply",
"account balance decreased");
XRPL_ASSERT_PARTS(

View File

@@ -258,7 +258,7 @@ LoanSet::preclaim(PreclaimContext const& ctx)
auto const brokerPseudo = brokerSle->at(sfAccount);
auto const borrower = counterparty == brokerOwner ? account : counterparty;
if (auto const borrowerSle = ctx.view.read(keylet::account(borrower)); !borrowerSle)
if (auto const wrappedBorrower = AccountRoot(borrower, ctx.view); !wrappedBorrower)
{
// It may not be possible to hit this case, because it'll fail the
// signature check with terNO_ACCOUNT.
@@ -348,8 +348,8 @@ LoanSet::doApply()
if (!brokerSle)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const brokerOwner = brokerSle->at(sfOwner);
auto const brokerOwnerSle = view.peek(keylet::account(brokerOwner));
if (!brokerOwnerSle)
WritableAccountRoot brokerOwnerAcct(brokerOwner, view);
if (!brokerOwnerAcct)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultSle = view.peek(keylet ::vault(brokerSle->at(sfVaultID)));
@@ -359,16 +359,16 @@ LoanSet::doApply()
Asset const vaultAsset = vaultSle->at(sfAsset);
auto const counterparty = tx[~sfCounterparty].value_or(brokerOwner);
auto const borrower = counterparty == brokerOwner ? account_ : counterparty;
auto const borrowerSle = view.peek(keylet::account(borrower));
if (!borrowerSle)
auto const borrower = counterparty == brokerOwner ? accountID_ : counterparty;
WritableAccountRoot wrappedBorrower(borrower, view);
if (!wrappedBorrower)
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
auto const brokerPseudo = brokerSle->at(sfAccount);
auto const brokerPseudoSle = view.peek(keylet::account(brokerPseudo));
if (!brokerPseudoSle)
WritableAccountRoot brokerPseudoAcct(brokerPseudo, view);
if (!brokerPseudoAcct)
{
return tefBAD_LEDGER; // LCOV_EXCL_LINE
}
@@ -474,11 +474,11 @@ LoanSet::doApply()
}
}
adjustOwnerCount(view, borrowerSle, 1, j_);
wrappedBorrower.adjustOwnerCount(1, j_);
{
auto const ownerCount = borrowerSle->at(sfOwnerCount);
auto const ownerCount = wrappedBorrower->at(sfOwnerCount);
auto const balance =
account_ == borrower ? preFeeBalance_ : borrowerSle->at(sfBalance).value().xrp();
accountID_ == borrower ? preFeeBalance_ : wrappedBorrower->at(sfBalance).value().xrp();
if (balance < view.fees().accountReserve(ownerCount))
return tecINSUFFICIENT_RESERVE;
}
@@ -490,11 +490,11 @@ LoanSet::doApply()
// Create a holding for the borrower if one does not already exist.
XRPL_ASSERT_PARTS(
borrower == account_ || borrower == counterparty,
borrower == accountID_ || borrower == counterparty,
"xrpl::LoanSet::doApply",
"borrower signed transaction");
if (auto const ter = addEmptyHolding(
view, borrower, borrowerSle->at(sfBalance).value().xrp(), vaultAsset, j_);
view, borrower, wrappedBorrower->at(sfBalance).value().xrp(), vaultAsset, j_);
ter && ter != tecDUPLICATE)
{
// ignore tecDUPLICATE. That means the holding already exists, and
@@ -512,12 +512,12 @@ LoanSet::doApply()
// Create the holding if it doesn't already exist (necessary for MPTs).
// The owner may have deleted their MPT / line at some point.
XRPL_ASSERT_PARTS(
brokerOwner == account_ || brokerOwner == counterparty,
brokerOwner == accountID_ || brokerOwner == counterparty,
"xrpl::LoanSet::doApply",
"broker owner signed transaction");
if (auto const ter = addEmptyHolding(
view, brokerOwner, brokerOwnerSle->at(sfBalance).value().xrp(), vaultAsset, j_);
view, brokerOwner, brokerOwnerAcct->at(sfBalance).value().xrp(), vaultAsset, j_);
ter && ter != tecDUPLICATE)
{
// ignore tecDUPLICATE. That means the holding already exists,
@@ -595,7 +595,7 @@ LoanSet::doApply()
adjustImpreciseNumber(brokerSle->at(sfDebtTotal), newDebtDelta, vaultAsset, vaultScale);
// The broker's owner count is solely for the number of outstanding loans,
// and is distinct from the broker's pseudo-account's owner count
adjustOwnerCount(view, brokerSle, 1, j_);
adjustOwnerCount(brokerSle, view, 1, j_);
loanSequenceProxy += 1;
// The sequence should be extremely unlikely to roll over, but fail if it
// does

View File

@@ -1,4 +1,5 @@
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Rate.h>
@@ -348,11 +349,11 @@ NFTokenAcceptOffer::transferNFToken(
!isTesSuccess(ret))
return ret;
auto const sleBuyer = view().read(keylet::account(buyer));
if (!sleBuyer)
AccountRoot const acctBuyer(buyer, view());
if (!acctBuyer)
return tecINTERNAL; // LCOV_EXCL_LINE
std::uint32_t const buyerOwnerCountBefore = sleBuyer->getFieldU32(sfOwnerCount);
std::uint32_t const buyerOwnerCountBefore = acctBuyer->getFieldU32(sfOwnerCount);
auto const insertRet = nft::insertToken(view(), buyer, std::move(tokenAndPage->token));
@@ -369,9 +370,9 @@ NFTokenAcceptOffer::transferNFToken(
// the deduction of the potential offer price. A small caveat here is
// that the balance has already deducted the transaction fee, meaning
// that the reserve requirement is a few drops higher.
auto const buyerBalance = sleBuyer->getFieldAmount(sfBalance);
auto const buyerBalance = acctBuyer->getFieldAmount(sfBalance);
auto const buyerOwnerCountAfter = sleBuyer->getFieldU32(sfOwnerCount);
auto const buyerOwnerCountAfter = acctBuyer->getFieldU32(sfOwnerCount);
if (buyerOwnerCountAfter > buyerOwnerCountBefore)
{
if (auto const reserve = view().fees().accountReserve(buyerOwnerCountAfter);
@@ -388,8 +389,8 @@ NFTokenAcceptOffer::acceptOffer(std::shared_ptr<SLE> const& offer)
{
bool const isSell = offer->isFlag(lsfSellNFToken);
AccountID const owner = (*offer)[sfOwner];
AccountID const& seller = isSell ? owner : account_;
AccountID const& buyer = isSell ? account_ : owner;
AccountID const& seller = isSell ? owner : accountID_;
AccountID const& buyer = isSell ? accountID_ : owner;
auto const nftokenID = (*offer)[sfNFTokenID];
@@ -510,7 +511,7 @@ NFTokenAcceptOffer::doApply()
// Send the broker the amount they requested.
if (auto const cut = ctx_.tx[~sfNFTokenBrokerFee]; cut && cut.value() != beast::zero)
{
if (auto const r = pay(buyer, account_, cut.value()); !isTesSuccess(r))
if (auto const r = pay(buyer, accountID_, cut.value()); !isTesSuccess(r))
return r;
amount -= cut.value();

View File

@@ -1,3 +1,4 @@
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/TxFlags.h>
@@ -34,9 +35,9 @@ NFTokenBurn::preclaim(PreclaimContext const& ctx)
if (auto const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); issuer != account)
{
if (auto const sle = ctx.view.read(keylet::account(issuer)); sle)
if (AccountRoot const acctIssuer(issuer, ctx.view); acctIssuer)
{
if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account)
if (auto const minter = acctIssuer->at(~sfNFTokenMinter); minter != account)
return tecNO_PERMISSION;
}
}
@@ -59,10 +60,10 @@ NFTokenBurn::doApply()
if (!isTesSuccess(ret))
return ret;
if (auto issuer = view().peek(keylet::account(nft::getIssuer(ctx_.tx[sfNFTokenID]))))
if (WritableAccountRoot issuer(nft::getIssuer(ctx_.tx[sfNFTokenID]), view()); issuer)
{
(*issuer)[~sfBurnedNFTokens] = (*issuer)[~sfBurnedNFTokens].value_or(0) + 1;
view().update(issuer);
issuer.update();
}
// Delete up to 500 offers in total.

View File

@@ -1,5 +1,6 @@
#include <xrpl/basics/Expected.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/InnerObjectFormats.h>
#include <xrpl/protocol/Rate.h>
@@ -166,12 +167,12 @@ NFTokenMint::preclaim(PreclaimContext const& ctx)
// transaction. Check that and verify that this is allowed:
if (auto issuer = ctx.tx[~sfIssuer])
{
auto const sle = ctx.view.read(keylet::account(*issuer));
AccountRoot const acctIssuer(*issuer, ctx.view);
if (!sle)
if (!acctIssuer)
return tecNO_ISSUER;
if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != ctx.tx[sfAccount])
if (auto const minter = acctIssuer->at(~sfNFTokenMinter); minter != ctx.tx[sfAccount])
return tecNO_PERMISSION;
}
@@ -202,11 +203,11 @@ NFTokenMint::preclaim(PreclaimContext const& ctx)
TER
NFTokenMint::doApply()
{
auto const issuer = ctx_.tx[~sfIssuer].value_or(account_);
auto const issuer = ctx_.tx[~sfIssuer].value_or(accountID_);
auto const tokenSeq = [this, &issuer]() -> Expected<std::uint32_t, TER> {
auto const root = view().peek(keylet::account(issuer));
if (root == nullptr)
WritableAccountRoot root(issuer, view());
if (!root)
{
// Should not happen. Checked in preclaim.
return Unexpected(tecNO_ISSUER);
@@ -251,7 +252,7 @@ NFTokenMint::doApply()
if (tokenSeq + 1u == 0u || tokenSeq < offset)
return Unexpected(tecMAX_SEQUENCE_REACHED);
ctx_.view().update(root);
root.update();
return tokenSeq;
}();
@@ -259,7 +260,7 @@ NFTokenMint::doApply()
return (tokenSeq.error());
std::uint32_t const ownerCountBefore =
view().read(keylet::account(account_))->getFieldU32(sfOwnerCount);
AccountRoot(accountID_, view())->getFieldU32(sfOwnerCount);
// Assemble the new NFToken.
SOTemplate const* nfTokenTemplate =
@@ -285,7 +286,7 @@ NFTokenMint::doApply()
object.setFieldVL(sfURI, *uri);
});
if (TER const ret = nft::insertToken(ctx_.view(), account_, std::move(newToken));
if (TER const ret = nft::insertToken(ctx_.view(), accountID_, std::move(newToken));
!isTesSuccess(ret))
return ret;
@@ -312,8 +313,7 @@ NFTokenMint::doApply()
// allows NFTs to be added to the page (and burn fees) without
// requiring the reserve to be met each time. The reserve is
// only managed when a new NFT page or sell offer is added.
if (auto const ownerCountAfter =
view().read(keylet::account(account_))->getFieldU32(sfOwnerCount);
if (auto const ownerCountAfter = AccountRoot(accountID_, view())->getFieldU32(sfOwnerCount);
ownerCountAfter > ownerCountBefore)
{
if (auto const reserve = view().fees().accountReserve(ownerCountAfter);

View File

@@ -1,3 +1,4 @@
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/TxFlags.h>
#include <xrpl/tx/transactors/nft/NFTokenModify.h>
@@ -36,10 +37,10 @@ NFTokenModify::preclaim(PreclaimContext const& ctx)
// Verify permissions for the issuer
if (AccountID const issuer = nft::getIssuer(ctx.tx[sfNFTokenID]); issuer != account)
{
auto const sle = ctx.view.read(keylet::account(issuer));
if (!sle)
AccountRoot const acctIssuer(issuer, ctx.view);
if (!acctIssuer)
return tecINTERNAL; // LCOV_EXCL_LINE
if (auto const minter = (*sle)[~sfNFTokenMinter]; minter != account)
if (auto const minter = acctIssuer->at(~sfNFTokenMinter); minter != account)
return tecNO_PERMISSION;
}

View File

@@ -247,11 +247,8 @@ insertToken(ApplyView& view, AccountID owner, STObject&& nft)
// the NFT.
std::shared_ptr<SLE> page =
getPageForToken(view, owner, nft[sfNFTokenID], [](ApplyView& view, AccountID const& owner) {
adjustOwnerCount(
view,
view.peek(keylet::account(owner)),
1,
beast::Journal{beast::Journal::getNullSink()});
WritableAccountRoot wrappedOwner(owner, view);
wrappedOwner.adjustOwnerCount(1, beast::Journal{beast::Journal::getNullSink()});
});
if (!page)
@@ -409,11 +406,8 @@ removeToken(
if (cnt != 0)
{
adjustOwnerCount(
view,
view.peek(keylet::account(owner)),
cnt,
beast::Journal{beast::Journal::getNullSink()});
WritableAccountRoot wrappedOwner(owner, view);
wrappedOwner.adjustOwnerCount(cnt, beast::Journal{beast::Journal::getNullSink()});
}
return tesSUCCESS;
@@ -448,11 +442,8 @@ removeToken(
curr->makeFieldAbsent(sfPreviousPageMin);
}
adjustOwnerCount(
view,
view.peek(keylet::account(owner)),
-1,
beast::Journal{beast::Journal::getNullSink()});
WritableAccountRoot wrappedOwner(owner, view);
wrappedOwner.adjustOwnerCount(-1, beast::Journal{beast::Journal::getNullSink()});
view.update(curr);
view.erase(prev);
@@ -507,11 +498,8 @@ removeToken(
view.peek(Keylet(ltNFTOKEN_PAGE, next->key()))))
cnt++;
adjustOwnerCount(
view,
view.peek(keylet::account(owner)),
-1 * cnt,
beast::Journal{beast::Journal::getNullSink()});
WritableAccountRoot wrappedOwner(owner, view);
wrappedOwner.adjustOwnerCount(-1 * cnt, beast::Journal{beast::Journal::getNullSink()});
return tesSUCCESS;
}
@@ -654,8 +642,8 @@ deleteTokenOffer(ApplyView& view, std::shared_ptr<SLE> const& offer)
false))
return false;
adjustOwnerCount(
view, view.peek(keylet::account(owner)), -1, beast::Journal{beast::Journal::getNullSink()});
WritableAccountRoot wrappedOwner(owner, view);
wrappedOwner.adjustOwnerCount(-1, beast::Journal{beast::Journal::getNullSink()});
view.erase(offer);
return true;
@@ -868,10 +856,10 @@ tokenOfferCreatePreclaim(
if (nftIssuer != acctID && ((nftFlags & nft::flagTransferable) == 0))
{
auto const root = view.read(keylet::account(nftIssuer));
XRPL_ASSERT(root, "xrpl::nft::tokenOfferCreatePreclaim : non-null account");
AccountRoot const acctRoot(nftIssuer, view);
XRPL_ASSERT(acctRoot, "xrpl::nft::tokenOfferCreatePreclaim : non-null account");
if (auto minter = (*root)[~sfNFTokenMinter]; minter != acctID)
if (auto minter = acctRoot->at(~sfNFTokenMinter); minter != acctID)
return tefNFTOKEN_IS_NOT_TRANSFERABLE;
}
@@ -893,26 +881,26 @@ tokenOfferCreatePreclaim(
{
// If a destination is specified, the destination must already be in
// the ledger.
auto const sleDst = view.read(keylet::account(*dest));
AccountRoot const acctDst(*dest, view);
if (!sleDst)
if (!acctDst)
return tecNO_DST;
// check if the destination has disallowed incoming offers
if ((sleDst->getFlags() & lsfDisallowIncomingNFTokenOffer) != 0u)
if ((acctDst->getFlags() & lsfDisallowIncomingNFTokenOffer) != 0u)
return tecNO_PERMISSION;
}
if (owner)
{
auto const sleOwner = view.read(keylet::account(*owner));
AccountRoot const acctOwner(*owner, view);
// defensively check
// it should not be possible to specify owner that doesn't exist
if (!sleOwner)
if (!acctOwner)
return tecNO_TARGET;
if ((sleOwner->getFlags() & lsfDisallowIncomingNFTokenOffer) != 0u)
if ((acctOwner->getFlags() & lsfDisallowIncomingNFTokenOffer) != 0u)
return tecNO_PERMISSION;
}
@@ -944,9 +932,8 @@ tokenOfferCreateApply(
beast::Journal j,
std::uint32_t txFlags)
{
Keylet const acctKeylet = keylet::account(acctID);
if (auto const acct = view.read(acctKeylet);
priorBalance < view.fees().accountReserve((*acct)[sfOwnerCount] + 1))
AccountRoot const acctRoot(acctID, view);
if (priorBalance < view.fees().accountReserve(acctRoot->getFieldU32(sfOwnerCount) + 1))
return tecINSUFFICIENT_RESERVE;
auto const offerID = keylet::nftoffer(acctID, seqProxy.value());
@@ -998,7 +985,8 @@ tokenOfferCreateApply(
}
// Update owner count.
adjustOwnerCount(view, view.peek(acctKeylet), 1, j);
WritableAccountRoot wrappedOwner(acctID, view);
wrappedOwner.adjustOwnerCount(1, j);
return tesSUCCESS;
}
@@ -1015,8 +1003,8 @@ checkTrustlineAuthorized(
if (view.rules().enabled(fixEnforceNFTokenTrustlineV2))
{
auto const issuerAccount = view.read(keylet::account(issue.account));
if (!issuerAccount)
AccountRoot const acctIssuer(issue.account, view);
if (!acctIssuer)
{
JLOG(j.debug()) << "xrpl::nft::checkTrustlineAuthorized: can't "
"receive IOUs from non-existent issuer: "
@@ -1033,7 +1021,7 @@ checkTrustlineAuthorized(
return tesSUCCESS;
}
if (issuerAccount->isFlag(lsfRequireAuth))
if (acctIssuer->isFlag(lsfRequireAuth))
{
auto const trustLine = view.read(keylet::line(id, issue.account, issue.currency));
@@ -1067,8 +1055,8 @@ checkTrustlineDeepFrozen(
if (view.rules().enabled(featureDeepFreeze))
{
auto const issuerAccount = view.read(keylet::account(issue.account));
if (!issuerAccount)
AccountRoot const acctIssuer(issue.account, view);
if (!acctIssuer)
{
JLOG(j.debug()) << "xrpl::nft::checkTrustlineDeepFrozen: can't "
"receive IOUs from non-existent issuer: "

View File

@@ -56,13 +56,13 @@ OracleDelete::deleteOracle(
// LCOV_EXCL_STOP
}
auto const sleOwner = view.peek(keylet::account(account));
if (!sleOwner)
WritableAccountRoot wrappedOwner(account, view);
if (!wrappedOwner)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const count = sle->getFieldArray(sfPriceDataSeries).size() > 5 ? -2 : -1;
adjustOwnerCount(view, sleOwner, count, j);
wrappedOwner.adjustOwnerCount(count, j);
view.erase(sle);
@@ -72,8 +72,8 @@ OracleDelete::deleteOracle(
TER
OracleDelete::doApply()
{
if (auto sle = ctx_.view().peek(keylet::oracle(account_, ctx_.tx[sfOracleDocumentID])))
return deleteOracle(ctx_.view(), sle, account_, j_);
if (auto sle = ctx_.view().peek(keylet::oracle(accountID_, ctx_.tx[sfOracleDocumentID])))
return deleteOracle(ctx_.view(), sle, accountID_, j_);
return tecINTERNAL; // LCOV_EXCL_LINE
}

View File

@@ -42,8 +42,8 @@ OracleSet::preflight(PreflightContext const& ctx)
TER
OracleSet::preclaim(PreclaimContext const& ctx)
{
auto const sleSetter = ctx.view.read(keylet::account(ctx.tx.getAccountID(sfAccount)));
if (!sleSetter)
AccountRoot const acctSetter(ctx.tx.getAccountID(sfAccount), ctx.view);
if (!acctSetter)
return terNO_ACCOUNT; // LCOV_EXCL_LINE
// lastUpdateTime must be within maxLastUpdateTimeDelta seconds
@@ -150,8 +150,8 @@ OracleSet::preclaim(PreclaimContext const& ctx)
return tecARRAY_TOO_LARGE;
auto const reserve =
ctx.view.fees().accountReserve(sleSetter->getFieldU32(sfOwnerCount) + adjustReserve);
auto const& balance = sleSetter->getFieldAmount(sfBalance);
ctx.view.fees().accountReserve(acctSetter->getFieldU32(sfOwnerCount) + adjustReserve);
auto const& balance = acctSetter->getFieldAmount(sfBalance);
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -162,9 +162,9 @@ OracleSet::preclaim(PreclaimContext const& ctx)
static bool
adjustOwnerCount(ApplyContext& ctx, int count)
{
if (auto const sleAccount = ctx.view().peek(keylet::account(ctx.tx[sfAccount])))
if (auto wrappedAccount = WritableAccountRoot(ctx.tx.getAccountID(sfAccount), ctx.view()))
{
adjustOwnerCount(ctx.view(), sleAccount, count, ctx.journal);
wrappedAccount.adjustOwnerCount(count, ctx.journal);
return true;
}
@@ -182,7 +182,7 @@ setPriceDataInnerObjTemplate(STObject& obj)
TER
OracleSet::doApply()
{
auto const oracleID = keylet::oracle(account_, ctx_.tx[sfOracleDocumentID]);
auto const oracleID = keylet::oracle(accountID_, ctx_.tx[sfOracleDocumentID]);
auto populatePriceData = [](STObject& priceData, STObject const& entry) {
setPriceDataInnerObjTemplate(priceData);
@@ -292,7 +292,7 @@ OracleSet::doApply()
sle->setFieldU32(sfLastUpdateTime, ctx_.tx[sfLastUpdateTime]);
auto page = ctx_.view().dirInsert(
keylet::ownerDir(account_), sle->key(), describeOwnerDir(account_));
keylet::ownerDir(accountID_), sle->key(), describeOwnerDir(accountID_));
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE

View File

@@ -135,8 +135,8 @@ DepositPreauth::doApply()
{
if (ctx_.tx.isFieldPresent(sfAuthorize))
{
auto const sleOwner = view().peek(keylet::account(account_));
if (!sleOwner)
WritableAccountRoot wrappedOwner(accountID_, view());
if (!wrappedOwner)
return {tefINTERNAL};
// A preauth counts against the reserve of the issuing account, but we
@@ -144,7 +144,7 @@ DepositPreauth::doApply()
// reserve to pay fees.
{
STAmount const reserve{
view().fees().accountReserve(sleOwner->getFieldU32(sfOwnerCount) + 1)};
view().fees().accountReserve(wrappedOwner->getFieldU32(sfOwnerCount) + 1)};
if (preFeeBalance_ < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -153,15 +153,15 @@ DepositPreauth::doApply()
// Preclaim already verified that the Preauth entry does not yet exist.
// Create and populate the Preauth entry.
AccountID const auth{ctx_.tx[sfAuthorize]};
Keylet const preauthKeylet = keylet::depositPreauth(account_, auth);
Keylet const preauthKeylet = keylet::depositPreauth(accountID_, auth);
auto slePreauth = std::make_shared<SLE>(preauthKeylet);
slePreauth->setAccountID(sfAccount, account_);
slePreauth->setAccountID(sfAccount, accountID_);
slePreauth->setAccountID(sfAuthorize, auth);
view().insert(slePreauth);
auto const page =
view().dirInsert(keylet::ownerDir(account_), preauthKeylet, describeOwnerDir(account_));
auto const page = view().dirInsert(
keylet::ownerDir(accountID_), preauthKeylet, describeOwnerDir(accountID_));
JLOG(j_.trace()) << "Adding DepositPreauth to owner directory "
<< to_string(preauthKeylet.key) << ": " << (page ? "success" : "failure");
@@ -172,18 +172,18 @@ DepositPreauth::doApply()
slePreauth->setFieldU64(sfOwnerNode, *page);
// If we succeeded, the new entry counts against the creator's reserve.
adjustOwnerCount(view(), sleOwner, 1, j_);
wrappedOwner.adjustOwnerCount(1, j_);
}
else if (ctx_.tx.isFieldPresent(sfUnauthorize))
{
auto const preauth = keylet::depositPreauth(account_, ctx_.tx[sfUnauthorize]);
auto const preauth = keylet::depositPreauth(accountID_, ctx_.tx[sfUnauthorize]);
return DepositPreauth::removeFromLedger(view(), preauth.key, j_);
}
else if (ctx_.tx.isFieldPresent(sfAuthorizeCredentials))
{
auto const sleOwner = view().peek(keylet::account(account_));
if (!sleOwner)
WritableAccountRoot wrappedOwner(accountID_, view());
if (!wrappedOwner)
return tefINTERNAL; // LCOV_EXCL_LINE
// A preauth counts against the reserve of the issuing account, but we
@@ -191,7 +191,7 @@ DepositPreauth::doApply()
// reserve to pay fees.
{
STAmount const reserve{
view().fees().accountReserve(sleOwner->getFieldU32(sfOwnerCount) + 1)};
view().fees().accountReserve(wrappedOwner->getFieldU32(sfOwnerCount) + 1)};
if (preFeeBalance_ < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -211,18 +211,18 @@ DepositPreauth::doApply()
sortedLE.push_back(std::move(cred));
}
Keylet const preauthKey = keylet::depositPreauth(account_, sortedTX);
Keylet const preauthKey = keylet::depositPreauth(accountID_, sortedTX);
auto slePreauth = std::make_shared<SLE>(preauthKey);
if (!slePreauth)
return tefINTERNAL; // LCOV_EXCL_LINE
slePreauth->setAccountID(sfAccount, account_);
slePreauth->setAccountID(sfAccount, accountID_);
slePreauth->peekFieldArray(sfAuthorizeCredentials) = std::move(sortedLE);
view().insert(slePreauth);
auto const page =
view().dirInsert(keylet::ownerDir(account_), preauthKey, describeOwnerDir(account_));
auto const page = view().dirInsert(
keylet::ownerDir(accountID_), preauthKey, describeOwnerDir(accountID_));
JLOG(j_.trace()) << "Adding DepositPreauth to owner directory " << to_string(preauthKey.key)
<< ": " << (page ? "success" : "failure");
@@ -233,12 +233,12 @@ DepositPreauth::doApply()
slePreauth->setFieldU64(sfOwnerNode, *page);
// If we succeeded, the new entry counts against the creator's reserve.
adjustOwnerCount(view(), sleOwner, 1, j_);
wrappedOwner.adjustOwnerCount(1, j_);
}
else if (ctx_.tx.isFieldPresent(sfUnauthorizeCredentials))
{
auto const preauthKey = keylet::depositPreauth(
account_, credentials::makeSorted(ctx_.tx.getFieldArray(sfUnauthorizeCredentials)));
accountID_, credentials::makeSorted(ctx_.tx.getFieldArray(sfUnauthorizeCredentials)));
return DepositPreauth::removeFromLedger(view(), preauthKey.key, j_);
}
@@ -267,11 +267,11 @@ DepositPreauth::removeFromLedger(ApplyView& view, uint256 const& preauthIndex, b
}
// If we succeeded, update the DepositPreauth owner's reserve.
auto const sleOwner = view.peek(keylet::account(account));
if (!sleOwner)
WritableAccountRoot wrappedOwner(account, view);
if (!wrappedOwner)
return tefINTERNAL; // LCOV_EXCL_LINE
adjustOwnerCount(view, sleOwner, -1, j);
wrappedOwner.adjustOwnerCount(-1, j);
// Remove DepositPreauth from ledger.
view.erase(slePreauth);

View File

@@ -1,3 +1,4 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
@@ -275,10 +276,9 @@ Payment::preclaim(PreclaimContext const& ctx)
AccountID const dstAccountID(ctx.tx[sfDestination]);
STAmount const dstAmount(ctx.tx[sfAmount]);
auto const k = keylet::account(dstAccountID);
auto const sleDst = ctx.view.read(k);
AccountRoot const dstAcct(dstAccountID, ctx.view);
if (!sleDst)
if (!dstAcct)
{
// Destination account does not exist.
if (!dstAmount.native())
@@ -314,7 +314,7 @@ Payment::preclaim(PreclaimContext const& ctx)
}
}
else if (
((sleDst->getFlags() & lsfRequireDestTag) != 0u) &&
((dstAcct->getFlags() & lsfRequireDestTag) != 0u) &&
!ctx.tx.isFieldPresent(sfDestinationTag))
{
// The tag is basically account-specific information we don't
@@ -373,30 +373,29 @@ Payment::doApply()
AccountID const dstAccountID(ctx_.tx.getAccountID(sfDestination));
STAmount const dstAmount(ctx_.tx.getFieldAmount(sfAmount));
bool const mptDirect = dstAmount.holds<MPTIssue>();
STAmount const maxSourceAmount = getMaxSourceAmount(account_, dstAmount, sendMax);
STAmount const maxSourceAmount = getMaxSourceAmount(accountID_, dstAmount, sendMax);
JLOG(j_.trace()) << "maxSourceAmount=" << maxSourceAmount.getFullText()
<< " dstAmount=" << dstAmount.getFullText();
// Open a ledger for editing.
auto const k = keylet::account(dstAccountID);
SLE::pointer sleDst = view().peek(k);
WritableAccountRoot dst(dstAccountID, view());
if (!sleDst)
if (!dst)
{
// Create the account.
sleDst = std::make_shared<SLE>(k);
sleDst->setAccountID(sfAccount, dstAccountID);
sleDst->setFieldU32(sfSequence, view().seq());
dst.newSLE();
dst->setAccountID(sfAccount, dstAccountID);
dst->setFieldU32(sfSequence, view().seq());
view().insert(sleDst);
dst.insert();
}
else
{
// Tell the engine that we are intending to change the destination
// account. The source account gets always charged a fee so it's always
// marked as modified.
view().update(sleDst);
dst.update();
}
bool const ripple = (hasPaths || sendMax || !dstAmount.native()) && !mptDirect;
@@ -411,8 +410,7 @@ Payment::doApply()
// 1. If Account == Destination, or
// 2. If Account is deposit preauthorized by destination.
if (auto err = verifyDepositPreauth(
ctx_.tx, ctx_.view(), account_, dstAccountID, sleDst, ctx_.journal);
if (auto err = verifyDepositPreauth(ctx_.tx, ctx_.view(), accountID_, dst, ctx_.journal);
!isTesSuccess(err))
return err;
@@ -431,10 +429,10 @@ Payment::doApply()
maxSourceAmount,
dstAmount,
dstAccountID,
account_,
accountID_,
ctx_.tx.getFieldPathSet(sfPaths),
ctx_.tx[~sfDomainID],
ctx_.registry,
ctx_.registry.logs(),
&rcInput);
// VFALCO NOTE We might not need to apply, depending
// on the TER. But always applying *should*
@@ -471,18 +469,17 @@ Payment::doApply()
JLOG(j_.trace()) << " dstAmount=" << dstAmount.getFullText();
auto const& mptIssue = dstAmount.get<MPTIssue>();
if (auto const ter = requireAuth(view(), mptIssue, account_); !isTesSuccess(ter))
if (auto const ter = requireAuth(view(), mptIssue, accountID_); !isTesSuccess(ter))
return ter;
if (auto const ter = requireAuth(view(), mptIssue, dstAccountID); !isTesSuccess(ter))
return ter;
if (auto const ter = canTransfer(view(), mptIssue, account_, dstAccountID);
if (auto const ter = canTransfer(view(), mptIssue, accountID_, dstAccountID);
!isTesSuccess(ter))
return ter;
if (auto err = verifyDepositPreauth(
ctx_.tx, ctx_.view(), account_, dstAccountID, sleDst, ctx_.journal);
if (auto err = verifyDepositPreauth(ctx_.tx, ctx_.view(), accountID_, dst, ctx_.journal);
!isTesSuccess(err))
return err;
@@ -491,13 +488,13 @@ Payment::doApply()
// Transfer rate
Rate rate{QUALITY_ONE};
// Payment between the holders
if (account_ != issuer && dstAccountID != issuer)
if (accountID_ != issuer && dstAccountID != issuer)
{
// If globally/individually locked then
// - can't send between holders
// - holder can send back to issuer
// - issuer can send to holder
if (isAnyFrozen(view(), {account_, dstAccountID}, mptIssue))
if (isAnyFrozen(view(), {accountID_, dstAccountID}, mptIssue))
return tecLOCKED;
// Get the rate for a payment between the holders.
@@ -525,7 +522,7 @@ Payment::doApply()
return tecPATH_PARTIAL;
PaymentSandbox pv(&view());
auto res = accountSend(pv, account_, dstAccountID, amountDeliver, ctx_.journal);
auto res = accountSend(pv, accountID_, dstAccountID, amountDeliver, ctx_.journal);
if (isTesSuccess(res))
{
pv.apply(ctx_.rawView());
@@ -548,13 +545,13 @@ Payment::doApply()
// Direct XRP payment.
auto const sleSrc = view().peek(keylet::account(account_));
if (!sleSrc)
WritableAccountRoot srcAcct(accountID_, view());
if (!srcAcct)
return tefINTERNAL; // LCOV_EXCL_LINE
// ownerCount is the number of entries in this ledger for this
// account that require a reserve.
auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
auto const ownerCount = srcAcct->getFieldU32(sfOwnerCount);
// This is the total reserve in drops.
auto const reserve = view().fees().accountReserve(ownerCount);
@@ -580,7 +577,7 @@ Payment::doApply()
// transaction types. Note, this is not amendment-gated because all writes
// to pseudo-account discriminator fields **are** amendment gated, hence the
// behaviour of this check will always match the active amendments.
if (isPseudoAccount(sleDst))
if (dst.isPseudoAccount())
return tecNO_PERMISSION;
// The source account does have enough money. Make sure the
@@ -607,21 +604,20 @@ Payment::doApply()
// Get the base reserve.
XRPAmount const dstReserve{view().fees().reserve};
if (dstAmount > dstReserve || sleDst->getFieldAmount(sfBalance) > dstReserve)
if (dstAmount > dstReserve || dst->getFieldAmount(sfBalance) > dstReserve)
{
if (auto err = verifyDepositPreauth(
ctx_.tx, ctx_.view(), account_, dstAccountID, sleDst, ctx_.journal);
if (auto err = verifyDepositPreauth(ctx_.tx, ctx_.view(), accountID_, dst, ctx_.journal);
!isTesSuccess(err))
return err;
}
// Do the arithmetic for the transfer and make the ledger change.
sleSrc->setFieldAmount(sfBalance, sleSrc->getFieldAmount(sfBalance) - dstAmount);
sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount);
srcAcct->setFieldAmount(sfBalance, srcAcct->getFieldAmount(sfBalance) - dstAmount);
dst->setFieldAmount(sfBalance, dst->getFieldAmount(sfBalance) + dstAmount);
// Re-arm the password change fee if we can and need to.
if ((sleDst->getFlags() & lsfPasswordSpent) != 0u)
sleDst->clearFlag(lsfPasswordSpent);
if ((dst->getFlags() & lsfPasswordSpent) != 0u)
dst->clearFlag(lsfPasswordSpent);
return tesSUCCESS;
}

View File

@@ -1,5 +1,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -108,7 +110,7 @@ PaymentChannelClaim::doApply()
auto const closeTime = ctx_.view().header().parentCloseTime.time_since_epoch().count();
if ((cancelAfter && closeTime >= *cancelAfter) ||
(curExpiration && closeTime >= *curExpiration))
return closeChannel(slep, ctx_.view(), k.key, ctx_.registry.getJournal("View"));
return closeChannel(slep, ctx_.view(), k.key, ctx_.registry.journal("View"));
}
if (txAccount != src && txAccount != dst)
@@ -139,12 +141,12 @@ PaymentChannelClaim::doApply()
return tecUNFUNDED_PAYMENT;
}
auto const sled = ctx_.view().peek(keylet::account(dst));
if (!sled)
WritableAccountRoot dstAcct(dst, ctx_.view());
if (!dstAcct)
return tecNO_DST;
if (auto err =
verifyDepositPreauth(ctx_.tx, ctx_.view(), txAccount, dst, sled, ctx_.journal);
if (auto err = verifyDepositPreauth(
ctx_.tx, ctx_.view(), txAccount, AccountRoot(dst, ctx_.view()), ctx_.journal);
!isTesSuccess(err))
return err;
@@ -152,8 +154,8 @@ PaymentChannelClaim::doApply()
XRPAmount const reqDelta = reqBalance - chanBalance;
XRPL_ASSERT(
reqDelta >= beast::zero, "xrpl::PaymentChannelClaim::doApply : minimum balance delta");
(*sled)[sfBalance] = (*sled)[sfBalance] + reqDelta;
ctx_.view().update(sled);
(*dstAcct)[sfBalance] = (*dstAcct)[sfBalance] + reqDelta;
dstAcct.update();
ctx_.view().update(slep);
}
@@ -169,7 +171,7 @@ PaymentChannelClaim::doApply()
{
// Channel will close immediately if dry or the receiver closes
if (dst == txAccount || (*slep)[sfBalance] == (*slep)[sfAmount])
return closeChannel(slep, ctx_.view(), k.key, ctx_.registry.getJournal("View"));
return closeChannel(slep, ctx_.view(), k.key, ctx_.registry.journal("View"));
auto const settleExpiration =
ctx_.view().header().parentCloseTime.time_since_epoch().count() +

View File

@@ -58,14 +58,14 @@ TER
PaymentChannelCreate::preclaim(PreclaimContext const& ctx)
{
auto const account = ctx.tx[sfAccount];
auto const sle = ctx.view.read(keylet::account(account));
if (!sle)
AccountRoot const acctSrc(account, ctx.view);
if (!acctSrc)
return terNO_ACCOUNT;
// Check reserve and funds availability
{
auto const balance = (*sle)[sfBalance];
auto const reserve = ctx.view.fees().accountReserve((*sle)[sfOwnerCount] + 1);
auto const balance = acctSrc->at(sfBalance);
auto const reserve = ctx.view.fees().accountReserve(acctSrc->getFieldU32(sfOwnerCount) + 1);
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -78,11 +78,11 @@ PaymentChannelCreate::preclaim(PreclaimContext const& ctx)
{
// Check destination account
auto const sled = ctx.view.read(keylet::account(dst));
if (!sled)
AccountRoot const acctDst(dst, ctx.view);
if (!acctDst)
return tecNO_DST;
auto const flags = sled->getFlags();
auto const flags = acctDst->getFlags();
// Check if they have disallowed incoming payment channels
if ((flags & lsfDisallowIncomingPayChan) != 0u)
@@ -97,7 +97,7 @@ PaymentChannelCreate::preclaim(PreclaimContext const& ctx)
// writes to pseudo-account discriminator fields **are** amendment
// gated, hence the behaviour of this check will always match the
// currently active amendments.
if (isPseudoAccount(sled))
if (acctDst.isPseudoAccount())
return tecNO_PERMISSION;
}
@@ -107,9 +107,8 @@ PaymentChannelCreate::preclaim(PreclaimContext const& ctx)
TER
PaymentChannelCreate::doApply()
{
auto const account = ctx_.tx[sfAccount];
auto const sle = ctx_.view().peek(keylet::account(account));
if (!sle)
WritableAccountRoot wrappedOwner(accountID_, ctx_.view());
if (!wrappedOwner)
return tefINTERNAL; // LCOV_EXCL_LINE
if (ctx_.view().rules().enabled(fixPayChanCancelAfter))
@@ -125,14 +124,14 @@ PaymentChannelCreate::doApply()
//
// Note that we we use the value from the sequence or ticket as the
// payChan sequence. For more explanation see comments in SeqProxy.h.
Keylet const payChanKeylet = keylet::payChan(account, dst, ctx_.tx.getSeqValue());
Keylet const payChanKeylet = keylet::payChan(accountID_, dst, ctx_.tx.getSeqValue());
auto const slep = std::make_shared<SLE>(payChanKeylet);
// Funds held in this channel
(*slep)[sfAmount] = ctx_.tx[sfAmount];
// Amount channel has already paid
(*slep)[sfBalance] = ctx_.tx[sfAmount].zeroed();
(*slep)[sfAccount] = account;
(*slep)[sfAccount] = accountID_;
(*slep)[sfDestination] = dst;
(*slep)[sfSettleDelay] = ctx_.tx[sfSettleDelay];
(*slep)[sfPublicKey] = ctx_.tx[sfPublicKey];
@@ -149,7 +148,7 @@ PaymentChannelCreate::doApply()
// Add PayChan to owner directory
{
auto const page = ctx_.view().dirInsert(
keylet::ownerDir(account), payChanKeylet, describeOwnerDir(account));
keylet::ownerDir(accountID_), payChanKeylet, describeOwnerDir(accountID_));
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE
(*slep)[sfOwnerNode] = *page;
@@ -165,9 +164,9 @@ PaymentChannelCreate::doApply()
}
// Deduct owner's balance, increment owner count
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
adjustOwnerCount(ctx_.view(), sle, 1, ctx_.journal);
ctx_.view().update(sle);
(*wrappedOwner)[sfBalance] = (*wrappedOwner)[sfBalance] - ctx_.tx[sfAmount];
wrappedOwner.adjustOwnerCount(1, ctx_.journal);
wrappedOwner.update();
return tesSUCCESS;
}

View File

@@ -1,5 +1,6 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/tx/transactors/payment_channel/PaymentChannelFund.h>
@@ -38,7 +39,7 @@ PaymentChannelFund::doApply()
auto const cancelAfter = (*slep)[~sfCancelAfter];
auto const closeTime = ctx_.view().header().parentCloseTime.time_since_epoch().count();
if ((cancelAfter && closeTime >= *cancelAfter) || (expiration && closeTime >= *expiration))
return closeChannel(slep, ctx_.view(), k.key, ctx_.registry.getJournal("View"));
return closeChannel(slep, ctx_.view(), k.key, ctx_.registry.journal("View"));
}
if (src != txAccount)
@@ -60,14 +61,14 @@ PaymentChannelFund::doApply()
ctx_.view().update(slep);
}
auto const sle = ctx_.view().peek(keylet::account(txAccount));
if (!sle)
WritableAccountRoot acct(txAccount, ctx_.view());
if (!acct)
return tefINTERNAL; // LCOV_EXCL_LINE
{
// Check reserve and funds availability
auto const balance = (*sle)[sfBalance];
auto const reserve = ctx_.view().fees().accountReserve((*sle)[sfOwnerCount]);
auto const balance = (*acct)[sfBalance];
auto const reserve = ctx_.view().fees().accountReserve((*acct)[sfOwnerCount]);
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
@@ -77,7 +78,7 @@ PaymentChannelFund::doApply()
}
// do not allow adding funds if dst does not exist
if (AccountID const dst = (*slep)[sfDestination]; !ctx_.view().read(keylet::account(dst)))
if (AccountID const dst = (*slep)[sfDestination]; !AccountRoot(dst, ctx_.view()))
{
return tecNO_DST;
}
@@ -85,8 +86,8 @@ PaymentChannelFund::doApply()
(*slep)[sfAmount] = (*slep)[sfAmount] + ctx_.tx[sfAmount];
ctx_.view().update(slep);
(*sle)[sfBalance] = (*sle)[sfBalance] - ctx_.tx[sfAmount];
ctx_.view().update(sle);
(*acct)[sfBalance] = (*acct)[sfBalance] - ctx_.tx[sfAmount];
acct.update();
return tesSUCCESS;
}

View File

@@ -41,15 +41,16 @@ closeChannel(
}
// Transfer amount back to owner, decrement owner count
auto const sle = view.peek(keylet::account(src));
if (!sle)
WritableAccountRoot wrappedOwner(src, view);
if (!wrappedOwner)
return tefINTERNAL; // LCOV_EXCL_LINE
XRPL_ASSERT(
(*slep)[sfAmount] >= (*slep)[sfBalance], "xrpl::closeChannel : minimum channel amount");
(*sle)[sfBalance] = (*sle)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance];
adjustOwnerCount(view, sle, -1, j);
view.update(sle);
(*wrappedOwner)[sfBalance] =
(*wrappedOwner)[sfBalance] + (*slep)[sfAmount] - (*slep)[sfBalance];
wrappedOwner.adjustOwnerCount(-1, j);
wrappedOwner.update();
// Remove PayChan from ledger
view.erase(slep);

View File

@@ -44,7 +44,7 @@ PermissionedDomainDelete::doApply()
auto const slePd = view().peek(keylet::permissionedDomain(ctx_.tx.at(sfDomainID)));
auto const page = (*slePd)[sfOwnerNode];
if (!view().dirRemove(keylet::ownerDir(account_), page, slePd->key(), true))
if (!view().dirRemove(keylet::ownerDir(accountID_), page, slePd->key(), true))
{
// LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete permissioned domain directory entry.";
@@ -52,11 +52,11 @@ PermissionedDomainDelete::doApply()
// LCOV_EXCL_STOP
}
auto const ownerSle = view().peek(keylet::account(account_));
auto wrappedOwner = WritableAccountRoot(accountID_, view());
XRPL_ASSERT(
ownerSle && ownerSle->getFieldU32(sfOwnerCount) > 0,
wrappedOwner && wrappedOwner->getFieldU32(sfOwnerCount) > 0,
"xrpl::PermissionedDomainDelete::doApply : nonzero owner count");
adjustOwnerCount(view(), ownerSle, -1, ctx_.journal);
wrappedOwner.adjustOwnerCount(-1, ctx_.journal);
view().erase(slePd);
return tesSUCCESS;

View File

@@ -64,8 +64,8 @@ PermissionedDomainSet::preclaim(PreclaimContext const& ctx)
TER
PermissionedDomainSet::doApply()
{
auto const ownerSle = view().peek(keylet::account(account_));
if (!ownerSle)
WritableAccountRoot wrappedOwner(accountID_, view());
if (!wrappedOwner)
return tefINTERNAL; // LCOV_EXCL_LINE
auto const sortedTxCredentials =
@@ -92,26 +92,28 @@ PermissionedDomainSet::doApply()
{
// Create new permissioned domain.
// Check reserve availability for new object creation
auto const balance = STAmount((*ownerSle)[sfBalance]).xrp();
auto const reserve = ctx_.view().fees().accountReserve((*ownerSle)[sfOwnerCount] + 1);
auto const balance = STAmount((*wrappedOwner)[sfBalance]).xrp();
auto const reserve = ctx_.view().fees().accountReserve((*wrappedOwner)[sfOwnerCount] + 1);
if (balance < reserve)
return tecINSUFFICIENT_RESERVE;
Keylet const pdKeylet =
keylet::permissionedDomain(account_, ctx_.tx.getFieldU32(sfSequence));
keylet::permissionedDomain(accountID_, ctx_.tx.getFieldU32(sfSequence));
auto slePd = std::make_shared<SLE>(pdKeylet);
if (!slePd)
return tefINTERNAL; // LCOV_EXCL_LINE
slePd->setAccountID(sfOwner, account_);
slePd->setAccountID(sfOwner, accountID_);
slePd->setFieldU32(sfSequence, ctx_.tx.getFieldU32(sfSequence));
slePd->peekFieldArray(sfAcceptedCredentials) = std::move(sortedLE);
auto const page =
view().dirInsert(keylet::ownerDir(account_), pdKeylet, describeOwnerDir(account_));
view().dirInsert(keylet::ownerDir(accountID_), pdKeylet, describeOwnerDir(accountID_));
if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE
slePd->setFieldU64(sfOwnerNode, *page);
// If we succeeded, the new entry counts against the creator's reserve.
adjustOwnerCount(view(), ownerSle, 1, ctx_.journal);
wrappedOwner.adjustOwnerCount(1, ctx_.journal);
view().insert(slePd);
}

View File

@@ -136,7 +136,7 @@ Change::doApply()
void
Change::preCompute()
{
XRPL_ASSERT(account_ == beast::zero, "xrpl::Change::preCompute : zero account");
XRPL_ASSERT(accountID_ == beast::zero, "xrpl::Change::preCompute : zero account");
}
TER

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