Compare commits

..

17 Commits

Author SHA1 Message Date
Vito
5abb72ec0a test: Add withdrawal-to-issuer assertion in IOU global-freeze test
Mirror the MPT and trust-line-freeze variants: under global freeze the
redemption path (dstAcct == vaultAsset.getIssuer()) should still succeed.
2026-06-03 17:59:36 +02:00
Vito
42b7e858a4 test: Restore clawback-under-MPT-global-lock coverage
The previous edit dropped the assertion that clawback still works when
the MPT asset is globally locked. Restore it before the issuer-redemption
step, claw back 50 of the 100 deposited units, then withdraw the remaining
50 to the issuer so both behaviours are exercised in the same test.
2026-06-03 17:55:54 +02:00
Vito
3daf40c408 fix: clarifying comment 2026-06-03 17:43:30 +02:00
Vito
43fc095b1a fix: Use IgnoreFreeze in doApply for issuer-redemption withdrawals
Hoist dstAcct into doApply and use FreezeHandling::IgnoreFreeze for
accountHolds when dstAcct == vaultAsset.getIssuer() under fixCleanup3_2_0.
Without this the locked-share balance read as zero and the redemption
failed with tecINSUFFICIENT_FUNDS despite preclaim passing.

Update tests: issuer-redemption now succeeds end-to-end for both IOU and
MPT vaults.
2026-06-03 17:40:14 +02:00
Vito
45fa34de4b test: Add freeze-check tests for VaultWithdraw issuer guard
Verify the dstAcct != vaultAsset.getIssuer() guard introduced under
fixCleanup3_2_0: frozen vault trust line and MPT global lock both block
non-issuer withdrawals, while the issuer-destination path bypasses
preclaim's freeze checks (redemption path). Preclaim passes for the
issuer destination, but doApply::accountHolds(ZeroIfFrozen) still returns
0 for locked shares — a matching doApply fix is tracked via TODO comments.

Also updates expected error codes in existing freeze tests affected by
the new vault-sender and deep-frozen-destination checks.
2026-06-03 17:32:32 +02:00
Vito Tumas
250b0d2c25 Merge branch 'develop' into tapanito/vault-freeze-check 2026-06-02 18:22:08 +02:00
Vito
488e1be1dc fix: Check vault sender freeze and use checkDeepFrozen for destination
Under fixCleanup3_2_0, VaultWithdraw::preclaim now explicitly checks that
the vault pseudo-account (sender) is not frozen, and replaces the
destination checkFrozen with checkDeepFrozen — a frozen account can still
receive assets, only a deep-frozen one cannot.

Pre-amendment behaviour is preserved via the else branch. Tests are updated
to reflect the changed error codes and new pre/post amendment cases are
added for the vault-account and 3rd-party freeze scenarios.
2026-06-02 18:18:14 +02:00
Ayaz Salikhov
ad111bcc22 ci: Patch binaries in nix-based images and test in every distro (#7376)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-02 13:51:20 +00:00
Ayaz Salikhov
d4cb68d5a1 ci: Check binaries separately from building them (#7355)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-01 16:47:01 +00:00
dependabot[bot]
e209ee5371 ci: [DEPENDABOT] bump eps1lon/actions-label-merge-conflict from 3.0.3 to 3.1.0 (#7375)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-01 15:29:12 +00:00
Vito Tumas
109b649106 refactor: Use STLedgerEntry type aliases instead of std::shared_ptr (#7282) 2026-06-01 15:27:13 +00:00
Michael Legleux
0fffe23abc fix: Adjust xrpld systemd service and update timer (#7374) 2026-06-01 03:33:19 +00:00
Bart
7e15621e7b release: Bump version to 3.2.0-rc3 (#7371)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-05-31 22:55:18 +00:00
Vito Tumas
99431d7833 fix: Pin overpayment principal reduction to exact on-grid value (#7360) 2026-05-31 22:54:23 +00:00
Ed Hennis
47365f4220 fix: Improve upward rounding edge cases for Number::operator/= (#7328)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Vito Tumas <5780819+Tapanito@users.noreply.github.com>
2026-05-31 00:23:29 +00:00
Bart
1599c1a672 refactor: Revert "perf: Remove unnecessary caches (#5439)" (#7359)
Co-authored-by: Bart <11445373+bthomee@users.noreply.github.com>
2026-05-30 18:48:59 +00:00
yinyiqian1
763dd503be fix: Add zero domainID check for permissionedDomain (#7362) 2026-05-30 00:16:25 +00:00
324 changed files with 2657 additions and 6278 deletions

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check if PRs are dirty
uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3.0.3
uses: eps1lon/actions-label-merge-conflict@0273be72a0bbd58fcd71d0d6c02c209b50d1e5e1 # v3.1.0
with:
dirtyLabel: "PR: has conflicts"
repoToken: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -953,6 +953,21 @@
#
# Optional keys for NuDB and RocksDB:
#
# cache_size Size of cache for database records. Default is 16384.
# Setting this value to 0 will use the default value.
#
# cache_age Length of time in minutes to keep database records
# cached. Default is 5 minutes. Setting this value to
# 0 will use the default value.
#
# Note: if cache_size or cache_age is not specified,
# default values will be used for the unspecified
# parameter.
#
# Note: the cache will not be created if online_delete
# is specified, because the rotating NodeStore does
# not use this cache).
#
# fast_load Boolean. If set, load the last persisted ledger
# from disk upon process start before syncing to
# the network. This is likely to improve performance

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a ${name} ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit ${name}(std::shared_ptr<SLE const> sle)
explicit ${name}(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -168,7 +168,7 @@ ${field['typeData']['setter_type']} ${field['paramName']}${',' if i < len(requir
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
${name}Builder(std::shared_ptr<SLE const> sle)
${name}Builder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ${tag})
{

View File

@@ -1,48 +0,0 @@
#!/bin/bash
# Sanity-check that the sanitizer runtimes shipped with g++/clang++ work
# end-to-end against the system loader: compile each example with both
# compilers, run it, and confirm the expected diagnostic is emitted.
set -eo pipefail
cpp_files_dir="${1:?usage: $0 <cpp_files_dir>}"
case "$(uname -m)" in
x86_64) loader=/lib64/ld-linux-x86-64.so.2 ;;
aarch64) loader=/lib/ld-linux-aarch64.so.1 ;;
*)
echo "Unsupported arch: $(uname -m)" >&2
exit 1
;;
esac
declare -A sanitize=(
[asan]="-fsanitize=address"
[tsan]="-fsanitize=thread"
[ubsan]="-fsanitize=undefined"
)
declare -A expect=(
[asan]="heap-use-after-free"
[tsan]="data race"
[ubsan]="signed integer overflow"
)
for compiler in g++ clang++; do
for name in asan tsan ubsan; do
bin="/tmp/${name}-${compiler}"
echo "=== Build ${name} with ${compiler} ==="
"$compiler" -std=c++20 -O1 -g ${sanitize[$name]} \
-Wl,--dynamic-linker=$loader \
"${cpp_files_dir}/${name}.cpp" -o "$bin"
echo "=== Run ${name}-${compiler} ==="
output=$("$bin" 2>&1) || true
echo "$output"
echo "$output" | grep -q "${expect[$name]}" ||
{
echo "expected '${expect[$name]}' from $bin"
exit 1
}
rm -f "$bin"
done
done

24
docker/check-tool-versions.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Verify that every tool expected in the Nix CI env is present and runnable.
set -euo pipefail
ccache --version
clang --version
clang++ --version
clang-format --version
cmake --version
conan --version
g++ --version
gcc --version
gcovr --version
git --version
less --version
make --version
mold --version
ninja --version
perl --version
pkg-config --version
pre-commit --version
python3 --version
run-clang-tidy --help
vim --version

View File

@@ -0,0 +1,89 @@
#!/bin/bash
# Install sanitizer runtime libraries required to run binaries compiled with:
# -fsanitize=address → libasan.so.8
# -fsanitize=thread → libtsan.so.2
# -fsanitize=undefined → libubsan.so.1
#
# The exact SONAMEs required depend on the compiler toolchain used to build the
# test binaries (see nix/ci-env.nix). If the toolchain is bumped and SONAMEs
# change, update the list below (or detect them from the binaries).
#
# Supported base images:
# debian:bookworm
# ubuntu:20.04
# rhel:9
# nixos/nix — tests are skipped; this script is not called
set -euo pipefail
if [ ! -f /etc/os-release ]; then
echo "ERROR: /etc/os-release not found; cannot detect OS" >&2
exit 1
fi
# shellcheck source=/dev/null
. /etc/os-release
echo "Detected OS: ${ID} ${VERSION_ID:-}"
case "${ID}" in
debian)
apt-get update -y
apt-get install -y --no-install-recommends \
libasan8 \
libtsan2 \
libubsan1
apt-get clean
rm -rf /var/lib/apt/lists/*
;;
ubuntu)
apt-get update -y
apt-get install -y --no-install-recommends \
gnupg \
software-properties-common
add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt-get update -y
apt-get install -y --no-install-recommends \
libasan8 \
libtsan2 \
libubsan1
apt-get clean
rm -rf /var/lib/apt/lists/*
;;
rhel | centos | rocky | almalinux)
dnf install -y \
libasan8 \
libtsan2 \
libubsan
dnf clean -y all
rm -rf /var/cache/dnf/*
;;
*)
echo "ERROR: unsupported OS '${ID}'. Supported: debian, ubuntu, rhel-family" >&2
exit 1
;;
esac
# Verify that every expected library is now resolvable by the dynamic linker.
missing=0
for lib in libasan.so.8 libtsan.so.2 libubsan.so.1; do
if ldconfig -p | grep -q "${lib}"; then
echo "OK: ${lib} found"
else
echo "ERROR: ${lib} not found after installation" >&2
missing=$((missing + 1))
fi
done
if [ "${missing}" -ne 0 ]; then
echo "ERROR: ${missing} library/libraries missing" >&2
exit 1
fi
echo "All sanitizer runtime libraries installed successfully."

12
docker/loader-path.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
case "$(uname -m)" in
x86_64) LOADER=/lib64/ld-linux-x86-64.so.2 ;;
aarch64) LOADER=/lib/ld-linux-aarch64.so.1 ;;
*)
echo "Unsupported arch: $(uname -m)" >&2
exit 1
;;
esac
echo "${LOADER}"

View File

@@ -27,10 +27,12 @@ RUN mkdir /tmp/nix-store-closure && \
cp -R $(nix-store -qR result/) /tmp/nix-store-closure
# Final image
FROM ${BASE_IMAGE}
FROM ${BASE_IMAGE} AS final
ARG BASE_IMAGE
# bash is not located at /bin/bash in nixos/nix, so we need to create a symlink to it.
RUN if [ -d /nix ]; then \
RUN if echo "${BASE_IMAGE}" | grep -qiE 'nixos'; then \
ln -s /root/.nix-profile/bin/bash /bin/bash; \
fi
@@ -43,53 +45,64 @@ ENTRYPOINT ["/bin/bash"]
COPY --from=builder /tmp/nix-store-closure /nix/store
COPY --from=builder /tmp/build/result /nix/ci-env
ENV PATH="/nix/ci-env/bin:$PATH"
ENV PATH="/nix/ci-env/bin:${PATH}"
# Externally-built dynamically-linked ELF binaries hard-code the loader path
# (e.g. /lib64/ld-linux-x86-64.so.2) in their PT_INTERP header. Copy the
# loader from the Nix store to that path when the base image doesn't already
# provide one (i.e. on nixos/nix).
# (e.g. /lib64/ld-linux-x86-64.so.2) in their PT_INTERP header. Install it
# from the Nix store when the base image doesn't already provide one.
COPY docker/loader-path.sh /tmp/loader-path.sh
RUN <<EOF
case "$(uname -m)" in
x86_64) target=/lib64/ld-linux-x86-64.so.2 ;;
aarch64) target=/lib/ld-linux-aarch64.so.1 ;;
*) echo "Unsupported arch: $(uname -m)" >&2; exit 1 ;;
esac
if [ ! -e "$target" ]; then
target="$(/tmp/loader-path.sh)"
if [ ! -e "${target}" ]; then
# Use the loader from the same glibc that gcc links libc against, so
# ld-linux and libc/libpthread share GLIBC_PRIVATE symbols at runtime.
src="$(dirname "$(gcc -print-file-name=libc.so.6)")/$(basename "$target")"
[ -e "$src" ] || { echo "ld-linux not found at $src" >&2; exit 1; }
mkdir -p "$(dirname "$target")"
cp "$src" "$target"
src="$(dirname "$(gcc -print-file-name=libc.so.6)")/$(basename "${target}")"
[ -e "${src}" ] || { echo "ld-linux not found at ${src}" >&2; exit 1; }
mkdir -p "$(dirname "${target}")"
cp "${src}" "${target}"
fi
EOF
COPY docker/check-tool-versions.sh /tmp/check-tool-versions.sh
RUN /tmp/check-tool-versions.sh
# Sanity-check that the g++/clang++ are able to build binaries, including sanitizer-instrumented ones.
COPY docker/test_files/cpp_sources/ /tmp/cpp_sources/
COPY docker/test_files/compile-cpp-sources.sh /tmp/compile-cpp-sources.sh
RUN /tmp/compile-cpp-sources.sh /tmp/cpp_sources /tmp/bins
# Tester: start from a clean BASE_IMAGE, install sanitizer runtime libraries,
# and run the compiled test binaries to verify they execute correctly.
FROM ${BASE_IMAGE} AS tester
ARG BASE_IMAGE
# bash is not located at /bin/bash in nixos/nix, so we need to create a symlink to it.
RUN if echo "${BASE_IMAGE}" | grep -qiE 'nixos'; then \
ln -s /root/.nix-profile/bin/bash /bin/bash; \
fi
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
# Sanity-check that the built binaries run correctly in the vanilla base image, with the necessary sanitizer runtime libraries installed.
COPY docker/install-sanitizer-libs.sh /tmp/install-sanitizer-libs.sh
COPY docker/test_files/run-test-binaries.sh /tmp/run-test-binaries.sh
COPY --from=final /tmp/bins /tmp/bins
RUN <<EOF
ccache --version
clang --version
clang++ --version
clang-format --version
cmake --version
conan --version
g++ --version
gcc --version
gcovr --version
git --version
make --version
mold --version
ninja --version
perl --version
pkg-config --version
pre-commit --version
python3 --version
run-clang-tidy --help
vim --version
if echo "${BASE_IMAGE}" | grep -qiE 'nixos'; then
echo "Skipping runnning binaries on NixOS."
else
/tmp/install-sanitizer-libs.sh
/tmp/run-test-binaries.sh /tmp/bins
fi
touch /tmp/tests-passed
EOF
# Sanity-check that the sanitizer runtimes shipped with g++/clang++ work
# end-to-end against the system loader.
COPY docker/cpp_files/ /tmp/cpp_files/
COPY docker/check-sanitizers.sh /tmp/check-sanitizers.sh
RUN grep -qi ubuntu /etc/os-release 2>/dev/null && /tmp/check-sanitizers.sh /tmp/cpp_files || true
# Output: the final image, gated on a successful test run in the tester stage.
# Copying the sentinel from tester creates a hard build dependency: if the test
# run above failed, this stage — and the overall build — fails too.
FROM final
COPY --from=tester /tmp/tests-passed /tmp/tests-passed

View File

@@ -0,0 +1,57 @@
#!/bin/bash
# Compile all C++ test binaries during the Docker image build.
# Each binary has the target system's ELF PT_INTERP (dynamic-linker path)
# baked in so it can run on the (potentially minimal) final BASE_IMAGE.
set -eo pipefail
src_dir="${1:?usage: $0 <src_dir> <dst_dir>}"
dst_dir="${2:?usage: $0 <src_dir> <dst_dir>}"
loader="$(/tmp/loader-path.sh)"
mkdir -p "${dst_dir}"
function compile() {
local compiler="${1}"
local name="${2}"
local san_flag="${3:-}"
local src="${src_dir}/${name}.cpp"
local binary="${dst_dir}/${name}-${compiler}"
echo "=== Compiling ${name} with ${compiler} ==="
# Always statically link libstdc++ so the test binary does not depend on
# the host's libstdc++.so.6 version.
local compile_cmd="${compiler} -std=c++23 -O1 -g \
-pthread \
-static-libstdc++ \
${san_flag} \
${src} -o ${binary}"
echo "Compile cmd: ${compile_cmd}"
eval "${compile_cmd}"
echo "=== Patching ${binary} to use ${loader} as PT_INTERP ==="
local patch_cmd="patchelf --set-interpreter ${loader} --remove-rpath ${binary}"
echo "Patch cmd: ${patch_cmd}"
eval "${patch_cmd}"
}
declare -A sanitize=(
[regular]=""
[asan]="-fsanitize=address"
[tsan]="-fsanitize=thread"
[ubsan]="-fsanitize=undefined -fno-sanitize-recover=all"
)
for name in regular asan tsan ubsan; do
san_flag="${sanitize[${name}]}"
for compiler in g++ clang++; do
compile "${compiler}" "${name}" "${san_flag}"
done
done
echo "=== All binaries compiled ==="
ls -la "${dst_dir}"

View File

@@ -0,0 +1,28 @@
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
static std::mutex gMutex;
void
worker(int id)
{
std::lock_guard<std::mutex> lock(gMutex);
std::cout << "Hello from thread " << id << "\n";
}
int
main()
{
constexpr int kNumThreads = 10;
std::vector<std::thread> threads;
threads.reserve(kNumThreads);
for (int i = 0; i < kNumThreads; ++i)
threads.emplace_back(worker, i);
for (auto& t : threads)
t.join();
std::cout << "Hello from main thread\n";
return 0;
}

View File

@@ -0,0 +1,86 @@
#!/bin/bash
# Run pre-compiled sanitizer binaries and confirm each emits its expected diagnostic.
# Binaries must already exist in <bins_dir> with the layout:
# <name>-g++ and <name>-clang++ for name in {regular,asan,tsan,ubsan}
set -eo pipefail
bins_dir="${1:?usage: $0 <bins_dir>}"
failed_binaries=()
# Run a binary and verify its exit code and output.
# Usage: run <binary> <expected_output> <expected_rc>
function run() {
local binary="${1}"
local expected_output="${2}"
local expected_rc="${3}"
local out_file
out_file="$(mktemp)"
echo "=== Run ${binary} ==="
set +e
"${binary}" >"${out_file}" 2>&1
local rc=$?
set -e
cat "${out_file}"
local failed=0
if [ "${expected_rc}" = "nonzero" ]; then
if [ "${rc}" -eq 0 ]; then
echo "ERROR: expected non-zero exit code from ${binary}, got ${rc}" >&2
failed=1
fi
elif [ "${rc}" -ne "${expected_rc}" ]; then
echo "ERROR: expected exit code ${expected_rc} from ${binary}, got ${rc}" >&2
failed=1
fi
if ! grep -q "${expected_output}" "${out_file}"; then
echo "ERROR: expected '${expected_output}' from ${binary}" >&2
failed=1
fi
if [ "${failed}" -eq 0 ]; then
echo "OK: '${expected_output}' detected"
else
failed_binaries+=("${binary}")
fi
}
declare -A expect=(
[regular]="Hello from main thread"
[asan]="heap-use-after-free"
[tsan]="data race"
[ubsan]="signed integer overflow"
)
for compiler in g++ clang++; do
for name in regular asan tsan ubsan; do
binary="${bins_dir}/${name}-${compiler}"
if [ "${name}" = "tsan" ] && [ "${compiler}" = "g++" ] &&
grep -qi 'debian' /etc/os-release 2>/dev/null &&
[ "$(uname -m)" = "aarch64" ]; then
echo "=== Skipping ${binary} (tsan-g++ unsupported on Debian ARM64) ==="
echo " NOTE: to enable it, add --security-opt seccomp=unconfined to your docker run command"
continue
fi
if [ "${name}" = "regular" ]; then
expected_rc=0
else
expected_rc=nonzero
fi
run "${binary}" "${expect[$name]}" "${expected_rc}"
done
done
if [ "${#failed_binaries[@]}" -gt 0 ]; then
echo "ERROR: the following binaries failed:" >&2
printf ' %s\n' "${failed_binaries[@]}" >&2
exit 1
fi

View File

@@ -2,12 +2,14 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <array>
#include <cstdint>
#include <functional>
#include <limits>
#include <optional>
#include <ostream>
#include <set>
#include <stdexcept>
#include <string>
#include <unordered_map>
@@ -40,6 +42,47 @@ isPowerOfTen(T value)
return logTen(value).has_value();
}
namespace detail {
/** Builds a table of the powers of 10
*
* This function is marked consteval, so it can only be run in
* a constexpr context. This assures that it is and can only be run at
* compile time. Doing it at runtime would be pretty wasteful and
* inefficient.
*/
constexpr std::size_t kInt64Digits = 20;
consteval std::array<std::uint64_t, kInt64Digits>
buildPowersOfTen()
{
std::array<std::uint64_t, kInt64Digits> result{};
std::uint64_t power = 1;
std::size_t exponent = 0;
// end the loop early so it doesn't overflow;
for (; exponent < result.size() - 1; ++exponent, power *= 10)
{
result[exponent] = power;
if (power > std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is too big");
}
result[exponent] = power;
if (power < std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is not big enough for the uint64_t type");
return result;
}
} // namespace detail
constexpr std::array<std::uint64_t, detail::kInt64Digits> kPowerOfTen = detail::buildPowersOfTen();
static_assert(kPowerOfTen[0] == 1);
static_assert(kPowerOfTen[1] == 10);
static_assert(kPowerOfTen[10] == 10'000'000'000);
static_assert(
isPowerOfTen(kPowerOfTen.back()) && *logTen(kPowerOfTen.back()) == detail::kInt64Digits - 1);
/** MantissaRange defines a range for the mantissa of a normalized Number.
*
* The mantissa is in the range [min, max], where
@@ -76,6 +119,7 @@ isPowerOfTen(T value)
struct MantissaRange final
{
using rep = std::uint64_t;
enum class MantissaScale {
Small,
// LargeLegacy can be removed when fixCleanup3_2_0 is retired
@@ -89,19 +133,15 @@ struct MantissaRange final
Enabled = true,
};
explicit constexpr MantissaRange(MantissaScale scale)
: min(getMin(scale))
, cuspRoundingFixEnabled(isCuspFixEnabled(scale))
, log(logTen(min).value_or(-1))
, scale(scale)
explicit constexpr MantissaRange(MantissaScale sc) : scale(sc)
{
}
rep min;
rep max{(min * 10) - 1};
CuspRoundingFix cuspRoundingFixEnabled;
int log;
MantissaScale scale;
MantissaScale const scale;
int const log{getExponent(scale)};
rep const min{getMin(scale, log)};
rep const max{(min * 10) - 1};
CuspRoundingFix const cuspRoundingFixEnabled{isCuspFixEnabled(scale)};
static MantissaRange const&
getMantissaRange(MantissaScale scale);
@@ -110,23 +150,35 @@ struct MantissaRange final
getAllScales();
private:
static constexpr rep
getMin(MantissaScale scale)
static constexpr int
getExponent(MantissaScale scale)
{
switch (scale)
{
case MantissaScale::Small:
return 1'000'000'000'000'000ULL;
return 15;
case MantissaScale::LargeLegacy:
case MantissaScale::Large:
return 1'000'000'000'000'000'000ULL;
return 18;
// LCOV_EXCL_START
default:
// If called in a constexpr context, this throw assures that the build fails if an
// invalid scale is used.
throw std::runtime_error("Unknown mantissa scale"); // LCOV_EXCL_LINE
throw std::runtime_error("Unknown mantissa scale");
// LCOV_EXCL_STOP
}
}
// Keep this function for future use with different ways to compute
// the ranges.
static constexpr rep
getMin(MantissaScale scale, int exponent)
{
if (exponent < 0 || exponent >= kPowerOfTen.size())
throw std::runtime_error("Invalid exponent"); // LCOV_EXCL_LINE
return kPowerOfTen[exponent];
}
static constexpr CuspRoundingFix
isCuspFixEnabled(MantissaScale scale)
{
@@ -477,8 +529,7 @@ public:
template <
auto MinMantissa,
auto MaxMantissa,
Integral64 T = std::decay_t<decltype(MinMantissa)>,
Integral64 TMax = std::decay_t<decltype(MaxMantissa)>>
Integral64 T = std::decay_t<decltype(MinMantissa)>>
[[nodiscard]]
std::pair<T, int>
normalizeToRange() const;
@@ -519,7 +570,8 @@ private:
int& exponent,
MantissaRange::rep const& minMantissa,
MantissaRange::rep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled);
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled,
bool dropped);
[[nodiscard]] bool
isnormal() const noexcept;
@@ -725,16 +777,18 @@ Number::isnormal() const noexcept
kMinExponent <= exponent_ && exponent_ <= kMaxExponent);
}
template <auto MinMantissa, auto MaxMantissa, Integral64 T, Integral64 TMax>
template <auto MinMantissa, auto MaxMantissa, Integral64 T>
std::pair<T, int>
Number::normalizeToRange() const
{
static_assert(std::is_same_v<T, std::uint64_t> || std::is_same_v<T, std::int64_t>);
static_assert(std::is_same_v<T, TMax>);
static_assert(std::is_same_v<T, std::decay_t<decltype(MinMantissa)>>);
static_assert(std::is_same_v<T, std::decay_t<decltype(MaxMantissa)>>);
auto constexpr kMIN = static_cast<T>(MinMantissa);
auto constexpr kMAX = static_cast<T>(MaxMantissa);
static_assert(kMIN > 0);
static_assert(kMIN % 10 == 0);
static_assert(isPowerOfTen(kMIN));
static_assert(kMAX % 10 == 9);
static_assert((kMAX + 1) / 10 == kMIN);

View File

@@ -157,7 +157,7 @@ public:
/** Fetch an item from the cache.
If the digest was not found, Handler
will be called with this signature:
std::shared_ptr<SLE const>(void)
SLE::const_pointer(void)
*/
template <class Handler>
SharedPointerType

View File

@@ -123,7 +123,7 @@ private:
bool preserveOrder,
Keylet const& directory,
uint256 const& key,
std::function<void(std::shared_ptr<SLE> const&)> const& describe);
std::function<void(SLE::ref)> const& describe);
public:
ApplyView() = default;
@@ -153,7 +153,7 @@ public:
@return `nullptr` if the key is not present
*/
virtual std::shared_ptr<SLE>
virtual SLE::pointer
peek(Keylet const& k) = 0;
/** Remove a peeked SLE.
@@ -168,7 +168,7 @@ public:
The key is no longer associated with the SLE.
*/
virtual void
erase(std::shared_ptr<SLE> const& sle) = 0;
erase(SLE::ref sle) = 0;
/** Insert a new state SLE
@@ -189,7 +189,7 @@ public:
@note The key is taken from the SLE
*/
virtual void
insert(std::shared_ptr<SLE> const& sle) = 0;
insert(SLE::ref sle) = 0;
/** Indicate changes to a peeked SLE
@@ -208,7 +208,7 @@ public:
*/
/** @{ */
virtual void
update(std::shared_ptr<SLE> const& sle) = 0;
update(SLE::ref sle) = 0;
//--------------------------------------------------------------------------
@@ -301,7 +301,7 @@ public:
dirAppend(
Keylet const& directory,
Keylet const& key,
std::function<void(std::shared_ptr<SLE> const&)> const& describe)
std::function<void(SLE::ref)> const& describe)
{
if (key.type != ltOFFER)
{
@@ -340,7 +340,7 @@ public:
dirInsert(
Keylet const& directory,
uint256 const& key,
std::function<void(std::shared_ptr<SLE> const&)> const& describe)
std::function<void(SLE::ref)> const& describe)
{
return dirAdd(false, directory, key, describe);
}
@@ -349,7 +349,7 @@ public:
dirInsert(
Keylet const& directory,
Keylet const& key,
std::function<void(std::shared_ptr<SLE> const&)> const& describe)
std::function<void(SLE::ref)> const& describe)
{
return dirAdd(false, directory, key.key, describe);
}
@@ -411,7 +411,7 @@ createRoot(
ApplyView& view,
Keylet const& directory,
uint256 const& key,
std::function<void(std::shared_ptr<SLE> const&)> const& describe);
std::function<void(SLE::ref)> const& describe);
auto
findPreviousPage(ApplyView& view, Keylet const& directory, SLE::ref start);
@@ -434,7 +434,7 @@ insertPage(
SLE::ref next,
uint256 const& key,
Keylet const& directory,
std::function<void(std::shared_ptr<SLE> const&)> const& describe);
std::function<void(SLE::ref)> const& describe);
} // namespace directory
} // namespace xrpl

View File

@@ -67,8 +67,8 @@ public:
std::function<void(
uint256 const& key,
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after)> const& func);
SLE::const_ref before,
SLE::const_ref after)> const& func);
private:
std::optional<STAmount> deliver_;

View File

@@ -11,13 +11,13 @@ private:
uint256 const root_;
uint256 const nextQuality_;
uint256 const key_;
std::shared_ptr<SLE const> sle_ = nullptr;
SLE::const_pointer sle_ = nullptr;
unsigned int entry_ = 0;
uint256 index_;
public:
class const_iterator; // NOLINT(readability-identifier-naming)
using value_type = std::shared_ptr<SLE const>;
using value_type = SLE::const_pointer;
BookDirs(ReadView const&, Book const&);
@@ -76,7 +76,7 @@ private:
uint256 nextQuality_;
uint256 key_;
uint256 curKey_;
std::shared_ptr<SLE const> sle_;
SLE::const_pointer sle_;
unsigned int entry_ = 0;
uint256 index_;
std::optional<value_type> mutable cache_;

View File

@@ -36,7 +36,7 @@ public:
bool
exists(Keylet const& k) const override;
std::shared_ptr<SLE const>
SLE::const_pointer
read(Keylet const& k) const override;
bool

View File

@@ -1,229 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/hardened_hash.h>
#include <array>
#include <cstdint>
#include <functional>
#include <unordered_map>
#include <vector>
namespace xrpl {
/** An inner-node position in a SHAMap that needs hash recomputation.
Plan 7's deferred-rebuild algorithm walks bottom-up, recomputing
each affected inner node's hash from its children. `AffectedNode`
identifies one such node by:
* depth: 0 = root, 1..63 = inner nodes, 64 = leaf (not included
in the plan output — only inner nodes are rebuilt)
* prefix: the leaf-key's first `depth*4` bits, with the remainder
zeroed. Two nodes at the same depth with the same
prefix are the same node.
*/
struct AffectedNode
{
int depth;
uint256 prefix;
[[nodiscard]] bool
operator==(AffectedNode const& other) const noexcept
{
return depth == other.depth && prefix == other.prefix;
}
};
/** Plan which inner nodes need rebuild for a given set of leaf changes.
Returns the union of ancestor paths of all `modifiedKeys`, sorted
by depth descending so a bottom-up rebuild can iterate the result
and find each level's nodes before the level above.
The returned plan contains only INNER nodes (depths 0..63). The
leaves themselves are at depth 64 and are not in the plan — they
are the modifications, not nodes to be rebuilt.
Complexity: O(K * 64) where K is `modifiedKeys.size()`. For real
workloads (~thousands of modifications), this is microseconds.
*/
[[nodiscard]] std::vector<AffectedNode>
planDeferredRebuild(std::vector<uint256> const& modifiedKeys);
/** Compute the hash of a SHAMap inner node from its 16 children.
Byte-identical to `SHAMapInnerNode::updateHash()`:
sha512_half(
HashPrefix::InnerNode (4 bytes, big-endian) ||
child[0] (32 bytes) ||
child[1] (32 bytes) ||
...
child[15] (32 bytes))
This is the elementary operation of plan-7's bottom-up rebuild:
given the (already-computed) 16 child hashes of an inner node,
produce that node's hash. Empty branches are passed as zero
uint256 — the same convention SHAMap uses.
Pure function; no SHAMap state, no allocation beyond a stack buffer.
*/
[[nodiscard]] uint256
computeInnerNodeHash(std::array<uint256, 16> const& childHashes);
/** Hash combiner for AffectedNode keys in unordered_map. */
struct AffectedNodeHash
{
[[nodiscard]] std::size_t
operator()(AffectedNode const& n) const noexcept
{
// Mix depth into the high bits of a hash of prefix.
std::size_t h = 0;
for (auto b : n.prefix)
h = h * 31 + b;
return h ^ (static_cast<std::size_t>(n.depth) << 56);
}
};
/** Map of recomputed inner-node hashes keyed by (depth, prefix). */
using RebuildResult =
std::unordered_map<AffectedNode, uint256, AffectedNodeHash>;
/** Walk a depth-descending plan and compute each affected node's new hash.
For each AffectedNode in the plan (deepest first), collect its 16
child hashes:
* If a child position is itself in the plan (and already
computed, since we walk deepest-first), use the computed hash.
* Otherwise, fall back to `getOriginalChildHash` — the callback
is expected to walk the parent SHAMap to find the hash at that
position.
Then `computeInnerNodeHash` over the 16 children yields the
affected node's new hash. The result map contains every entry in
the plan keyed by its (depth, prefix).
@param plan
Depth-descending plan from `planDeferredRebuild`.
@param getOriginalChildHash
Callable `uint256(int depth, uint256 const& prefix)` returning
the hash at the given position in the parent SHAMap. May
return uint256{} for absent positions.
@note Pure function; safe to call concurrently with disjoint plans.
*/
template <typename GetChildHashFn>
[[nodiscard]] RebuildResult
executeRebuildPlan(
std::vector<AffectedNode> const& plan,
GetChildHashFn getOriginalChildHash);
namespace detail {
// Forwarder for template instantiation; declared here, defined in .cpp.
[[nodiscard]] RebuildResult
executeRebuildPlanImpl(
std::vector<AffectedNode> const& plan,
std::function<uint256(int, uint256 const&)> getOriginalChildHash);
} // namespace detail
template <typename GetChildHashFn>
[[nodiscard]] RebuildResult
executeRebuildPlan(
std::vector<AffectedNode> const& plan,
GetChildHashFn getOriginalChildHash)
{
return detail::executeRebuildPlanImpl(
plan,
std::function<uint256(int, uint256 const&)>(
std::move(getOriginalChildHash)));
}
/** End-to-end deferred rebuild: produce the new SHAMap root hash.
Combines `planDeferredRebuild` + `executeRebuildPlan` into one call.
This is the consumer-facing API — the integration site only needs
to supply the set of modified keys and a callback that reads the
parent SHAMap. No AffectedNode plumbing is exposed.
@param modifiedKeys
Keys whose leaves have been added/replaced/deleted in this
ledger close. Empty → no rebuild; returns the existing root
via the callback at (depth=0, prefix=zero).
@param getOriginalChildHash
Callable `uint256(int depth, uint256 const& prefix)` returning
the hash at the given position in the parent SHAMap. May return
uint256{} for absent positions.
@return The new SHAMap root hash.
*/
template <typename GetChildHashFn>
[[nodiscard]] uint256
deferredRebuildRoot(
std::vector<uint256> const& modifiedKeys,
GetChildHashFn getOriginalChildHash)
{
if (modifiedKeys.empty())
return getOriginalChildHash(0, uint256{});
auto const plan = planDeferredRebuild(modifiedKeys);
auto const result = executeRebuildPlan(plan, std::move(getOriginalChildHash));
AffectedNode const rootKey{0, uint256{}};
auto const it = result.find(rootKey);
if (it == result.end())
return uint256{};
return it->second;
}
/** Partition modified keys by their first nibble (0..15).
At depth 1 the root has 16 child subtrees, one per first-nibble
value. Keys in different subtrees rebuild independently, so this
partition is the basis for plan-7 P7.3's parallel-by-subtree
rebuild.
Returns 16 buckets, one per first-nibble value, each containing
only the keys whose first nibble matches the bucket index.
*/
[[nodiscard]] std::array<std::vector<uint256>, 16>
partitionByFirstNibble(std::vector<uint256> const& modifiedKeys);
namespace detail {
[[nodiscard]] uint256
deferredRebuildRootParallelImpl(
std::vector<uint256> const& modifiedKeys,
std::function<uint256(int, uint256 const&)> getOriginalChildHash);
} // namespace detail
/** Parallel deferred rebuild: partition by first nibble, rebuild each
of the 16 subtrees in parallel, combine into the root.
Equivalent to `deferredRebuildRoot` in output; differs only in
execution strategy. Useful when the parent SHAMap is large enough
that the rebuild cost matters per-close. For small workloads
(handful of modifications), the serial path is faster — threading
overhead exceeds the work saved.
@param modifiedKeys
Keys whose leaves have been added/replaced/deleted.
@param getOriginalChildHash
Thread-safe callable; will be invoked concurrently from
multiple subtree workers.
@return The new SHAMap root hash, byte-identical to
`deferredRebuildRoot` over the same inputs.
*/
template <typename GetChildHashFn>
[[nodiscard]] uint256
deferredRebuildRootParallel(
std::vector<uint256> const& modifiedKeys,
GetChildHashFn getOriginalChildHash)
{
return detail::deferredRebuildRootParallelImpl(
modifiedKeys,
std::function<uint256(int, uint256 const&)>(
std::move(getOriginalChildHash)));
}
} // namespace xrpl

View File

@@ -22,12 +22,12 @@ class Dir
private:
ReadView const* view_ = nullptr;
Keylet root_;
std::shared_ptr<SLE const> sle_;
SLE::const_pointer sle_;
STVector256 const* indexes_ = nullptr;
public:
class ConstIterator;
using value_type = std::shared_ptr<SLE const>;
using value_type = SLE::const_pointer;
Dir(ReadView const&, Keylet const&);
@@ -102,7 +102,7 @@ private:
Keylet page_;
uint256 index_;
std::optional<value_type> mutable cache_;
std::shared_ptr<SLE const> sle_;
SLE::const_pointer sle_;
STVector256 const* indexes_ = nullptr;
std::vector<uint256>::const_iterator it_;
};

View File

@@ -1,347 +0,0 @@
#pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/hardened_hash.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <cstddef>
#include <iterator>
#include <memory>
#include <shared_mutex>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace xrpl {
/** Flat keylet-indexed materialization of XRPL state.
The SHAMap is XRPL's authoritative state structure — it produces
the state root that consensus agrees on. But on its own, it forces
every state read to walk the trie: ~610 spinlocked inner-node
fetches per `read(Keylet)`.
`FlatStateMap` materializes the same keylet → SLE mapping into a
flat hash table. Once populated, lookups are a single
`unordered_map::find()` — nanoseconds, not microseconds.
This is the 2-writes-for-1-read pattern (Plan 6):
* On apply, the apply path dual-writes to SHAMap and FlatStateMap.
* On read, only FlatStateMap is consulted.
The flat map is purely auxiliary. The SHAMap remains authoritative,
can always be rebuilt from the underlying NodeStore, and is what the
network's state-root commitment is computed from. If FlatStateMap is
wrong, the differential invariant check at ledger close (Plan 6 P6.5)
catches it; there is **no runtime fallback to SHAMap descent on
miss** — a miss is a bug.
Thread-safe via a shared_mutex. Concurrent reads do not block each
other; writes are exclusive. Future phases may replace this with
a lock-free atomic-pointer-swap design.
*/
class FlatStateMap
{
public:
using key_type = uint256;
using value_type = std::shared_ptr<STLedgerEntry const>;
FlatStateMap() = default;
~FlatStateMap() = default;
// Non-copyable, non-movable. The map owns a shared_mutex (not movable)
// and a potentially large hash table; callers that need ownership
// transfer should wrap in std::unique_ptr<FlatStateMap>.
FlatStateMap(FlatStateMap const&) = delete;
FlatStateMap&
operator=(FlatStateMap const&) = delete;
FlatStateMap(FlatStateMap&&) = delete;
FlatStateMap&
operator=(FlatStateMap&&) = delete;
/** Look up an SLE by its SHAMap key.
Returns nullptr if the key is not in the map. In Plan 6's pure
2w/1r model, callers reading state that *should* exist treat
nullptr as a precondition violation — there is no fallback path
that would recover from a missed entry.
*/
[[nodiscard]] value_type
read(key_type const& key) const;
/** Test whether an SLE is present. O(1). */
[[nodiscard]] bool
exists(key_type const& key) const;
/** Insert a new SLE. Replaces any prior entry under the same key.
Used by both:
* the apply path's `view.insert()` (new ledger object), and
* the apply path's `view.update()` (mutating an existing SLE
produces a new shared_ptr value).
*/
void
insert(key_type const& key, value_type sle);
/** Remove an SLE. No-op if the key is absent. */
void
erase(key_type const& key);
/** Number of SLEs currently materialized. */
[[nodiscard]] std::size_t
size() const;
/** Test whether the map is empty. O(1). */
[[nodiscard]] bool
empty() const;
/** Remove every entry. Used by tests and by snapshot reset. */
void
clear();
/** Deep-copy snapshot of the current state.
The snapshot is a frozen FlatStateMap (returned by value-like
unique_ptr) that shares the underlying SLE objects via
shared_ptr but has its own hash table. Subsequent writes to the
source FlatStateMap do not affect the snapshot.
Snapshot cost is O(N) in entry count — ~one pointer copy per
entry plus bucket allocation. For current mainnet (~10M SLEs)
this is ~100200 ms; expensive enough that snapshots should be
per-ledger-close, not per-transaction.
A future phase will replace this with a persistent / HAMT
structure that gives O(log N) snapshot and structural sharing
across versions.
*/
[[nodiscard]] std::unique_ptr<FlatStateMap>
snapshot() const;
/** Visit every (key, SLE) pair under a single shared lock.
@param visitor Called as `void(key_type const&, value_type const&)`.
The lock is held for the duration of the iteration; visitors
must not call back into the same FlatStateMap (deadlock /
recursive shared_lock UB). Visitors that want to mutate state
should collect keys first and apply mutations after iteration
returns.
*/
template <typename F>
void
forEach(F&& visitor) const
{
std::shared_lock<std::shared_mutex> lock(mutex_);
for (auto const& [key, sle] : map_)
visitor(key, sle);
}
private:
using HashFn = HardenedHash<>;
using MapType = std::unordered_map<key_type, value_type, HashFn>;
mutable std::shared_mutex mutex_;
MapType map_;
};
// Forward declarations to avoid pulling heavy headers into this file.
class ReadView;
class Ledger;
/** Populate a FlatStateMap from every SLE in a ReadView.
Used at node startup to build the flat materialization from a
SHAMap-backed authoritative ledger. Cost is O(N) iterations of
`view.sles`, each of which descends the SHAMap, so this is
expected to take seconds-to-minutes for a current mainnet-sized
ledger (~10M SLEs). Run once on startup; subsequent ledgers are
maintained incrementally via dual-write at apply time (P6.3).
@pre `target` is empty. (Not enforced — replacing existing entries
is well-defined, but mixing populated state with an externally-
provided ReadView is a bug-shaped pattern; assert in DEBUG.)
*/
void
populateFromReadView(FlatStateMap& target, ReadView const& source);
/** Populate a FlatStateMap from any forward range of `shared_ptr<SLE const>`.
Lower-level building block underlying `populateFromReadView`. Useful
in tests (the range can be a `std::vector<shared_ptr<SLE const>>`)
and in non-ReadView contexts (e.g., reloading a persisted flat-map
sidecar at startup).
The range element type must be `shared_ptr<SLE const>` (or
implicitly convertible). Each element's `.key()` becomes the
FlatStateMap key.
*/
template <typename Range>
void
populateFromRange(FlatStateMap& target, Range const& sles)
{
for (auto const& sle : sles)
target.insert(sle->key(), sle);
}
// ---------------------------------------------------------------------------
// Mirror helpers (P6.3).
//
// The xrpld `RawView` interface defines three pure-virtual methods that
// every state mutation flows through: `rawInsert`, `rawReplace`, and
// `rawErase`. In plan-6's 2-writes-for-1-read pattern, every such call
// must also update the flat map. These helpers perform the flat-map side
// of that dual-write — they exist as standalone functions (rather than
// methods on FlatStateMap) so the Ledger integration is a one-line
// addition at each `raw*` override site, with no FlatStateMap class
// surface added for purely Ledger-specific semantics.
//
// Permissive semantics: `mirrorRawReplace` on an absent key inserts;
// `mirrorRawErase` on an absent key is a no-op. The SHAMap side enforces
// the precondition (replace requires existence); the flat mirror ensures
// the post-state matches whatever the SHAMap committed. If the caller
// gets it wrong, the differential invariant check at close (P6.5) is the
// stop-the-line gate.
// ---------------------------------------------------------------------------
void
mirrorRawInsert(FlatStateMap& map, std::shared_ptr<STLedgerEntry const> sle);
void
mirrorRawReplace(FlatStateMap& map, std::shared_ptr<STLedgerEntry const> sle);
void
mirrorRawErase(FlatStateMap& map, std::shared_ptr<STLedgerEntry const> const& sle);
void
mirrorRawErase(FlatStateMap& map, uint256 const& key);
// ---------------------------------------------------------------------------
// Keylet-aware read (P6.4).
//
// This is the read-side counterpart to `mirrorRaw*` — the testable unit
// underlying `Ledger::read(Keylet)`'s flat-map path. It looks up the
// SLE by `k.key` and verifies the SLE matches the keylet's expected
// type via `Keylet::check`. On either a miss or a type mismatch, it
// returns nullptr — matching the contract of `Ledger::read`.
//
// Plan 6 v2 semantics: this function does not consult a SHAMap or any
// other source on miss. When a FlatStateMap is the read source of
// truth, a miss IS the answer. The differential invariant check at
// close (P6.5) is what makes that safe.
// ---------------------------------------------------------------------------
std::shared_ptr<STLedgerEntry const>
readFromFlatStateMap(FlatStateMap const& map, Keylet const& k);
// ---------------------------------------------------------------------------
// Differential invariant (P6.5).
//
// At every ledger close, the flat map's key-set must match the
// SHAMap's key-set. `diffFlatStateKeys` produces both sides of the
// disagreement; `flatStateMapMatches` is the boolean predicate the
// hot-path integration calls (and fails the close if it returns false).
//
// Content drift (right keys, wrong SLE bodies) is a separate, stronger
// invariant. It's prevented by construction: the mirror helpers write
// exactly the SLE the caller passed to raw*. If mirror helpers and
// wiring are both correct, the membership check above is sufficient.
// ---------------------------------------------------------------------------
struct FlatStateKeyDiff
{
std::vector<uint256> missingFromFlat;
std::vector<uint256> extraInFlat;
};
template <typename SourceRange>
[[nodiscard]] FlatStateKeyDiff
diffFlatStateKeys(FlatStateMap const& flat, SourceRange const& sourceKeys)
{
FlatStateKeyDiff diff;
// Pass 1: walk source keys; collect any absent from flat. Record
// which keys we've seen so pass 2 can spot phantoms.
std::unordered_set<uint256, HardenedHash<>> seen;
seen.reserve(static_cast<std::size_t>(std::distance(
std::begin(sourceKeys), std::end(sourceKeys))));
for (auto const& key : sourceKeys)
{
seen.insert(key);
if (!flat.exists(key))
diff.missingFromFlat.push_back(key);
}
// Pass 2: walk flat; anything not in `seen` is a phantom.
flat.forEach(
[&seen, &diff](uint256 const& key, auto const& /*sle*/) {
if (!seen.contains(key))
diff.extraInFlat.push_back(key);
});
return diff;
}
template <typename SourceRange>
[[nodiscard]] bool
flatStateMapMatches(FlatStateMap const& flat, SourceRange const& sourceKeys)
{
auto const diff = diffFlatStateKeys(flat, sourceKeys);
return diff.missingFromFlat.empty() && diff.extraInFlat.empty();
}
/** Compare a FlatStateMap against a SHAMap-like source.
`ShaMapLike` is any range whose elements expose a `key()` accessor
returning a `uint256`. The real `SHAMap` satisfies this contract
(its iterators yield `SHAMapItem`s with `.key()`), as does the
`MockShaMapItem` used in tests.
This is the helper the Ledger integration calls to run the P6.5
differential invariant. It extracts keys into a transient buffer
(O(N) allocation, ~N pointers' worth of memory) and forwards to
`flatStateMapMatches`. The transient buffer is acceptable at close
cadence; the integration can later optimize by walking the SHAMap
in-place once profiling shows the allocation matters.
*/
template <typename ShaMapLike>
[[nodiscard]] bool
flatStateMapMatchesShaMap(FlatStateMap const& flat, ShaMapLike const& shaMap)
{
std::vector<uint256> keys;
for (auto const& item : shaMap)
keys.push_back(item.key());
return flatStateMapMatches(flat, keys);
}
// ---------------------------------------------------------------------------
// A-phase integration: attach a populated FlatStateMap to a Ledger.
//
// This is the public entry point a node or test uses to "turn on" the
// flat-map read path for a Ledger. The function:
// 1. Allocates a new FlatStateMap.
// 2. Eagerly populates it by walking every SLE in the Ledger.
// 3. Attaches it via `Ledger::setFlatStateMap`.
//
// After this call:
// * `Ledger::flatStateMap()` returns the populated map
// * `Ledger::read(keylet)` routes through the flat map (no SHAMap
// descent on the hot path; see P6.4 wiring)
// * `Ledger::raw{Insert,Replace,Erase}` mirror writes to the flat
// map alongside the SHAMap (see P6.3 wiring)
// * `Ledger::validateFlatStateMapMatchesShaMap()` returns true
//
// Repeat calls discard the prior map and produce a fresh one.
//
// Cost: O(N) walk over the Ledger's state SHAMap to populate the flat
// map. For mainnet-scale state, this is bounded by SHAMap traversal
// speed — typically minutes once. Run at node startup or whenever a
// Ledger first becomes "live" (the one apply writes to).
// ---------------------------------------------------------------------------
void
attachFlatStateMapTo(Ledger& ledger);
} // namespace xrpl

View File

@@ -14,7 +14,6 @@
namespace xrpl {
class FlatStateMap;
class ServiceRegistry;
class Job;
class TransactionMaster;
@@ -167,7 +166,7 @@ public:
std::optional<uint256>
succ(uint256 const& key, std::optional<uint256> const& last = std::nullopt) const override;
std::shared_ptr<SLE const>
SLE::const_pointer
read(Keylet const& k) const override;
std::unique_ptr<SlesType::iter_base>
@@ -203,16 +202,16 @@ public:
//
void
rawErase(std::shared_ptr<SLE> const& sle) override;
rawErase(SLE::ref sle) override;
void
rawInsert(std::shared_ptr<SLE> const& sle) override;
rawInsert(SLE::ref sle) override;
void
rawErase(uint256 const& key);
void
rawReplace(std::shared_ptr<SLE> const& sle) override;
rawReplace(SLE::ref sle) override;
void
rawDestroyXRP(XRPAmount const& fee) override
@@ -362,41 +361,9 @@ public:
bool
isVotingLedger() const;
std::shared_ptr<SLE>
SLE::pointer
peek(Keylet const& k) const;
//
// Flat-state mirror (Plan 6 P6.3).
//
// When a FlatStateMap is attached, every successful `raw*` call below
// mirrors the operation into the map via the matching `mirrorRaw*`
// helper. With no map attached (the default), the ledger behaves
// exactly as before — no allocation, no mutex, no observable change.
// The map's lifetime is managed by the caller (typically the
// Application owns the live ledger's map).
//
void
setFlatStateMap(std::shared_ptr<FlatStateMap> map);
[[nodiscard]] std::shared_ptr<FlatStateMap>
flatStateMap() const;
/** Run the Plan 6 P6.5 differential invariant.
Returns true iff (a) no FlatStateMap is attached (vacuously
true — there is no second source of truth to disagree), or
(b) the attached FlatStateMap's key-set matches the SHAMap's
key-set exactly.
Intended to be called at ledger close, before the new state
root is published. A false return is a stop-the-line bug —
the integrator should crash rather than publish a state root
that disagrees with the read path.
*/
[[nodiscard]] bool
validateFlatStateMapMatchesShaMap() const;
private:
class SlesIterImpl;
class TxsIterImpl;
@@ -433,11 +400,6 @@ private:
// A SHAMap containing the state objects for this ledger.
SHAMap mutable stateMap_;
// Optional flat keylet→SLE mirror. When non-null, every successful
// raw* state mutation is mirrored into this map. See FlatStateMap.h
// and the Plan 6 docs in tasks/.
std::shared_ptr<FlatStateMap> mutable flatStateMap_;
// Protects fee variables
std::mutex mutable mutex_;

View File

@@ -197,7 +197,7 @@ public:
std::optional<key_type>
succ(key_type const& key, std::optional<key_type> const& last = std::nullopt) const override;
std::shared_ptr<SLE const>
SLE::const_pointer
read(Keylet const& k) const override;
std::unique_ptr<SlesType::iter_base>
@@ -224,13 +224,13 @@ public:
// RawView
void
rawErase(std::shared_ptr<SLE> const& sle) override;
rawErase(SLE::ref sle) override;
void
rawInsert(std::shared_ptr<SLE> const& sle) override;
rawInsert(SLE::ref sle) override;
void
rawReplace(std::shared_ptr<SLE> const& sle) override;
rawReplace(SLE::ref sle) override;
void
rawDestroyXRP(XRPAmount const& fee) override;

View File

@@ -25,7 +25,7 @@ public:
can calculate metadata.
*/
virtual void
rawErase(std::shared_ptr<SLE> const& sle) = 0;
rawErase(SLE::ref sle) = 0;
/** Unconditionally insert a state item.
@@ -39,7 +39,7 @@ public:
@note The key is taken from the SLE
*/
virtual void
rawInsert(std::shared_ptr<SLE> const& sle) = 0;
rawInsert(SLE::ref sle) = 0;
/** Unconditionally replace a state item.
@@ -54,7 +54,7 @@ public:
@note The key is taken from the SLE
*/
virtual void
rawReplace(std::shared_ptr<SLE> const& sle) = 0;
rawReplace(SLE::ref sle) = 0;
/** Destroy XRP.

View File

@@ -34,9 +34,9 @@ public:
using key_type = uint256;
using mapped_type = std::shared_ptr<SLE const>;
using mapped_type = SLE::const_pointer;
struct SlesType : detail::ReadViewFwdRange<std::shared_ptr<SLE const>>
struct SlesType : detail::ReadViewFwdRange<SLE::const_pointer>
{
explicit SlesType(ReadView const& view);
[[nodiscard]] Iterator
@@ -143,7 +143,7 @@ public:
@return `nullptr` if the key is not present or
if the type does not match.
*/
[[nodiscard]] virtual std::shared_ptr<SLE const>
[[nodiscard]] virtual SLE::const_pointer
read(Keylet const& k) const = 0;
// Accounts in a payment are not allowed to use assets acquired during that

View File

@@ -12,7 +12,6 @@
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <utility>
@@ -135,7 +134,7 @@ areCompatible(
dirLink(
ApplyView& view,
AccountID const& owner,
std::shared_ptr<SLE>& object,
SLE::pointer& object,
SF_UINT64 const& node = sfOwnerNode);
/** Checks that can withdraw funds from an object to itself or a destination.
@@ -215,8 +214,8 @@ doWithdraw(
* (if should not be skipped) and if the entry should be skipped. The status
* is always tesSUCCESS if the entry should be skipped.
*/
using EntryDeleter = std::function<
std::pair<TER, SkipEntry>(LedgerEntryType, uint256 const&, std::shared_ptr<SLE>&)>;
using EntryDeleter =
std::function<std::pair<TER, SkipEntry>(LedgerEntryType, uint256 const&, SLE::pointer&)>;
/** Cleanup owner directory entries on account delete.
* Used for a regular and AMM accounts deletion. The caller
* has to provide the deleter function, which handles details of

View File

@@ -8,8 +8,6 @@
#include <xrpl/protocol/TxMeta.h>
#include <xrpl/protocol/XRPAmount.h>
#include <memory>
namespace xrpl::detail {
// Helper class that buffers modifications
@@ -26,7 +24,7 @@ private:
Modify,
};
using items_t = std::map<key_type, std::pair<Action, std::shared_ptr<SLE>>>;
using items_t = std::map<key_type, std::pair<Action, SLE::pointer>>;
items_t items_;
XRPAmount dropsDestroyed_{0};
@@ -60,10 +58,10 @@ public:
[[nodiscard]] std::optional<key_type>
succ(ReadView const& base, key_type const& key, std::optional<key_type> const& last) const;
[[nodiscard]] std::shared_ptr<SLE const>
[[nodiscard]] SLE::const_pointer
read(ReadView const& base, Keylet const& k) const;
std::shared_ptr<SLE>
SLE::pointer
peek(ReadView const& base, Keylet const& k);
[[nodiscard]] std::size_t
@@ -75,23 +73,23 @@ public:
std::function<void(
uint256 const& key,
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after)> const& func) const;
SLE::const_ref before,
SLE::const_ref after)> const& func) const;
void
erase(ReadView const& base, std::shared_ptr<SLE> const& sle);
erase(ReadView const& base, SLE::ref sle);
void
rawErase(ReadView const& base, std::shared_ptr<SLE> const& sle);
rawErase(ReadView const& base, SLE::ref sle);
void
insert(ReadView const& base, std::shared_ptr<SLE> const& sle);
insert(ReadView const& base, SLE::ref sle);
void
update(ReadView const& base, std::shared_ptr<SLE> const& sle);
update(ReadView const& base, SLE::ref sle);
void
replace(ReadView const& base, std::shared_ptr<SLE> const& sle);
replace(ReadView const& base, SLE::ref sle);
void
destroyXRP(XRPAmount const& fee);
@@ -104,12 +102,12 @@ public:
}
private:
using Mods = hash_map<key_type, std::shared_ptr<SLE>>;
using Mods = hash_map<key_type, SLE::pointer>;
static void
threadItem(TxMeta& meta, std::shared_ptr<SLE> const& to);
threadItem(TxMeta& meta, SLE::ref to);
std::shared_ptr<SLE>
SLE::pointer
getForMod(ReadView const& base, key_type const& key, Mods& mods, beast::Journal j);
void
@@ -119,7 +117,7 @@ private:
threadOwners(
ReadView const& base,
TxMeta& meta,
std::shared_ptr<SLE const> const& sle,
SLE::const_ref sle,
Mods& mods,
beast::Journal j);
};

View File

@@ -40,7 +40,7 @@ public:
[[nodiscard]] std::optional<key_type>
succ(key_type const& key, std::optional<key_type> const& last = std::nullopt) const override;
[[nodiscard]] std::shared_ptr<SLE const>
[[nodiscard]] SLE::const_pointer
read(Keylet const& k) const override;
[[nodiscard]] std::unique_ptr<SlesType::iter_base>
@@ -69,28 +69,28 @@ public:
[[nodiscard]] ApplyFlags
flags() const override;
std::shared_ptr<SLE>
SLE::pointer
peek(Keylet const& k) override;
void
erase(std::shared_ptr<SLE> const& sle) override;
erase(SLE::ref sle) override;
void
insert(std::shared_ptr<SLE> const& sle) override;
insert(SLE::ref sle) override;
void
update(std::shared_ptr<SLE> const& sle) override;
update(SLE::ref sle) override;
// RawView
void
rawErase(std::shared_ptr<SLE> const& sle) override;
rawErase(SLE::ref sle) override;
void
rawInsert(std::shared_ptr<SLE> const& sle) override;
rawInsert(SLE::ref sle) override;
void
rawReplace(std::shared_ptr<SLE> const& sle) override;
rawReplace(SLE::ref sle) override;
void
rawDestroyXRP(XRPAmount const& feeDrops) override;

View File

@@ -49,15 +49,15 @@ public:
succ(ReadView const& base, key_type const& key, std::optional<key_type> const& last) const;
void
erase(std::shared_ptr<SLE> const& sle);
erase(SLE::ref sle);
void
insert(std::shared_ptr<SLE> const& sle);
insert(SLE::ref sle);
void
replace(std::shared_ptr<SLE> const& sle);
replace(SLE::ref sle);
[[nodiscard]] std::shared_ptr<SLE const>
[[nodiscard]] SLE::const_pointer
read(ReadView const& base, Keylet const& k) const;
void
@@ -84,10 +84,10 @@ private:
struct SleAction
{
Action action;
std::shared_ptr<SLE> sle;
SLE::pointer sle;
// Constructor needed for emplacement in std::map
SleAction(Action action, std::shared_ptr<SLE> const& sle) : action(action), sle(sle)
SleAction(Action action, SLE::pointer sle) : action(action), sle(std::move(sle))
{
}
};

View File

@@ -792,7 +792,7 @@ deleteAMMAccount(Sandbox& view, Asset const& asset, Asset const& asset2, beast::
void
initializeFeeAuctionVote(
ApplyView& view,
std::shared_ptr<SLE>& ammSle,
SLE::pointer& ammSle,
AccountID const& account,
Asset const& lptAsset,
std::uint16_t tfee);
@@ -812,7 +812,7 @@ Expected<bool, TER>
verifyAndAdjustLPTokenBalance(
Sandbox& sb,
STAmount const& lpTokens,
std::shared_ptr<SLE>& ammSle,
SLE::pointer& ammSle,
AccountID const& account);
} // namespace xrpl

View File

@@ -9,7 +9,6 @@
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
#include <memory>
#include <set>
#include <vector>
@@ -36,11 +35,7 @@ xrpLiquid(ReadView const& view, AccountID const& id, std::int32_t ownerCountAdj,
/** Adjust the owner count up or down. */
void
adjustOwnerCount(
ApplyView& view,
std::shared_ptr<SLE> const& sle,
std::int32_t amount,
beast::Journal j);
adjustOwnerCount(ApplyView& view, SLE::ref 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
@@ -76,9 +71,7 @@ getPseudoAccountFields();
- null pointer
*/
[[nodiscard]] bool
isPseudoAccount(
std::shared_ptr<SLE const> sleAcct,
std::set<SField const*> const& pseudoFieldFilter = {});
isPseudoAccount(SLE::const_pointer sleAcct, std::set<SField const*> const& pseudoFieldFilter = {});
/** Convenience overload that reads the account from the view. */
[[nodiscard]] inline bool
@@ -98,7 +91,7 @@ isPseudoAccount(
* before using a field. The amendment check is **not** performed in
* createPseudoAccount.
*/
[[nodiscard]] Expected<std::shared_ptr<SLE>, TER>
[[nodiscard]] Expected<SLE::pointer, TER>
createPseudoAccount(ApplyView& view, uint256 const& pseudoOwnerKey, SField const& ownerField);
/** Checks the destination and tag.

View File

@@ -23,7 +23,7 @@ checkExpired(SLE const& sleCredential, NetClock::time_point const& closed);
// Actually remove a credentials object from the ledger
[[nodiscard]] TER
deleteSLE(ApplyView& view, std::shared_ptr<SLE> const& sleCredential, beast::Journal j);
deleteSLE(ApplyView& view, SLE::ref sleCredential, beast::Journal j);
// Amendment and parameters checks for sfCredentialIDs field
NotTEC
@@ -70,7 +70,7 @@ verifyDepositPreauth(
ApplyView& view,
AccountID const& src,
AccountID const& dst,
std::shared_ptr<SLE const> const& sleDst,
SLE::const_ref sleDst,
beast::Journal j);
} // namespace xrpl

View File

@@ -15,7 +15,7 @@ namespace xrpl {
* if not.
*/
NotTEC
checkTxPermission(std::shared_ptr<SLE const> const& delegate, STTx const& tx);
checkTxPermission(SLE::const_ref delegate, STTx const& tx);
/**
* Load the granular permissions granted to the delegate account for the
@@ -28,7 +28,7 @@ checkTxPermission(std::shared_ptr<SLE const> const& delegate, STTx const& tx);
*/
void
loadGranularPermission(
std::shared_ptr<SLE const> const& delegate,
SLE::const_ref delegate,
TxType const& type,
std::unordered_set<GranularPermissionType>& granularPermissions);

View File

@@ -115,7 +115,7 @@ bool
cdirFirst(
ReadView const& view,
uint256 const& root,
std::shared_ptr<SLE const>& page,
SLE::const_pointer& page,
unsigned int& index,
uint256& entry);
@@ -123,7 +123,7 @@ bool
dirFirst(
ApplyView& view,
uint256 const& root,
std::shared_ptr<SLE>& page,
SLE::pointer& page,
unsigned int& index,
uint256& entry);
/** @} */
@@ -147,7 +147,7 @@ bool
cdirNext(
ReadView const& view,
uint256 const& root,
std::shared_ptr<SLE const>& page,
SLE::const_pointer& page,
unsigned int& index,
uint256& entry);
@@ -155,17 +155,14 @@ bool
dirNext(
ApplyView& view,
uint256 const& root,
std::shared_ptr<SLE>& page,
SLE::pointer& page,
unsigned int& index,
uint256& entry);
/** @} */
/** Iterate all items in the given directory. */
void
forEachItem(
ReadView const& view,
Keylet const& root,
std::function<void(std::shared_ptr<SLE const> const&)> const& f);
forEachItem(ReadView const& view, Keylet const& root, std::function<void(SLE::const_ref)> const& f);
/** Iterate all items after an item in the given directory.
@param after The key of the item to start after
@@ -180,14 +177,11 @@ forEachItemAfter(
uint256 const& after,
std::uint64_t const hint,
unsigned int limit,
std::function<bool(std::shared_ptr<SLE const> const&)> const& f);
std::function<bool(SLE::const_ref)> const& f);
/** Iterate all items in an account's owner directory. */
inline void
forEachItem(
ReadView const& view,
AccountID const& id,
std::function<void(std::shared_ptr<SLE const> const&)> const& f)
forEachItem(ReadView const& view, AccountID const& id, std::function<void(SLE::const_ref)> const& f)
{
forEachItem(view, keylet::ownerDir(id), f);
}
@@ -205,7 +199,7 @@ forEachItemAfter(
uint256 const& after,
std::uint64_t const hint,
unsigned int limit,
std::function<bool(std::shared_ptr<SLE const> const&)> const& f)
std::function<bool(SLE::const_ref)> const& f)
{
return forEachItemAfter(view, keylet::ownerDir(id), after, hint, limit, f);
}

View File

@@ -18,7 +18,7 @@ TER
escrowUnlockApplyHelper(
ApplyView& view,
Rate lockedRate,
std::shared_ptr<SLE> const& sleDest,
SLE::ref sleDest,
STAmount const& xrpBalance,
STAmount const& amount,
AccountID const& issuer,
@@ -32,7 +32,7 @@ inline TER
escrowUnlockApplyHelper<Issue>(
ApplyView& view,
Rate lockedRate,
std::shared_ptr<SLE> const& sleDest,
SLE::ref sleDest,
STAmount const& xrpBalance,
STAmount const& amount,
AccountID const& issuer,
@@ -162,7 +162,7 @@ inline TER
escrowUnlockApplyHelper<MPTIssue>(
ApplyView& view,
Rate lockedRate,
std::shared_ptr<SLE> const& sleDest,
SLE::ref sleDest,
STAmount const& xrpBalance,
STAmount const& amount,
AccountID const& issuer,

View File

@@ -461,6 +461,7 @@ loanAccruedInterest(
ExtendedPaymentComponents
computeOverpaymentComponents(
Rules const& rules,
Asset const& asset,
int32_t const loanScale,
Number const& overpayment,

View File

@@ -28,10 +28,9 @@ findToken(ReadView const& view, AccountID const& owner, uint256 const& nftokenID
struct TokenAndPage
{
STObject token;
std::shared_ptr<SLE> page;
SLE::pointer page;
TokenAndPage(STObject token, std::shared_ptr<SLE> page)
: token(std::move(token)), page(std::move(page))
TokenAndPage(STObject token, SLE::pointer page) : token(std::move(token)), page(std::move(page))
{
}
};
@@ -47,11 +46,7 @@ TER
removeToken(ApplyView& view, AccountID const& owner, uint256 const& nftokenID);
TER
removeToken(
ApplyView& view,
AccountID const& owner,
uint256 const& nftokenID,
std::shared_ptr<SLE> const& page);
removeToken(ApplyView& view, AccountID const& owner, uint256 const& nftokenID, SLE::ref page);
/** Deletes the given token offer.
@@ -63,7 +58,7 @@ removeToken(
The offer also consumes one incremental reserve.
*/
bool
deleteTokenOffer(ApplyView& view, std::shared_ptr<SLE> const& offer);
deleteTokenOffer(ApplyView& view, SLE::ref offer);
/** Repairs the links in an NFTokenPage directory.

View File

@@ -5,8 +5,6 @@
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/TER.h>
#include <memory>
namespace xrpl {
/** Delete an offer.
@@ -23,6 +21,6 @@ namespace xrpl {
*/
// [[nodiscard]] // nodiscard commented out so Flow, BookTip and others compile.
TER
offerDelete(ApplyView& view, std::shared_ptr<SLE> const& sle, beast::Journal j);
offerDelete(ApplyView& view, SLE::ref sle, beast::Journal j);
} // namespace xrpl

View File

@@ -8,10 +8,6 @@
namespace xrpl {
TER
closeChannel(
std::shared_ptr<SLE> const& slep,
ApplyView& view,
uint256 const& key,
beast::Journal j);
closeChannel(SLE::ref slep, ApplyView& view, uint256 const& key, beast::Journal j);
} // namespace xrpl

View File

@@ -154,7 +154,7 @@ trustCreate(
[[nodiscard]] TER
trustDelete(
ApplyView& view,
std::shared_ptr<SLE> const& sleRippleState,
SLE::ref sleRippleState,
AccountID const& uLowAccountID,
AccountID const& uHighAccountID,
beast::Journal j);
@@ -248,7 +248,7 @@ removeEmptyHolding(
[[nodiscard]] TER
deleteAMMTrustLine(
ApplyView& view,
std::shared_ptr<SLE> sleState,
SLE::pointer sleState,
std::optional<AccountID> const& ammAccountID,
beast::Journal j);
@@ -258,7 +258,7 @@ deleteAMMTrustLine(
[[nodiscard]] TER
deleteAMMMPToken(
ApplyView& view,
std::shared_ptr<SLE> sleMPT,
SLE::pointer sleMPT,
AccountID const& ammAccountID,
beast::Journal j);

View File

@@ -5,7 +5,6 @@
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <memory>
#include <optional>
namespace xrpl {
@@ -21,10 +20,7 @@ namespace xrpl {
@return The number of shares, or nullopt on error.
*/
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& assets);
assetsToSharesDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount const& assets);
/** From the perspective of a vault, return the number of assets to take from
depositor when they receive a fixed amount of shares. Note, since shares are
@@ -37,10 +33,7 @@ assetsToSharesDeposit(
@return The number of assets, or nullopt on error.
*/
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
STAmount const& shares);
sharesToAssetsDeposit(SLE::const_ref vault, SLE::const_ref issuance, STAmount const& shares);
/** Controls whether to truncate shares instead of rounding. */
enum class TruncateShares : bool { No = false, Yes = true };
@@ -69,8 +62,8 @@ enum class WaiveUnrealizedLoss : bool { No = false, Yes = true };
*/
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
SLE::const_ref vault,
SLE::const_ref issuance,
STAmount const& assets,
TruncateShares truncate = TruncateShares::No,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
@@ -89,8 +82,8 @@ assetsToSharesWithdraw(
*/
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
std::shared_ptr<SLE const> const& vault,
std::shared_ptr<SLE const> const& issuance,
SLE::const_ref vault,
SLE::const_ref issuance,
STAmount const& shares,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
@@ -104,9 +97,6 @@ sharesToAssetsWithdraw(
both the share MPTID and the outstanding-amount total.
*/
[[nodiscard]] bool
isSoleShareholder(
ReadView const& view,
AccountID const& account,
std::shared_ptr<SLE const> const& issuance);
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref issuance);
} // namespace xrpl

View File

@@ -131,6 +131,10 @@ public:
std::uint32_t ledgerSeq,
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback);
/** Remove expired entries from the positive and negative caches. */
virtual void
sweep() = 0;
/** Gather statistics pertaining to read and write activities.
*
* @param obj Json object reference into which to place counters.

View File

@@ -22,6 +22,32 @@ public:
beast::Journal j)
: Database(scheduler, readThreads, config, j), backend_(std::move(backend))
{
std::optional<int> cacheSize, cacheAge;
if (config.exists("cache_size"))
{
cacheSize = get<int>(config, "cache_size");
if (cacheSize.value() < 0)
Throw<std::runtime_error>("Specified negative value for cache_size");
}
if (config.exists("cache_age"))
{
cacheAge = get<int>(config, "cache_age");
if (cacheAge.value() < 0)
Throw<std::runtime_error>("Specified negative value for cache_age");
}
if (cacheSize.has_value() || cacheAge.has_value())
{
cache_ = std::make_shared<TaggedCache<uint256, NodeObject>>(
"DatabaseNodeImp",
cacheSize.value_or(0),
std::chrono::minutes(cacheAge.value_or(0)),
stopwatch(),
j);
}
XRPL_ASSERT(
backend_,
"xrpl::NodeStore::DatabaseNodeImp::DatabaseNodeImp : non-null "
@@ -73,7 +99,13 @@ public:
std::uint32_t ledgerSeq,
std::function<void(std::shared_ptr<NodeObject> const&)>&& callback) override;
void
sweep() override;
private:
// Cache for database objects. This cache is not always initialized. Check
// for null before using.
std::shared_ptr<TaggedCache<uint256, NodeObject>> cache_;
// Persistent key/value storage
std::shared_ptr<Backend> backend_;

View File

@@ -55,6 +55,9 @@ public:
void
sync() override;
void
sweep() override;
private:
std::shared_ptr<Backend> writableBackend_;
std::shared_ptr<Backend> archiveBackend_;

View File

@@ -27,7 +27,7 @@ public:
* @brief Construct a ledger entry wrapper from an existing SLE object.
* @param sle The underlying serialized ledger entry to wrap
*/
explicit LedgerEntryBase(std::shared_ptr<SLE const> sle) : sle_(std::move(sle))
explicit LedgerEntryBase(SLE::const_pointer sle) : sle_(std::move(sle))
{
}
@@ -151,7 +151,7 @@ public:
* @return A constant reference to the underlying SLE object
*/
[[nodiscard]]
std::shared_ptr<SLE const>
SLE::const_pointer
getSle() const
{
return sle_;
@@ -159,7 +159,7 @@ public:
protected:
/** @brief The underlying serialized ledger entry being wrapped. */
std::shared_ptr<SLE const> sle_;
SLE::const_pointer sle_;
};
} // namespace xrpl::ledger_entries

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a AMM ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit AMM(std::shared_ptr<SLE const> sle)
explicit AMM(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -256,7 +256,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
AMMBuilder(std::shared_ptr<SLE const> sle)
AMMBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltAMM)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a AccountRoot ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit AccountRoot(std::shared_ptr<SLE const> sle)
explicit AccountRoot(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -555,7 +555,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
AccountRootBuilder(std::shared_ptr<SLE const> sle)
AccountRootBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltACCOUNT_ROOT)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Amendments ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Amendments(std::shared_ptr<SLE const> sle)
explicit Amendments(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -166,7 +166,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
AmendmentsBuilder(std::shared_ptr<SLE const> sle)
AmendmentsBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltAMENDMENTS)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Bridge ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Bridge(std::shared_ptr<SLE const> sle)
explicit Bridge(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -210,7 +210,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
BridgeBuilder(std::shared_ptr<SLE const> sle)
BridgeBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltBRIDGE)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Check ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Check(std::shared_ptr<SLE const> sle)
explicit Check(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -269,7 +269,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
CheckBuilder(std::shared_ptr<SLE const> sle)
CheckBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltCHECK)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Credential ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Credential(std::shared_ptr<SLE const> sle)
explicit Credential(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -219,7 +219,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
CredentialBuilder(std::shared_ptr<SLE const> sle)
CredentialBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltCREDENTIAL)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a DID ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit DID(std::shared_ptr<SLE const> sle)
explicit DID(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -193,7 +193,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
DIDBuilder(std::shared_ptr<SLE const> sle)
DIDBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltDID)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Delegate ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Delegate(std::shared_ptr<SLE const> sle)
explicit Delegate(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -172,7 +172,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
DelegateBuilder(std::shared_ptr<SLE const> sle)
DelegateBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltDELEGATE)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a DepositPreauth ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit DepositPreauth(std::shared_ptr<SLE const> sle)
explicit DepositPreauth(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -170,7 +170,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
DepositPreauthBuilder(std::shared_ptr<SLE const> sle)
DepositPreauthBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltDEPOSIT_PREAUTH)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a DirectoryNode ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit DirectoryNode(std::shared_ptr<SLE const> sle)
explicit DirectoryNode(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -431,7 +431,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
DirectoryNodeBuilder(std::shared_ptr<SLE const> sle)
DirectoryNodeBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltDIR_NODE)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Escrow ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Escrow(std::shared_ptr<SLE const> sle)
explicit Escrow(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -363,7 +363,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
EscrowBuilder(std::shared_ptr<SLE const> sle)
EscrowBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltESCROW)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a FeeSettings ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit FeeSettings(std::shared_ptr<SLE const> sle)
explicit FeeSettings(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -285,7 +285,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
FeeSettingsBuilder(std::shared_ptr<SLE const> sle)
FeeSettingsBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltFEE_SETTINGS)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a LedgerHashes ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit LedgerHashes(std::shared_ptr<SLE const> sle)
explicit LedgerHashes(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -130,7 +130,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
LedgerHashesBuilder(std::shared_ptr<SLE const> sle)
LedgerHashesBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltLEDGER_HASHES)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Loan ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Loan(std::shared_ptr<SLE const> sle)
explicit Loan(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -607,7 +607,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
LoanBuilder(std::shared_ptr<SLE const> sle)
LoanBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltLOAN)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a LoanBroker ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit LoanBroker(std::shared_ptr<SLE const> sle)
explicit LoanBroker(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -378,7 +378,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
LoanBrokerBuilder(std::shared_ptr<SLE const> sle)
LoanBrokerBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltLOAN_BROKER)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a MPToken ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit MPToken(std::shared_ptr<SLE const> sle)
explicit MPToken(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -182,7 +182,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
MPTokenBuilder(std::shared_ptr<SLE const> sle)
MPTokenBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltMPTOKEN)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a MPTokenIssuance ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit MPTokenIssuance(std::shared_ptr<SLE const> sle)
explicit MPTokenIssuance(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -339,7 +339,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
MPTokenIssuanceBuilder(std::shared_ptr<SLE const> sle)
MPTokenIssuanceBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltMPTOKEN_ISSUANCE)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a NFTokenOffer ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit NFTokenOffer(std::shared_ptr<SLE const> sle)
explicit NFTokenOffer(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -208,7 +208,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
NFTokenOfferBuilder(std::shared_ptr<SLE const> sle)
NFTokenOfferBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltNFTOKEN_OFFER)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a NFTokenPage ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit NFTokenPage(std::shared_ptr<SLE const> sle)
explicit NFTokenPage(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -157,7 +157,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
NFTokenPageBuilder(std::shared_ptr<SLE const> sle)
NFTokenPageBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltNFTOKEN_PAGE)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a NegativeUNL ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit NegativeUNL(std::shared_ptr<SLE const> sle)
explicit NegativeUNL(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -190,7 +190,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
NegativeUNLBuilder(std::shared_ptr<SLE const> sle)
NegativeUNLBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltNEGATIVE_UNL)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Offer ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Offer(std::shared_ptr<SLE const> sle)
explicit Offer(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -259,7 +259,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
OfferBuilder(std::shared_ptr<SLE const> sle)
OfferBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltOFFER)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Oracle ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Oracle(std::shared_ptr<SLE const> sle)
explicit Oracle(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -222,7 +222,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
OracleBuilder(std::shared_ptr<SLE const> sle)
OracleBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltORACLE)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a PayChannel ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit PayChannel(std::shared_ptr<SLE const> sle)
explicit PayChannel(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -330,7 +330,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
PayChannelBuilder(std::shared_ptr<SLE const> sle)
PayChannelBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltPAYCHAN)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a PermissionedDomain ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit PermissionedDomain(std::shared_ptr<SLE const> sle)
explicit PermissionedDomain(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -148,7 +148,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
PermissionedDomainBuilder(std::shared_ptr<SLE const> sle)
PermissionedDomainBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltPERMISSIONED_DOMAIN)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a RippleState ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit RippleState(std::shared_ptr<SLE const> sle)
explicit RippleState(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -278,7 +278,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
RippleStateBuilder(std::shared_ptr<SLE const> sle)
RippleStateBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltRIPPLE_STATE)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a SignerList ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit SignerList(std::shared_ptr<SLE const> sle)
explicit SignerList(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -172,7 +172,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
SignerListBuilder(std::shared_ptr<SLE const> sle)
SignerListBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltSIGNER_LIST)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Ticket ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Ticket(std::shared_ptr<SLE const> sle)
explicit Ticket(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -134,7 +134,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
TicketBuilder(std::shared_ptr<SLE const> sle)
TicketBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltTICKET)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a Vault ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit Vault(std::shared_ptr<SLE const> sle)
explicit Vault(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -330,7 +330,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
VaultBuilder(std::shared_ptr<SLE const> sle)
VaultBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltVAULT)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a XChainOwnedClaimID ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit XChainOwnedClaimID(std::shared_ptr<SLE const> sle)
explicit XChainOwnedClaimID(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -187,7 +187,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
XChainOwnedClaimIDBuilder(std::shared_ptr<SLE const> sle)
XChainOwnedClaimIDBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltXCHAIN_OWNED_CLAIM_ID)
{

View File

@@ -33,7 +33,7 @@ public:
* @brief Construct a XChainOwnedCreateAccountClaimID ledger entry wrapper from an existing SLE object.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
explicit XChainOwnedCreateAccountClaimID(std::shared_ptr<SLE const> sle)
explicit XChainOwnedCreateAccountClaimID(SLE::const_pointer sle)
: LedgerEntryBase(std::move(sle))
{
// Verify ledger entry type
@@ -161,7 +161,7 @@ public:
* @param sle The existing ledger entry to copy from.
* @throws std::runtime_error if the ledger entry type doesn't match.
*/
XChainOwnedCreateAccountClaimIDBuilder(std::shared_ptr<SLE const> sle)
XChainOwnedCreateAccountClaimIDBuilder(SLE::const_pointer sle)
{
if (sle->at(sfLedgerEntryType) != ltXCHAIN_OWNED_CREATE_ACCOUNT_CLAIM_ID)
{

View File

@@ -178,31 +178,6 @@ public:
SHAMapHash
getHash() const;
/** Recompute dirty node hashes in parallel and return the root hash.
Plan 7 Phase 2. Equivalent in output to `getHash()` on a freshly
mutated map: it recomputes the hash of every node dirtied since the
last hash settle, bottom-up, then returns the root hash. The work is
fanned out by top-level subtree — the root's up-to-16 children are
independent (a dirty node under one branch is never shared with
another), so their subtree recomputations run concurrently with no
synchronization, and only the root hash is computed serially after.
Byte-identical to the serial path by construction: a node's hash is a
pure function of its children's hashes, so computation order is
irrelevant as long as children precede parents — which the bottom-up
walk guarantees.
Unlike `getHash()`/`unshare()`, this does NOT convert nodes to shared
(cowid stays as-is) or flush to the nodestore; it only refreshes hash
caches. A subsequent `getHash()` therefore returns immediately.
@param workers Maximum concurrent subtree recomputations. <= 1 runs
serially. Defaults to the hardware concurrency.
*/
SHAMapHash
updateHashesParallel(int workers = 0);
// save a copy if you have a temporary anyway
bool
updateGiveItem(SHAMapNodeType type, boost::intrusive_ptr<SHAMapItem const> item);

View File

@@ -93,8 +93,8 @@ public:
std::function<void(
uint256 const& key,
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after)> const& func);
SLE::const_ref before,
SLE::const_ref after)> const& func);
void
destroyXRP(XRPAmount const& fee)

View File

@@ -263,10 +263,7 @@ protected:
* to detect deletions.
*/
virtual void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) = 0;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) = 0;
/** Check transaction-specific post-conditions after all entries have
* been visited.
@@ -368,7 +365,7 @@ private:
ReadView const& view,
AccountID const& idSigner,
AccountID const& idAccount,
std::shared_ptr<SLE const> sleAccount,
SLE::const_pointer sleAccount,
beast::Journal const j);
static NotTEC
checkMultiSign(

View File

@@ -22,7 +22,7 @@ public:
ValidAMM() = default;
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);

View File

@@ -22,7 +22,7 @@ class TransfersNotFrozen
{
struct BalanceChange
{
std::shared_ptr<SLE const> const line;
SLE::const_pointer const line;
int const balanceChangeSign;
};
@@ -35,37 +35,34 @@ class TransfersNotFrozen
using ByIssuer = std::map<Issue, IssuerChanges>;
ByIssuer balanceChanges_;
std::map<AccountID, std::shared_ptr<SLE const> const> possibleIssuers_;
std::map<AccountID, SLE::const_pointer const> possibleIssuers_;
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
private:
bool
isValidEntry(std::shared_ptr<SLE const> const& before, std::shared_ptr<SLE const> const& after);
isValidEntry(SLE::const_ref before, SLE::const_ref after);
static STAmount
calculateBalanceChange(
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after,
bool isDelete);
calculateBalanceChange(SLE::const_ref before, SLE::const_ref after, bool isDelete);
void
recordBalance(Issue const& issue, BalanceChange change);
void
recordBalanceChanges(std::shared_ptr<SLE const> const& after, STAmount const& balanceChange);
recordBalanceChanges(SLE::const_ref after, STAmount const& balanceChange);
std::shared_ptr<SLE const>
SLE::const_pointer
findIssuer(AccountID const& issuerID, ReadView const& view);
static bool
validateIssuerChanges(
std::shared_ptr<SLE const> const& issuer,
SLE::const_ref issuer,
IssuerChanges const& changes,
STTx const& tx,
beast::Journal const& j,

View File

@@ -70,10 +70,7 @@ public:
* @param after ledger entry after modification by the transaction
*/
void
visitEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after);
visitEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after);
/**
* @brief called after all ledger entries have been visited to determine
@@ -111,7 +108,7 @@ class TransactionFeeCheck
{
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
static bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
@@ -131,7 +128,7 @@ class XRPNotCreated
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -151,7 +148,7 @@ class AccountRootsNotDeleted
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -174,11 +171,11 @@ class AccountRootsDeletedClean
// deleted, it can still be found. After is used specifically for any checks
// that are expected as part of the deletion, such as zeroing out the
// balance.
std::vector<std::pair<std::shared_ptr<SLE const>, std::shared_ptr<SLE const>>> accountsDeleted_;
std::vector<std::pair<SLE::const_pointer, SLE::const_pointer>> accountsDeleted_;
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
@@ -197,7 +194,7 @@ class XRPBalanceChecks
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -214,7 +211,7 @@ class LedgerEntryTypesMatch
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -232,7 +229,7 @@ class NoXRPTrustLines
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -251,7 +248,7 @@ class NoDeepFreezeTrustLinesWithoutFreeze
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -270,7 +267,7 @@ class NoBadOffers
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -286,7 +283,7 @@ class NoZeroEscrow
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -306,7 +303,7 @@ class ValidNewAccountRoot
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -327,7 +324,7 @@ class ValidClawback
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -347,7 +344,7 @@ class ValidPseudoAccounts
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);
@@ -367,7 +364,7 @@ class NoModifiedUnmodifiableFields
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);

View File

@@ -46,7 +46,7 @@ class ValidLoanBroker
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);

View File

@@ -23,7 +23,7 @@ class ValidLoan
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);

View File

@@ -37,7 +37,7 @@ class ValidMPTIssuance
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -65,7 +65,7 @@ class ValidMPTPayment
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);

View File

@@ -33,7 +33,7 @@ class ValidNFTokenPage
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;
@@ -61,7 +61,7 @@ class NFTokenCountTracking
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
[[nodiscard]] bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&) const;

View File

@@ -18,7 +18,7 @@ class ValidPermissionedDEX
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);

View File

@@ -32,7 +32,7 @@ class ValidPermissionedDomain
public:
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);

View File

@@ -154,7 +154,7 @@ public:
computeCoarsestScale(std::vector<DeltaInfo> const& numbers);
void
visitEntry(bool, std::shared_ptr<SLE const> const&, std::shared_ptr<SLE const> const&);
visitEntry(bool, SLE::const_ref, SLE::const_ref);
bool
finalize(STTx const&, TER const, XRPAmount const, ReadView const&, beast::Journal const&);

View File

@@ -21,7 +21,7 @@ private:
uint256 end_;
uint256 dir_;
uint256 index_;
std::shared_ptr<SLE> entry_;
SLE::pointer entry_;
Quality quality_{};
public:

View File

@@ -29,10 +29,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

View File

@@ -33,10 +33,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

View File

@@ -23,10 +23,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

View File

@@ -42,10 +42,7 @@ public:
preCompute() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

View File

@@ -28,10 +28,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(
@@ -64,10 +61,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(
@@ -111,10 +105,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(
@@ -152,10 +143,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(
@@ -195,10 +183,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(
@@ -238,10 +223,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(
@@ -272,10 +254,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(
@@ -330,10 +309,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

View File

@@ -23,10 +23,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

View File

@@ -26,10 +26,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

View File

@@ -26,10 +26,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

View File

@@ -26,10 +26,7 @@ public:
doApply() override;
void
visitInvariantEntry(
bool isDelete,
std::shared_ptr<SLE const> const& before,
std::shared_ptr<SLE const> const& after) override;
visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override;
[[nodiscard]] bool
finalizeInvariants(

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